## Automatically generated incremental diff
## From:   linux-2.4.19-pre4
## To:     linux-2.4.19-pre5
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.19-pre4/CREDITS linux-2.4.19-pre5/CREDITS
--- linux-2.4.19-pre4/CREDITS	Fri Mar 29 14:48:52 2002
+++ linux-2.4.19-pre5/CREDITS	Fri Mar 29 14:49:16 2002
@@ -1658,6 +1658,13 @@
 S: San Antonio, Texas 78269-1886
 S: USA
 
+N: Denis O. Kropp
+E: dok@directfb.org
+D: NeoMagic framebuffer driver
+S: Badensche Str. 46
+S: 10715 Berlin
+S: Germany
+
 N: Andrzej M. Krzysztofowicz
 E: ankry@mif.pg.gda.pl
 D: Some 8-bit XT disk driver and devfs hacking 
diff -urN linux-2.4.19-pre4/Documentation/Changes linux-2.4.19-pre5/Documentation/Changes
--- linux-2.4.19-pre4/Documentation/Changes	Fri Mar 29 14:48:52 2002
+++ linux-2.4.19-pre5/Documentation/Changes	Fri Mar 29 14:49:16 2002
@@ -326,7 +326,7 @@
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0b.tar.gz>
+o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.1b.tar.gz>
 
 LVM toolset
 -----------
diff -urN linux-2.4.19-pre4/Documentation/Configure.help linux-2.4.19-pre5/Documentation/Configure.help
--- linux-2.4.19-pre4/Documentation/Configure.help	Fri Mar 29 14:48:52 2002
+++ linux-2.4.19-pre5/Documentation/Configure.help	Fri Mar 29 14:49:17 2002
@@ -723,6 +723,59 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called ide-floppy.o.
 
+AWARD Bios Work-Around
+CONFIG_IDEDISK_STROKE
+  Should you have a system w/ an AWARD Bios and your drives are larger
+  than 32GB and it will not boot, one is required to perform a few OEM
+  operations first.  The option is called "STROKE" because it allows
+  one to "soft clip" the drive to work around a barrier limit.  For
+  Maxtor drives it is called "jumpon.exe".  Please search Maxtor's
+  web-site for "JUMPON.EXE".  IBM has a similar tool at:
+  <http://www.storage.ibm.com/hdd/support/download.htm>.
+
+  If you are unsure, say N here.
+
+Raw Access to Media
+CONFIG_IDE_TASK_IOCTL
+  This is a direct raw access to the media.  It is a complex but
+  elegant solution to test and validate the domain of the hardware and
+  perform below the driver data recover if needed.  This is the most
+  basic form of media-forensics.
+
+  If you are unsure, say N here.
+
+Use Taskfile I/O
+CONFIG_IDE_TASKFILE_IO
+  This is the "Jewel" of the patch.  It will go away and become the new
+  driver core.  Since all the chipsets/host side hardware deal w/ their
+  exceptions in "their local code" currently, adoption of a
+  standardized data-transport is the only logical solution.
+  Additionally we packetize the requests and gain rapid performance and
+  a reduction in system latency.  Additionally by using a memory struct
+  for the commands we can redirect to a MMIO host hardware in the next
+  generation of controllers, specifically second generation Ultra133
+  and Serial ATA.
+
+  Since this is a major transition, it was deemed necessary to make the
+  driver paths buildable in separtate models.  Therefore if using this
+  option fails for your arch then we need to address the needs for that
+  arch.
+
+  If you want to test this functionality, say Y here.
+
+Force DMA
+CONFIG_BLK_DEV_IDEDMA_FORCED
+  This is an old piece of lost code from Linux 2.0 Kernels.
+
+  Generally say N here.
+
+DMA Only on Disks
+CONFIG_IDEDMA_ONLYDISK
+  This is used if you know your ATAPI Devices are going to fail DMA
+  Transfers.
+
+  Generally say N here.
+
 SCSI emulation support
 CONFIG_BLK_DEV_IDESCSI
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
@@ -747,6 +800,14 @@
   If both this SCSI emulation and native ATAPI support are compiled
   into the kernel, the native support will be used.
 
+Use the NOOP Elevator (WARNING)
+CONFIG_BLK_DEV_ELEVATOR_NOOP
+  If you are using a raid class top-level driver above the ATA/IDE core,
+  one may find a performance boost by preventing a merging and re-sorting
+  of the new requests.
+
+  If unsure, say N.
+
 ISA-PNP EIDE support
 CONFIG_BLK_DEV_ISAPNP
   If you have an ISA EIDE card that is PnP (Plug and Play) and
@@ -1136,9 +1197,15 @@
 
 SiS5513 chipset support
 CONFIG_BLK_DEV_SIS5513
-  This driver ensures (U)DMA support for SIS5513 chipset based
-  mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all
-  other DMA mode 2 limited chipsets are unsupported to date.
+  This driver ensures (U)DMA support for SIS5513 chipset family based
+  mainboards.
+
+  The following chipsets are supported:
+  ATA16:  SiS5511, SiS5513
+  ATA33:  SiS5591, SiS5597, SiS5598, SiS5600
+  ATA66:  SiS530, SiS540, SiS620, SiS630, SiS640
+  ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
+          SiS745, SiS750
 
   If you say Y here, you need to say Y to "Use DMA by default when
   available" as well.
@@ -2513,6 +2580,19 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+Local NAT support
+CONFIG_IP_NF_NAT_LOCAL
+  This option enables support for NAT of locally originated connections. 
+  Enable this if you need to use destination NAT on connections
+  originating from local processes on the nat box itself.
+
+  Please note that you will need a recent version (>= 1.2.6a)
+  of the iptables userspace program in order to use this feature.
+  See http://www.iptables.org/ for download instructions.
+
+  If unsure, say 'N'.
+
+
 Full NAT (Network Address Translation)
 CONFIG_IP_NF_NAT
   The Full NAT option allows masquerading, port forwarding and other
@@ -4214,6 +4294,16 @@
   This driver supports the L7200 Color LCD.
   Say Y if you want graphics support.
 
+NeoMagic display support (EXPERIMENTAL)
+CONFIG_FB_NEOMAGIC
+  This driver supports notebooks with NeoMagic PCI chips.
+  Say Y if you have such a graphics card. 
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called neofb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
   This driver supports a frame buffer for the graphics adapter in the
diff -urN linux-2.4.19-pre4/Documentation/networking/3c509.txt linux-2.4.19-pre5/Documentation/networking/3c509.txt
--- linux-2.4.19-pre4/Documentation/networking/3c509.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/Documentation/networking/3c509.txt	Fri Mar 29 14:49:17 2002
@@ -0,0 +1,210 @@
+Linux and the 3Com EtherLink III Series Ethercards (driver v1.18c and higher)
+----------------------------------------------------------------------------
+
+This file contains the instructions and caveats for v1.18c and higher versions
+of the 3c509 driver. You should not use the driver without reading this file.
+
+release 1.0
+28 February 2002
+Current maintainer (corrections to):
+  David Ruggiero <jdr@farfalle.com>
+
+----------------------------------------------------------------------------
+
+(0) Introduction
+
+The following are notes and information on using the 3Com EtherLink III series
+ethercards in Linux. These cards are commonly known by the most widely-used
+card's 3Com model number, 3c509. They are all 10mb/s ISA-bus cards and shouldn't
+be (but sometimes are) confused with the similarly-numbered PCI-bus "3c905"
+(aka "Vortex" or "Boomerang") series.  Kernel support for the 3c509 family is
+provided by the module 3c509.c, which has code to support all of the following
+models:
+
+  3c509 (original ISA card)
+  3c509B (later revision of the ISA card; supports full-duplex)
+  3c589 (PCMCIA)
+  3c589B (later revision of the 3c589; supports full-duplex)
+  3c529 (MCA)
+  3c579 (EISA)
+
+Large portions of this documentation were heavily borrowed from the guide
+written the original author of the 3c509 driver, Donald Becker. The master
+copy of that document, which contains notes on older versions of the driver,
+currently resides on Scyld web server: http://www.scyld.com/network/3c509.html.
+
+
+(1) Special Driver Features
+
+Overriding card settings
+
+The driver allows boot- or load-time overriding of the card's detected IOADDR,
+IRQ, and transceiver settings, although this capability shouldn't generally be
+needed except to enable full-duplex mode (see below). An example of the syntax
+for LILO parameters for doing this:
+
+    ether=10,0x310,3,0x3c509,eth0 
+
+This configures the first found 3c509 card for IRQ 10, base I/O 0x310, and
+transceiver type 3 (10base2). The flag "0x3c509" must be set to avoid conflicts
+with other card types when overriding the I/O address. When the driver is
+loaded as a module, only the IRQ and transceiver setting may be overridden.
+For example, setting two cards to 10base2/IRQ10 and AUI/IRQ11 is done by using
+the xcvr and irq module options:
+
+   options 3c509 xcvr=3,3 irq=10,11
+
+
+(2) Full-duplex mode
+
+The v1.18c driver added support for the 3c509B's full-duplex capabilities.
+In order to enable and successfully use full-duplex mode, three conditions
+must be met: 
+
+(a) You must have a Etherlink III card model whose hardware supports full-
+duplex operations. Currently, the only members of the 3c509 family that are
+positively known to support full-duplex are the 3c509B (ISA bus) and 3c589B
+(PCMCIA) cards. Cards without the "B" model designation do *not* support
+full-duplex mode; these include the original 3c509 (no "B"), the original
+3c589, the 3c529 (MCA bus), and the 3c579 (EISA bus).
+
+(b) You must be using your card's 10baseT transceiver (i.e., the RJ-45
+connector), not its AUI (thick-net) or 10base2 (thin-net/coax) interfaces.
+AUI and 10base2 network cabling is physically incapable of full-duplex
+operation.
+
+(c) Most importantly, your 3c509B must be connected to a link partner that is
+itself full-duplex capable. This is almost certainly one of two things: a full-
+duplex-capable  Ethernet switch (*not* a hub), or a full-duplex-capable NIC on
+another system that's connected directly to the 3c509B via a crossover cable.
+ 
+/////Extremely important caution concerning full-duplex mode/////
+Understand that the 3c509B's hardware's full-duplex support is much more
+limited than that provide by more modern network interface cards. Although
+at the physical layer of the network it fully supports full-duplex operation,
+the card was designed before the current Ethernet auto-negotiation (N-way)
+spec was written. This means that the 3c509B family ***cannot and will not
+auto-negotiate a full-duplex connection with its link partner under any
+circumstances, no matter how it is initialized***. If the full-duplex mode
+of the 3c509B is enabled, its link partner will very likely need to be
+independently _forced_ into full-duplex mode as well; otherwise various nasty
+failures will occur - at the very least, you'll see massive numbers of packet
+collisions. This is one of very rare circumstances where disabling auto-
+negotiation and forcing the duplex mode of a network interface card or switch
+would ever be necessary or desirable.
+
+
+(3) Available Transceiver Types
+
+For versions of the driver v1.18c and above, the available transceiver types are:
+ 
+0  transceiver type from EEPROM config (normally 10baseT); force half-duplex
+1  AUI (thick-net / DB15 connector)
+2  (undefined)
+3  10base2 (thin-net == coax / BNC connector)
+4  10baseT (RJ-45 connector); force half-duplex mode
+8  transceiver type and duplex mode taken from card's EEPROM config settings
+12 10baseT (RJ-45 connector); force full-duplex mode
+
+Prior to driver version 1.18c, only tranceiver codes 0-4 were supported. Note
+that the new transceiver codes 8 and 12 are the *only* ones that will enable
+full-duplex mode, no matter what the card's detected EEPROM settings might be.
+This insured that merely upgrading the driver from an earlier version would
+never automatically enable full-duplex mode in an existing installation;
+it must always be explicitly enabled via one of these code in order to be
+activated.
+  
+
+(4a) Interpretation of error messages and common problems
+
+Error Messages
+
+eth0: Infinite loop in interrupt, status 2011. 
+These are "mostly harmless" message indicating that the driver had too much
+work during that interrupt cycle. With a status of 0x2011 you are receiving
+packets faster than they can be removed from the card. This should be rare
+or impossible in normal operation. Possible causes of this error report are:
+ 
+   - a "green" mode enabled that slows the processor down when there is no
+     keyboard activitiy. 
+
+   - some other device or device driver hogging the bus or disabling interrupts.
+     Check /proc/interrupts for excessive interrupt counts. The timer tick
+     interrupt should always be incrementing faster than the others. 
+
+No received packets 
+If a 3c509, 3c562 or 3c589 can successfully transmit packets, but never
+receives packets (as reported by /proc/net/dev or 'ifconfig') you likely
+have an interrupt line problem. Check /proc/interrupts to verify that the
+card is actually generating interrupts. If the interrupt count is not
+increasing you likely have a physical conflict with two devices trying to
+use the same ISA IRQ line. The common conflict is with a sound card on IRQ10
+or IRQ5, and the easiest solution is to move the 3c509 to a different
+interrupt line. If the device is receiving packets but 'ping' doesn't work,
+you have a routing problem.
+
+Tx Carrier Errors Reported in /proc/net/dev 
+If an EtherLink III appears to transmit packets, but the "Tx carrier errors"
+field in /proc/net/dev increments as quickly as the Tx packet count, you
+likely have an unterminated network or the incorrect media tranceiver selected. 
+
+3c509B card is not detected on machines with an ISA PnP BIOS. 
+While the updated driver works with most PnP BIOS programs, it does not work
+with all. This can be fixed by disabling PnP support using the 3Com-supplied
+setup program. 
+
+3c509 card is not detected on overclocked machines 
+Increase the delay time in id_read_eeprom() from the current value, 500,
+to an absurdly high value, such as 5000. 
+
+
+(4b) Decoding Status and Error Messages
+
+The bits in the main status register are: 
+
+value 	description
+0x01 	Interrupt latch
+0x02 	Tx overrun, or Rx underrun
+0x04 	Tx complete
+0x08 	Tx FIFO room available
+0x10 	A complete Rx packet has arrived
+0x20 	A Rx packet has started to arrive
+0x40 	The driver has requested an interrupt
+0x80 	Statistics counter nearly full
+
+The bits in the transmit (Tx) status word are: 
+
+value 	description
+0x02 	Out-of-window collision.
+0x04 	Status stack overflow (normally impossible).
+0x08 	16 collisions.
+0x10 	Tx underrun (not enough PCI bus bandwidth).
+0x20 	Tx jabber.
+0x40 	Tx interrupt requested.
+0x80 	Status is valid (this should always be set).
+
+
+When a transmit error occurs the driver produces a status message such as 
+
+   eth0: Transmit error, Tx status register 82
+
+The two values typically seen here are:
+
+0x82 
+Out of window collision. This typically occurs when some other Ethernet
+host is incorrectly set to full duplex on a half duplex network. 
+
+0x88 
+16 collisions. This typically occurs when the network is exceptionally busy
+or when another host doesn't correctly back off after a collision. If this
+error is mixed with 0x82 errors it is the result of a host incorrectly set
+to full duplex (see above).
+
+Both of these errors are the result of network problems that should be
+corrected. They do not represent driver malfunction.
+
+
+(5) Revision history (this file)
+
+28Feb02 v1.0  DR   New; major portions based on Becker original 3c509 docs
+
diff -urN linux-2.4.19-pre4/Documentation/networking/bonding.txt linux-2.4.19-pre5/Documentation/networking/bonding.txt
--- linux-2.4.19-pre4/Documentation/networking/bonding.txt	Fri Mar 29 14:48:53 2002
+++ linux-2.4.19-pre5/Documentation/networking/bonding.txt	Fri Mar 29 14:49:17 2002
@@ -271,7 +271,7 @@
 	
 	If you wish to change the MAC address, you can set it with ifconfig:
 
-	  # ifconfig bond0 ha ether 00:11:22:33:44:55
+	  # ifconfig bond0 hw ether 00:11:22:33:44:55
 
 	The MAC address can be also changed by bringing down/up the device
 	and then changing its slaves (or their order):
diff -urN linux-2.4.19-pre4/Documentation/networking/dl2k.txt linux-2.4.19-pre5/Documentation/networking/dl2k.txt
--- linux-2.4.19-pre4/Documentation/networking/dl2k.txt	Mon Feb 25 11:37:51 2002
+++ linux-2.4.19-pre5/Documentation/networking/dl2k.txt	Fri Mar 29 14:49:17 2002
@@ -1,7 +1,7 @@
 
     D-Link DL2000-based Gigabit Ethernet Adapter Installation
     for Linux
-    Jan 02, 2002
+    Jan 29, 2002
 
 Contents
 ========
@@ -199,8 +199,8 @@
 				  6          	1000Mbps full duplex.
 
 				  By default, the NIC operates at autosense.
-				  Note that only 1000mbps_fd and 1000mbps_hd
-				  types are available for fiber adapter.
+				  1000mbps_fd and 1000mbps_hd types are only
+				  available for fiber adapter.
 
 vlan=[0|1]			- Specifies the VLAN ID. If vlan=0, the
 				  Virtual Local Area Network (VLAN) function is
diff -urN linux-2.4.19-pre4/Documentation/networking/ifenslave.c linux-2.4.19-pre5/Documentation/networking/ifenslave.c
--- linux-2.4.19-pre4/Documentation/networking/ifenslave.c	Wed Nov  7 14:39:36 2001
+++ linux-2.4.19-pre5/Documentation/networking/ifenslave.c	Fri Mar 29 14:49:17 2002
@@ -38,6 +38,9 @@
  *         take care of this itself
  *       - Try the SIOC*** versions of the bonding ioctls before using the
  *         old versions
+ *    - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
+ *       - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
+ *         SIOCGIFFLAGS now called before hwaddr_notset test
  */
 
 static char *version =
@@ -288,19 +291,19 @@
 			     hwaddr from it's first slave.
 			   - if !hwaddr_notset, assign the master's hwaddr to each slave
 			*/
-	
+
+			strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
+			if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
+				int saved_errno = errno;
+				fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
+						strerror(saved_errno));
+				return 1;
+			}
+
 			if (hwaddr_notset) { /* we do nothing */
 
 			}
 			else {  /* we'll assign master's hwaddr to this slave */
-				strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
-				if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
-					int saved_errno = errno;
-					fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
-							strerror(saved_errno));
-					return 1;
-				}
-	
 				if (ifr2.ifr_flags & IFF_UP) {
 					ifr2.ifr_flags &= ~IFF_UP;
 					if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
diff -urN linux-2.4.19-pre4/Documentation/networking/ip-sysctl.txt linux-2.4.19-pre5/Documentation/networking/ip-sysctl.txt
--- linux-2.4.19-pre4/Documentation/networking/ip-sysctl.txt	Mon Feb 25 11:37:51 2002
+++ linux-2.4.19-pre5/Documentation/networking/ip-sysctl.txt	Fri Mar 29 14:49:17 2002
@@ -126,7 +126,13 @@
 	if network conditions require more than default value.
 
 tcp_tw_recycle - BOOLEAN
-	Enable fast recycling TIME-WAIT sockets. Default value is 1.
+	Enable fast recycling TIME-WAIT sockets. Default value is 0.
+	It should not be changed without advice/request of technical
+	experts.
+
+tcp_tw_reuse - BOOLEAN
+	Allow to reuse TIME-WAIT sockets for new connections when it is
+	safe from protocol viewpoint. Default value is 0.
 	It should not be changed without advice/request of technical
 	experts.
 
@@ -182,10 +188,7 @@
 	still did not receive an acknowledgement from connecting client.
 	Default value is 1024 for systems with more than 128Mb of memory,
 	and 128 for low memory machines. If server suffers of overload,
-	try to increase this number. Warning! If you make it greater
-	than 1024, it would be better to change TCP_SYNQ_HSIZE in
-	include/net/tcp.h to keep TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog
-	and to recompile kernel.
+	try to increase this number.
 
 tcp_window_scaling - BOOLEAN
 	Enable window scaling as defined in RFC1323.
@@ -358,6 +361,17 @@
 	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
 	and a multicast routing daemon is required.
 
+medium_id - INTEGER
+	Integer value used to differentiate the devices by the medium they
+	are attached to. Two devices can have different id values when
+	the broadcast packets are received only on one of them.
+	The default value 0 means that the device is the only interface
+	to its medium, value of -1 means that medium is not known.
+	
+	Currently, it is used to change the proxy_arp behavior:
+	the proxy_arp feature is enabled for packets forwarded between
+	two devices attached to different media.
+
 proxy_arp - BOOLEAN
 	Do proxy arp.
 
diff -urN linux-2.4.19-pre4/Documentation/sound/rme96xx linux-2.4.19-pre5/Documentation/sound/rme96xx
--- linux-2.4.19-pre4/Documentation/sound/rme96xx	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/Documentation/sound/rme96xx	Fri Mar 29 14:49:17 2002
@@ -0,0 +1,767 @@
+Beta release of the rme96xx (driver for RME 96XX cards like the 
+"Hammerfall" and the "Hammerfall light") 
+
+Important: The driver module has to be installed on a freshly rebooted system, 
+otherwise the driver might not be able to acquire its buffers.
+
+features:
+
+ - OSS programming interface (i.e. runs with standard OSS soundsoftware) 
+ - OSS/Multichannel interface (OSS multichannel is done by just aquiring
+   more than 2 channels). The driver does not use more than one device 
+   ( yet .. this feature may be implemented later ) 
+ - more than one RME card supported
+
+The driver uses a specific multichannel interface, which I will document
+when the driver gets stable. (take a look at the defines in rme96xx.h,
+which adds blocked multichannel formats i.e instead of 
+lrlrlrlr --> llllrrrr  etc.
+
+Use the "rmectrl" programm to look at the status of the card .. 
+or use xrmectrl, a GUI interface for the ctrl program.
+
+What you can do with the rmectrl program is to set the stereo device for
+OSS emulation (e.g. if you use SPDIF out).
+
+You do:
+
+./ctrl offset 24 24
+
+which makes the stereo device use channels 25 and 26.
+
+Guenter Geiger <geiger@epy.co.at> 
+               
+copy the first part of the attached source code into rmectrl.c
+and the  second part into xrmectrl (or get the program from
+http://gige.xdv.org/pages/soft/pages/rme)
+
+to compile: gcc -o rmectrl rmectrl.c
+------------------------------ snip ------------------------------------
+ 
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/soundcard.h>
+#include <math.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "rme96xx.h"
+
+/*
+  remctrl.c
+  (C) 2000 Guenter Geiger <geiger@debian.org>
+  HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
+*/
+
+/* # define DEVICE_NAME "/dev/mixer" */
+# define DEVICE_NAME "/dev/mixer1"
+
+
+void usage(void)
+{
+     fprintf(stderr,"usage: rmectrl [/dev/mixer<n>] [command [options]]\n\n");
+     fprintf(stderr,"where command is one of:\n");
+     fprintf(stderr,"  help                       show this help\n");
+     fprintf(stderr,"  status                     show status bits\n");
+     fprintf(stderr,"  control                    show control bits\n");
+     fprintf(stderr,"  mix                        show mixer/offset status\n");
+     fprintf(stderr,"  master <n>                 set sync master\n");
+     fprintf(stderr,"  pro <n>                    set spdif out pro\n");
+     fprintf(stderr,"  emphasis <n>               set spdif out emphasis\n");
+     fprintf(stderr,"  dolby <n>                  set spdif out no audio\n");
+     fprintf(stderr,"  optout <n>                 set spdif out optical\n");
+     fprintf(stderr,"  wordclock <n>              set sync wordclock\n");
+     fprintf(stderr,"  spdifin <n>                set spdif in (0=optical,1=coax,2=intern)\n");
+     fprintf(stderr,"  syncref <n>                set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n");
+     fprintf(stderr,"  adat1cd <n>                set ADAT1 on internal CD\n");
+     fprintf(stderr,"  offset <devnr> <in> <out>  set dev (0..3) offset (0..25)\n");
+     exit(-1);
+}
+
+
+int main(int argc, char* argv[])
+{
+     int cards;
+     int ret;
+     int i;
+     double ft;
+     int fd, fdwr;
+     int param,orig;
+     rme_status_t stat;
+     rme_ctrl_t ctrl;
+     char *device;
+     int argidx;
+
+     if (argc < 2)
+	  usage();
+
+     if (*argv[1]=='/') {
+	  device = argv[1];
+	  argidx = 2;
+     }
+     else {
+	  device = DEVICE_NAME;
+	  argidx = 1;
+     }
+
+     fprintf(stdout,"mixer device %s\n",device);
+     if ((fd = open(device,O_RDONLY)) < 0) {
+	  fprintf(stdout,"opening device failed\n");
+	  exit(-1);
+     }
+
+     if ((fdwr = open(device,O_WRONLY)) < 0) {
+	  fprintf(stdout,"opening device failed\n");
+	  exit(-1);
+     }
+
+     if (argc < argidx+1)
+	  usage();
+	  
+     if (!strcmp(argv[argidx],"help")) 
+        usage();
+     if (!strcmp(argv[argidx],"-h")) 
+        usage();
+     if (!strcmp(argv[argidx],"--help")) 
+        usage();
+
+     if (!strcmp(argv[argidx],"status")) {
+	  ioctl(fd,SOUND_MIXER_PRIVATE2,&stat);
+	  fprintf(stdout,"stat.irq %d\n",stat.irq);
+	  fprintf(stdout,"stat.lockmask %d\n",stat.lockmask);
+	  fprintf(stdout,"stat.sr48 %d\n",stat.sr48);
+	  fprintf(stdout,"stat.wclock %d\n",stat.wclock);
+	  fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint);
+	  fprintf(stdout,"stat.syncmask %d\n",stat.syncmask);
+	  fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed);
+	  fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy);
+	  fprintf(stdout,"stat.tc_out %d\n",stat.tc_out);
+	  fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate);
+	  fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error);
+	  fprintf(stdout,"stat.bufid %d\n",stat.bufid);
+	  fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid);
+	  exit (0);
+     }
+	 
+     if (!strcmp(argv[argidx],"control")) {
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  fprintf(stdout,"ctrl.start %d\n",ctrl.start);
+	  fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency);
+	  fprintf(stdout,"ctrl.master %d\n",ctrl.master);
+	  fprintf(stdout,"ctrl.ie %d\n",ctrl.ie);
+	  fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48);
+	  fprintf(stdout,"ctrl.spare %d\n",ctrl.spare);
+	  fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed);
+	  fprintf(stdout,"ctrl.pro %d\n",ctrl.pro);
+	  fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis);
+	  fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby);
+	  fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out);
+	  fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock);
+	  fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in);
+	  fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref);
+	  fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset);
+	  fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select);
+	  fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock);
+	  fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write);
+	  fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd);
+	  exit (0);
+     }
+     
+     if (!strcmp(argv[argidx],"mix")) {
+	  rme_mixer mix;
+	  int i;
+	  
+	  for (i=0; i<4; i++) {
+	       mix.devnr = i;
+	       ioctl(fd,SOUND_MIXER_PRIVATE1,&mix);
+	       if (mix.devnr == i) {
+		    fprintf(stdout,"devnr %d\n",mix.devnr);
+		    fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset);
+		    fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset);
+	       }
+	  }
+	  exit (0);
+     }
+
+/* the control flags */
+
+     if (argc < argidx+2)
+	  usage();
+	  
+     if (!strcmp(argv[argidx],"master")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("master = %d\n",val);
+	  ctrl.master = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"pro")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("pro = %d\n",val);
+	  ctrl.pro = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"emphasis")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("emphasis = %d\n",val);
+	  ctrl.emphasis = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"dolby")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("dolby = %d\n",val);
+	  ctrl.dolby = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"optout")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("optout = %d\n",val);
+	  ctrl.opt_out = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"wordclock")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("wordclock = %d\n",val);
+	  ctrl.wordclock = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"spdifin")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("spdifin = %d\n",val);
+	  ctrl.spdif_in = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+
+     if (!strcmp(argv[argidx],"syncref")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("syncref = %d\n",val);
+	  ctrl.sync_ref = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+ 
+     if (!strcmp(argv[argidx],"adat1cd")) {
+	  int val = atoi(argv[argidx+1]);
+	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
+	  printf("adat1cd = %d\n",val);
+	  ctrl.adat1_cd = val;
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
+	  exit (0);
+     }
+ 
+/* setting offset */
+
+     if (argc < argidx+4)
+	  usage();
+	  
+     if (!strcmp(argv[argidx],"offset")) {
+	  rme_mixer mix;
+
+	  mix.devnr = atoi(argv[argidx+1]);
+	  
+	  mix.i_offset = atoi(argv[argidx+2]);
+	  mix.o_offset = atoi(argv[argidx+3]);
+	  ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix);
+	  fprintf(stdout,"devnr %d\n",mix.devnr);
+	  fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset);
+	  fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset);
+	  exit (0);
+     }	 
+
+     usage();
+     exit (0); /* to avoid warning */
+}
+
+
+---------------------------- <snip> --------------------------------
+#!/usr/bin/wish
+
+# xrmectrl
+# (C) 2000 Guenter Geiger <geiger@debian.org>
+# HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
+
+#set defaults "-relief ridged"
+set CTRLPROG "./rmectrl"
+if {$argc} {
+    set CTRLPROG "$CTRLPROG $argv"
+}
+puts "CTRLPROG $CTRLPROG"
+
+frame .butts
+button .butts.exit -text "Exit" -command "exit" -relief ridge
+#button .butts.state -text "State" -command "get_all" 
+
+pack .butts.exit -side left 
+pack .butts -side bottom 
+
+
+#
+# STATUS 
+#
+
+frame .status
+
+# Sampling Rate
+
+frame .status.sr
+label .status.sr.text -text "Sampling Rate" -justify left
+radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times
+radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times
+radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times
+radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw  -variable srate -value 96000 -font times
+
+pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3
+
+# Lock
+
+frame .status.lock
+label .status.lock.text -text "Lock" -justify left
+checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times
+checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times
+checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times
+
+pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3 
+
+# Sync
+
+frame .status.sync
+label .status.sync.text -text "Sync" -justify left
+checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times
+checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times
+checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times
+
+pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3 
+
+# Timecode
+
+frame .status.tc
+label .status.tc.text -text "Timecode" -justify left
+checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times
+checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times
+checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times
+
+pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3 
+
+# SPDIF In
+
+frame .status.spdif
+label .status.spdif.text -text "SPDIF In" -justify left
+label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times
+checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times
+
+pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3 
+
+pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1
+
+
+#
+# CONTROL 
+#
+
+proc setprof {} {
+    global CTRLPROG
+    global spprof
+    exec $CTRLPROG pro $spprof
+}
+
+proc setemph {} {
+    global CTRLPROG
+    global spemph
+    exec $CTRLPROG emphasis $spemph
+}
+
+proc setnoaud {} {
+    global CTRLPROG
+    global spnoaud
+    exec $CTRLPROG dolby $spnoaud
+}
+
+proc setoptical {} {
+    global CTRLPROG
+    global spoptical
+    exec $CTRLPROG optout $spoptical
+}
+
+proc setspdifin {} {
+    global CTRLPROG
+    global spdifin
+    exec $CTRLPROG spdifin [expr $spdifin - 1]
+}
+
+proc setsyncsource {} {
+    global CTRLPROG
+    global syncsource
+    exec $CTRLPROG syncref [expr $syncsource -1]
+}
+
+
+proc setmaster {} {
+    global CTRLPROG
+    global master
+    exec $CTRLPROG master $master
+}
+
+proc setwordclock {} {
+    global CTRLPROG
+    global wordclock
+    exec $CTRLPROG wordclock $wordclock
+}
+
+proc setadat1cd {} {
+    global CTRLPROG
+    global adat1cd
+    exec $CTRLPROG adat1cd $adat1cd
+}
+
+
+frame .control
+
+# SPDIF In & SPDIF Out
+
+
+frame .control.spdif
+
+frame .control.spdif.in
+label .control.spdif.in.text -text "SPDIF In" -justify left
+radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times
+radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times
+radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times
+
+checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times
+
+pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd
+
+label .control.spdif.space
+
+frame .control.spdif.out
+label .control.spdif.out.text -text "SPDIF Out" -justify left
+checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times
+checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times
+checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times
+checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times
+
+pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom
+
+pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1
+
+# Sync Mode & Sync Source
+
+frame .control.sync
+frame .control.sync.mode
+label .control.sync.mode.text -text "Sync Mode" -justify left
+checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times
+checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times
+
+pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc
+
+label .control.sync.space
+
+frame .control.sync.src
+label .control.sync.src.text -text "Sync Source" -justify left
+radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times
+radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times
+radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times
+radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times
+
+pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom
+
+pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1
+
+label .control.space -text "" -width 10
+
+# Buffer Size
+
+frame .control.buf
+label .control.buf.text -text "Buffer Size (Latency)" -justify left
+radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times
+radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times
+radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times
+radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times
+radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times
+radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times
+radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times
+radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times
+
+pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3 
+
+# Offset
+
+frame .control.offset
+
+frame .control.offset.in
+label .control.offset.in.text -text "Offset In" -justify left
+label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
+label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
+label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
+label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
+
+pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3
+
+label .control.offset.space
+
+frame .control.offset.out
+label .control.offset.out.text -text "Offset Out" -justify left
+label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
+label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
+label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
+label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
+
+pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom
+
+pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1
+
+
+pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1
+
+
+label .statustext -text Status -justify center -relief ridge
+label .controltext -text Control -justify center -relief ridge
+
+label .statusspace
+label .controlspace
+
+pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1
+
+
+proc get_bit {output sstr} {
+    set idx1 [string last [concat $sstr 1] $output]
+    set idx1 [expr $idx1 != -1]
+    return $idx1
+}
+
+proc get_val {output sstr} {
+    set val [string wordend $output [string last $sstr $output]] 
+    set val [string range $output $val [expr $val+1]]
+    return $val
+}
+
+proc get_val2 {output sstr} {
+    set val [string wordend $output [string first $sstr $output]] 
+    set val [string range $output $val [expr $val+2]]
+    return $val
+}
+
+proc get_control {} {
+    global spprof
+    global spemph
+    global spnoaud
+    global spoptical
+    global spdifin
+    global ssrate
+    global master
+    global wordclock
+    global syncsource
+    global CTRLPROG
+
+    set f [open "| $CTRLPROG control" r+]
+    set ooo [read $f 1000]
+    close $f
+#    puts $ooo
+
+    set spprof [ get_bit $ooo "pro"]
+    set spemph [ get_bit $ooo "emphasis"]
+    set spnoaud [ get_bit $ooo "dolby"]
+    set spoptical [ get_bit $ooo "opt_out"]
+    set spdifin [ expr [ get_val $ooo "spdif_in"] + 1]
+    set ssrate [ expr [ get_val $ooo "latency"] + 1]
+    set master [ expr [ get_val $ooo "master"]]
+    set wordclock [ expr [ get_val $ooo "wordclock"]]
+    set syncsource [ expr [ get_val $ooo "sync_ref"] + 1]
+}
+
+proc get_status {} {
+    global srate
+    global ctrlcom
+    
+    global adatlock1
+    global adatlock2
+    global adatlock3
+
+    global adatsync1
+    global adatsync2
+    global adatsync3
+
+    global tcbusy
+    global tcout
+    global tcvalid
+
+    global spdiferr
+    global crystal
+    global .status.spdif.text
+    global CTRLPROG
+
+
+    set f [open "| $CTRLPROG status" r+]
+    set ooo [read $f 1000]
+    close $f
+#    puts $ooo
+ 
+# samplerate
+
+    set idx1 [string last "sr48 1" $ooo]
+    set idx2 [string last "doublespeed 1" $ooo]
+    if {$idx1 >= 0} {
+	set fact1 48000
+    } else {
+	set fact1 44100
+    }
+    
+    if {$idx2 >= 0} {
+	set fact2 2 
+    } else {
+	set fact2 1 
+    }
+    set srate [expr $fact1 * $fact2]
+#   ADAT lock 
+
+    set val [get_val $ooo lockmask]
+    set adatlock1 0
+    set adatlock2 0
+    set adatlock3 0
+    if {[expr $val & 1]} {
+       set adatlock3 1
+    } 
+    if {[expr $val & 2]} {
+       set adatlock2 1
+    } 
+    if {[expr $val & 4]} {
+       set adatlock1 1
+    } 
+
+#  ADAT sync
+    set val [get_val $ooo syncmask]
+    set adatsync1 0
+    set adatsync2 0
+    set adatsync3 0
+
+    if {[expr $val & 1]} {
+       set adatsync3 1
+    } 
+    if {[expr $val & 2]} {
+       set adatsync2 1
+    } 
+    if {[expr $val & 4]} {
+       set adatsync1 1
+    } 
+
+# TC busy
+
+    set tcbusy [get_bit $ooo "busy"]
+    set tcout [get_bit $ooo "out"]
+    set tcvalid [get_bit $ooo "valid"]
+    set spdiferr [expr [get_bit $ooo "spdif_error"] == 0]
+
+#  000=64kHz, 100=88.2kHz, 011=96kHz  
+#  111=32kHz, 110=44.1kHz, 101=48kHz
+
+    set val [get_val $ooo crystalrate] 
+
+    set crystal "--.- kHz"
+    if {$val == 0} {
+        set crystal "64 kHz"
+    }
+    if {$val == 4} {
+        set crystal "88.2 kHz"
+    }
+    if {$val == 3} {
+        set crystal "96 kHz"
+    }
+    if {$val == 7} {
+        set crystal "32 kHz"
+    }
+    if {$val == 6} {
+        set crystal "44.1 kHz"
+    }
+    if {$val == 5} {
+        set crystal "48 kHz"
+    }
+    .status.spdif.sr configure -text $crystal
+}
+
+proc get_offset {} {
+    global inoffset
+    global outoffset
+    global CTRLPROG
+
+    set f [open "| $CTRLPROG mix" r+]
+    set ooo [read $f 1000]
+    close $f
+#    puts $ooo
+
+    if { [string match "*devnr*" $ooo] } {
+	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+	set val [get_val2 $ooo i_offset] 
+	.control.offset.in.off0 configure -text "dev\#0: $val"
+	set val [get_val2 $ooo o_offset] 
+	.control.offset.out.off0 configure -text "dev\#0: $val"
+    } else {
+	.control.offset.in.off0 configure -text "dev\#0: -"
+	.control.offset.out.off0 configure -text "dev\#0: -"
+    }
+    if { [string match "*devnr*" $ooo] } {
+	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+	set val [get_val2 $ooo i_offset] 
+	.control.offset.in.off1 configure -text "dev\#1: $val"
+	set val [get_val2 $ooo o_offset] 
+	.control.offset.out.off1 configure -text "dev\#1: $val"
+    } else {
+	.control.offset.in.off1 configure -text "dev\#1: -"
+	.control.offset.out.off1 configure -text "dev\#1: -"
+    }
+    if { [string match "*devnr*" $ooo] } {
+	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+	set val [get_val2 $ooo i_offset] 
+	.control.offset.in.off2 configure -text "dev\#2: $val"
+	set val [get_val2 $ooo o_offset] 
+	.control.offset.out.off2 configure -text "dev\#2: $val"
+    } else {
+	.control.offset.in.off2 configure -text "dev\#2: -"
+	.control.offset.out.off2 configure -text "dev\#2: -"
+    }
+    if { [string match "*devnr*" $ooo] } {
+	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
+	set val [get_val2 $ooo i_offset] 
+	.control.offset.in.off3 configure -text "dev\#3: $val"
+	set val [get_val2 $ooo o_offset] 
+	.control.offset.out.off3 configure -text "dev\#3: $val"
+    } else {
+	.control.offset.in.off3 configure -text "dev\#3: -"
+	.control.offset.out.off3 configure -text "dev\#3: -"
+    }
+}
+
+
+proc get_all {} {
+get_status
+get_control
+get_offset
+}
+
+# main
+while {1} {
+  after 200 
+  get_all
+  update
+}
diff -urN linux-2.4.19-pre4/Documentation/usb/proc_usb_info.txt linux-2.4.19-pre5/Documentation/usb/proc_usb_info.txt
--- linux-2.4.19-pre4/Documentation/usb/proc_usb_info.txt	Tue Aug 22 09:06:31 2000
+++ linux-2.4.19-pre5/Documentation/usb/proc_usb_info.txt	Fri Mar 29 14:49:18 2002
@@ -1,32 +1,99 @@
 /proc/bus/usb filesystem output
 ===============================
-(version 2000.08.15)
+(version 2002.03.18)
 
 
-The /proc filesystem for USB devices generates
-/proc/bus/usb/drivers and /proc/bus/usb/devices.
+The /proc filesystem for USB devices provides /proc/bus/usb/drivers
+and /proc/bus/usb/devices, as well as /proc/bus/usb/BBB/DDD files.
 
-/proc/bus/usb/drivers lists the registered drivers,
-one per line, with each driver's USB minor dev node
-number range if applicable.
 
-**NOTE**: If /proc/bus/usb appears empty, you need
-          to mount the filesystem, issue the command (as root):
+**NOTE**: If /proc/bus/usb appears empty, and a host controller
+	  driver has been linked, then you need to mount the
+	  filesystem.  Issue the command (as root):
 
-      mount -t usbdevfs none /proc/bus/usb
+      mount -t usbfs none /proc/bus/usb
 
 	  An alternative and more permanent method would be to add
 
-      none  /proc/bus/usb  usbdevfs  defaults  0  0
+      none  /proc/bus/usb  usbfs  defaults  0  0
 
-	  to /etc/fstab.  This will mount usbdevfs at each reboot.
+	  to /etc/fstab.  This will mount usbfs at each reboot.
 	  You can then issue `cat /proc/bus/usb/devices` to extract
-	  USB device information.
+	  USB device information, and user mode drivers can use usbfs 
+	  to interact with USB devices.
 
-For more information on mounting the usbdevfs file system, see the
+	  There are a number of mount options supported by usbfs.
+	  Consult the source code (linux/drivers/usb/inode.c) for
+	  information about those options.
+
+**NOTE**: The filesystem has been renamed from "usbdevfs" to
+	  "usbfs", to reduce confusion with "devfs".  You may
+	  still see references to the older "usbdevfs" name.
+
+For more information on mounting the usbfs file system, see the
 "USB Device Filesystem" section of the USB Guide. The latest copy 
 of the USB Guide can be found at http://www.linux-usb.org/
 
+
+THE /proc/bus/usb/BBB/DDD FILES:
+--------------------------------
+Each connected USB device has one file.  The BBB indicates the bus
+number.  The DDD indicates the device address on that bus.  Both
+of these numbers are assigned sequentially, and can be reused, so
+you can't rely on them for stable access to devices.  For example,
+it's relatively common for devices to re-enumerate while they are
+still connected (perhaps someone jostled their power supply, hub,
+or USB cable), so a device might be 002/027 when you first connect
+it and 002/048 sometime later.
+
+These files can be read as binary data.  The binary data consists
+of first the device descriptor, then the descriptors for each
+configuration of the device.  That information is also shown in
+text form by the /proc/bus/usb/devices file, described later.
+
+These files may also be used to write user-level drivers for the USB
+devices.  You would open the /proc/bus/usb/BBB/DDD file read/write,
+read its descriptors to make sure it's the device you expect, and then
+bind to an interface (or perhaps several) using an ioctl call.  You
+would issue more ioctls to the device to communicate to it using
+control, bulk, or other kinds of USB transfers.  The IOCTLs are
+listed in the <linux/usbdevice_fs.h> file, and at this writing the
+source code (linux/drivers/usb/devio.c) is the primary reference
+for how to access devices through those files.
+
+Note that since by default these BBB/DDD files are writable only by
+root, only root can write such user mode drivers.  You can selectively
+grant read/write permissions to other users by using "chmod".  Also,
+usbfs mount options such as "devmode=0666" may be helpful.
+
+
+
+THE /proc/bus/usb/drivers FILE:
+-------------------------------
+Each of the USB device drivers linked into your kernel (statically,
+or dynamically using "modprobe") is listed in the "drivers" file.
+Here's an example from one system:
+
+         usbdevfs
+         hub
+  0- 15: usblp
+         usbnet
+         serial
+         usb-storage
+         pegasus
+
+If you see this file, "usbdevfs" and "hub" will always be listed,
+since those are part of the "usbcore" framework.
+
+Drivers that use the USB major number (180) to provide character devices
+will include a range of minor numbers, as shown above for the "usblp"
+(actually "printer.o") module.  USB device drivers can of course use any
+major number, but it's easy to use the USB range since there's explicit
+support for subdividing it in the USB device driver framework.
+
+
+THE /proc/bus/usb/devices FILE:
+-------------------------------
 In /proc/bus/usb/devices, each device's output has multiple
 lines of ASCII output.
 I made it ASCII instead of binary on purpose, so that someone
@@ -34,8 +101,6 @@
 auxiliary program.  However, with an auxiliary program, the numbers
 in the first 4 columns of each "T:" line (topology info:
 Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
-(I think.  I haven't proved this, but I have tested it with 3
-different topo/connections and it looked possible.)
 
 Each line is tagged with a one-character ID for that line:
 
@@ -73,14 +138,30 @@
 |   |__Bus number
 |__Topology info tag
 
+    Speed may be:
+    	1.5	Mbit/s for low speed USB
+	12	Mbit/s for full speed USB
+	480	Mbit/s for high speed USB (added for USB 2.0)
+
 
 Bandwidth info:
 B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
-|   |                       |         |__Number if isochronous requests
+|   |                       |         |__Number of isochronous requests
 |   |                       |__Number of interrupt requests
 |   |__Total Bandwidth allocated to this bus
 |__Bandwidth info tag
 
+    Bandwidth allocation is an approximation of how much of one frame
+    (millisecond) is in use.  It reflects only periodic transfers, which
+    are the only transfers that reserve bandwidth.  Control and bulk
+    transfers use all other bandwidth, including reserved bandwidth that
+    is not used for transfers (such as for short packets).
+    
+    The percentage is how much of the "reserved" bandwidth is scheduled by
+    those transfers.  For a low or full speed bus (loosely, "USB 1.1"),
+    90% of the bus bandwidth is reserved.  For a high speed bus (loosely,
+    "USB 2.0") 80% is reserved.
+
 
 Device descriptor info & Product ID info:
 
@@ -109,37 +190,55 @@
 
 S:  Manufacturer=ssss
 |   |__Manufacturer of this device as read from the device.
+|      For USB host controller drivers (virtual root hubs) this may
+|      be omitted, or (for newer drivers) will identify the kernel
+|      version and the driver which provides this hub emulation.
 |__String info tag
 
 S:  Product=ssss
-|   |__Product description of this device as read from the device,
-|      except that it is a generated string for USB host controllers
-|      (virtual root hubs), in the form "USB *HCI Root Hub".
+|   |__Product description of this device as read from the device.
+|      For older USB host controller drivers (virtual root hubs) this
+|      indicates the driver; for newer ones, it's a product (and vendor)
+|      description that often comes from the kernel's PCI ID database.
 |__String info tag
 
 S:  SerialNumber=ssss
-|   |__Serial Number of this device as read from the device,
-|      except that it is a generated string for USB host controllers
-|      (virtual root hubs), and represents the host controller's
-|      unique identification in the system (currently I/O or
-|      memory-mapped base address).
+|   |__Serial Number of this device as read from the device.
+|      For USB host controller drivers (virtual root hubs) this is
+|      some unique ID, normally a bus ID (address or slot name) that
+|      can't be shared with any other device.
 |__String info tag
 
 
+
 Configuration descriptor info:
 
-C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
-|   |       |       |      |__MaxPower in mA
-|   |       |       |__Attributes
-|   |       |__ConfiguratioNumber
-|   |__NumberOfInterfaces
+C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
+| | |       |       |      |__MaxPower in mA
+| | |       |       |__Attributes
+| | |       |__ConfiguratioNumber
+| | |__NumberOfInterfaces
+| |__ "*" indicates the active configuration (others are " ")
 |__Config info tag
+    
+    USB devices may have multiple configurations, each of which act
+    rather differently.  For example, a bus-powered configuration
+    might be much less capable than one that is self-powered.  Only
+    one device configuration can be active at a time; most devices
+    have only one configuration.
+
+    Each configuration consists of one or more interfaces.  Each
+    interface serves a distinct "function", which is typically bound
+    to a different USB device driver.  One common example is a USB
+    speaker with an audio interface for playback, and a HID interface
+    for use with software volume control.
 
 
 Interface descriptor info (can be multiple per Config):
 
 I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
 |   |      |      |       |             |      |       |__Driver name
+|   |      |      |       |             |      |          or "(none)"
 |   |      |      |       |             |      |__InterfaceProtocol
 |   |      |      |       |             |__InterfaceSubClass
 |   |      |      |       |__InterfaceClass
@@ -148,17 +247,39 @@
 |   |__InterfaceNumber
 |__Interface info tag
 
+    A given interface may have one or more "alternate" settings.
+    For example, default settings may not use more than a small
+    amount of periodic bandwidth.  To use significant fractions
+    of bus bandwidth, drivers must select a non-default altsetting.
+    
+    Only one setting for an interface may be active at a time, and
+    only one driver may bind to an interface at a time.  Most devices
+    have only one alternate setting per interface.
+
 
 Endpoint descriptor info (can be multiple per Interface):
 
 E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-|   |        |            |         |__Interval
+|   |        |            |         |__Interval (max) between transfers
 |   |        |            |__EndpointMaxPacketSize
 |   |        |__Attributes(EndpointType)
 |   |__EndpointAddress(I=In,O=Out)
 |__Endpoint info tag
 
+    The interval is nonzero for all periodic (interrupt or isochronous)
+    endpoints.  For high speed endpoints the transfer interval may be
+    measured in microseconds rather than milliseconds.
+
+    For high speed periodic endpoints, the "MaxPacketSize" reflects
+    the per-microframe data transfer size.  For "high bandwidth"
+    endpoints, that can reflect two or three packets (for up to
+    3KBytes every 125 usec) per endpoint.
+
+    With the Linux-USB stack, periodic bandwidth reservations use the
+    transfer intervals and sizes provided by URBs, which can be less
+    than those found in endpoint descriptor.
+
+
 =======================================================================
 
 
diff -urN linux-2.4.19-pre4/MAINTAINERS linux-2.4.19-pre5/MAINTAINERS
--- linux-2.4.19-pre4/MAINTAINERS	Fri Mar 29 14:48:53 2002
+++ linux-2.4.19-pre5/MAINTAINERS	Fri Mar 29 14:49:18 2002
@@ -714,12 +714,12 @@
 IDE DRIVER [GENERAL]
 P:	Andre Hedrick
 M:	andre@linux-ide.org
-M:	andre@aslab.com
-M:	andre@suse.com
+M:	andre@linuxdiskcert.org
 L:	linux-kernel@vger.kernel.org
 W:	http://www.kernel.org/pub/linux/kernel/people/hedrick/
 W:	http://www.linux-ide.org/
-S:	Supported
+W:	http://www.linuxdiskcert.org/
+S:	Maintained
 
 IDE/ATAPI CDROM DRIVER
 P:	Jens Axboe
@@ -742,16 +742,12 @@
 S:	Maintained
 
 IEEE 1394 SUBSYSTEM
-P:	Andreas Bombe
-M:	andreas.bombe@munich.netsurf.de
+P:	Ben Collins
+M:	bcollins@debian.org
 L:	linux1394-devel@lists.sourceforge.net
 W:	http://linux1394.sourceforge.net/
 S:	Maintained
 
-IEEE 1394 AIC5800 DRIVER
-L:	linux1394-devel@lists.sourceforge.net
-S:	Orphan
-
 IEEE 1394 OHCI DRIVER
 P:	Ben Collins
 M:	bcollins@debian.org
@@ -863,7 +859,7 @@
 M:	vojtech@suse.cz
 L:	linux-joystick@atrey.karlin.mff.cuni.cz
 W:	http://www.suse.cz/development/joystick/
-S:	Supported
+S:	Maintained
 
 KERNEL AUTOMOUNTER (AUTOFS)
 P:	H. Peter Anvin
@@ -932,6 +928,13 @@
 L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
 
+LINUX FOR 64BIT POWERPC
+P:	David Engebretsen
+M:	engebret@us.ibm.com
+W:	http://linuxppc64.org
+L:	linuxppc64-dev@lists.linuxppc.org
+S:	Supported
+
 LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
 P:	Richard Russon (FlatCap)
 M:	ldm@flatcap.org
@@ -1197,8 +1200,10 @@
 S:	Maintained
 
 PCI ID DATABASE
-P:	Jens Maurer
-M:	jmaurer@cck.uni-kl.de
+P:	Martin Mares
+M:	mj@ucw.cz
+L:	pciids-devel@lists.sourceforge.net
+W:	http://pciids.sourceforge.net/
 S:	Maintained
 
 PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES)
@@ -1440,8 +1445,6 @@
 M:	anton@samba.org
 L:	sparclinux@vger.kernel.org
 L:	ultralinux@vger.kernel.org
-W:	http://ultra.linux.cz
-W:	http://www.geog.ubc.ca/s_linux.html
 S:	Maintained
 
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
@@ -1590,7 +1593,7 @@
 M:	vojtech@suse.cz
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 USB AUERSWALD DRIVER
 P:	Wolfgang Muees
@@ -1626,7 +1629,7 @@
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.suse.cz/development/input/
-S:	Supported
+S:	Maintained
 
 USB HUB
 P:	Johannes Erdfelt
@@ -1677,7 +1680,7 @@
 M:	vojtech@suse.cz
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 USB SE401 DRIVER
 P:	Jeroen Vreeken
diff -urN linux-2.4.19-pre4/Makefile linux-2.4.19-pre5/Makefile
--- linux-2.4.19-pre4/Makefile	Fri Mar 29 14:48:53 2002
+++ linux-2.4.19-pre5/Makefile	Fri Mar 29 14:49:18 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 19
-EXTRAVERSION = -pre4
+EXTRAVERSION = -pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.19-pre4/arch/alpha/kernel/alpha_ksyms.c linux-2.4.19-pre5/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.19-pre4/arch/alpha/kernel/alpha_ksyms.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre5/arch/alpha/kernel/alpha_ksyms.c	Fri Mar 29 14:49:18 2002
@@ -214,6 +214,7 @@
 EXPORT_SYMBOL(smp_imb);
 EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL(__cpu_number_map);
+EXPORT_SYMBOL(__cpu_logical_map);
 EXPORT_SYMBOL(smp_num_cpus);
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_call_function_on_cpu);
diff -urN linux-2.4.19-pre4/arch/alpha/kernel/entry.S linux-2.4.19-pre5/arch/alpha/kernel/entry.S
--- linux-2.4.19-pre4/arch/alpha/kernel/entry.S	Fri Mar 29 14:48:53 2002
+++ linux-2.4.19-pre5/arch/alpha/kernel/entry.S	Fri Mar 29 14:49:18 2002
@@ -10,7 +10,7 @@
 
 #define SIGCHLD 20
 
-#define NR_SYSCALLS 378
+#define NR_SYSCALLS 382
 
 /*
  * These offsets must match with alpha_mv in <asm/machvec.h>.
@@ -1149,3 +1149,8 @@
 	.quad sys_readahead
 	.quad sys_ni_syscall			/* 380, sys_security */
 	.quad sys_tkill
+
+/* Remember to update everything, kids.  */
+.ifne (. - sys_call_table) - (NR_SYSCALLS * 8)
+.err
+.endif
diff -urN linux-2.4.19-pre4/arch/alpha/math-emu/math.c linux-2.4.19-pre5/arch/alpha/math-emu/math.c
--- linux-2.4.19-pre4/arch/alpha/math-emu/math.c	Fri Sep 22 13:54:09 2000
+++ linux-2.4.19-pre5/arch/alpha/math-emu/math.c	Fri Mar 29 14:49:18 2002
@@ -220,12 +220,12 @@
 				FP_CONV(S,D,1,1,SR,DB);
 				goto pack_s;
 			} else {
-				/* CVTST need do nothing else but copy the
-				   bits and repack.  */
+				vb = alpha_read_fp_reg_s(fb);
+				FP_UNPACK_SP(SB, &vb);
 				DR_c = DB_c;
 				DR_s = DB_s;
 				DR_e = DB_e;
-				DR_f = DB_f;
+				DR_f = SB_f << (52 - 23);
 				goto pack_d;
 			}
 
diff -urN linux-2.4.19-pre4/arch/alpha/mm/init.c linux-2.4.19-pre5/arch/alpha/mm/init.c
--- linux-2.4.19-pre4/arch/alpha/mm/init.c	Thu Sep 20 20:02:03 2001
+++ linux-2.4.19-pre5/arch/alpha/mm/init.c	Fri Mar 29 14:49:18 2002
@@ -380,7 +380,7 @@
 		free_page(addr);
 		totalram_pages++;
 	}
-	printk ("Freeing unused kernel memory: %ldk freed\n",
+	printk (KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
 
@@ -395,7 +395,7 @@
 		free_page(start);
 		totalram_pages++;
 	}
-	printk ("Freeing initrd memory: %ldk freed\n", (end - __start) >> 10);
+	printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - __start) >> 10);
 }
 #endif
 
diff -urN linux-2.4.19-pre4/arch/alpha/mm/numa.c linux-2.4.19-pre5/arch/alpha/mm/numa.c
--- linux-2.4.19-pre4/arch/alpha/mm/numa.c	Sun Aug 12 10:38:48 2001
+++ linux-2.4.19-pre5/arch/alpha/mm/numa.c	Fri Mar 29 14:49:18 2002
@@ -312,7 +312,7 @@
 		printk(".");				\
 } while(0)
 
-#define clobber(p, size) memset((p)->virtual, 0xaa, (size))
+#define clobber(p, size) memset(page_address(p), 0xaa, (size))
 
 void __init mem_stress(void)
 {
diff -urN linux-2.4.19-pre4/arch/arm/Makefile linux-2.4.19-pre5/arch/arm/Makefile
--- linux-2.4.19-pre4/arch/arm/Makefile	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre5/arch/arm/Makefile	Fri Mar 29 14:49:18 2002
@@ -39,10 +39,12 @@
 tune-$(CONFIG_CPU_ARM710)	:=-mtune=arm710
 tune-$(CONFIG_CPU_ARM720T)	:=-mtune=arm7tdmi
 tune-$(CONFIG_CPU_ARM920T)	:=-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM922T)	:=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM926T)	:=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_SA110)	:=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)	:=-mtune=strongarm1100
 
+CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
 CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
 AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu -msoft-float
 
@@ -74,6 +76,8 @@
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 MACHINE		 = ebsa110
+CFLAGS_3c589_cs	:=-DISA_SIXTEEN_BIT_PERIPHERAL
+export CFLAGS_3c589_cs
 endif
 
 ifeq ($(CONFIG_ARCH_CLPS7500),y)
@@ -121,6 +125,10 @@
 MACHINE		 = integrator
 endif
 
+ifeq ($(CONFIG_ARCH_MX1ADS),y)
+MACHINE		 = mx1ads
+endif
+
 ifeq ($(CONFIG_ARCH_CAMELOT),y)
 MACHINE          = epxa10db
 endif
@@ -130,11 +138,15 @@
 MACHINE		 = clps711x
 endif
 
+ifeq ($(CONFIG_ARCH_FORTUNET),y)
+TEXTADDR	 = 0xc0008000
+endif
+
 ifeq ($(CONFIG_ARCH_ANAKIN),y)
 MACHINE		 = anakin
 endif
 
-export	MACHINE PROCESSOR TEXTADDR GZFLAGS
+export	MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT
 
 # Only set INCDIR if its not already defined above
 # Grr, ?= doesn't work as all the other assignment operators do.  Make bug?
@@ -207,6 +219,7 @@
 	arch/arm/vmlinux.lds
 
 MRPROPER_FILES	+= \
+	arch/arm/tools/constants.h* \
 	include/asm-arm/arch \
 	include/asm-arm/proc \
 	include/asm-arm/constants.h* \
@@ -254,7 +267,7 @@
 	@( \
 	CFG=$(@:_config=); \
 	if [ -f arch/arm/def-configs/$$CFG ]; then \
-	  [ -f .config ] && $(MV) .config .config.old; \
+	  [ -f .config ] && mv -f .config .config.old; \
 	  cp arch/arm/def-configs/$$CFG .config; \
 	  echo "*** Default configuration for $$CFG installed"; \
 	  echo "*** Next, you may run 'make oldconfig'"; \
diff -urN linux-2.4.19-pre4/arch/arm/boot/Makefile linux-2.4.19-pre5/arch/arm/boot/Makefile
--- linux-2.4.19-pre4/arch/arm/boot/Makefile	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/boot/Makefile	Fri Mar 29 14:49:18 2002
@@ -54,6 +54,14 @@
 INITRD_VIRT	 = 0xc0800000
 endif
 
+ifeq ($(CONFIG_ARCH_MX1ADS),y)
+ZTEXTADDR	 = 0x08008000
+endif
+
+ifeq ($(CONFIG_ARCH_CAMELOT),y)
+ZTEXTADDR	 = 0x00008000
+endif
+
 ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
 ZTEXTADDR	 = 0x40008000
 endif
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/Makefile linux-2.4.19-pre5/arch/arm/boot/compressed/Makefile
--- linux-2.4.19-pre4/arch/arm/boot/compressed/Makefile	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/Makefile	Fri Mar 29 14:49:18 2002
@@ -9,7 +9,7 @@
 
 HEAD		 = head.o
 OBJS		 = misc.o
-CFLAGS		 = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) -msoft-float
+CFLAGS		 = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_BOOT)
 FONTC		 = $(TOPDIR)/drivers/video/font_acorn_8x8.c
 ZLDFLAGS	 = -p -X -T vmlinux.lds
 
@@ -33,6 +33,14 @@
 OBJS		+= head-integrator.o
 endif
 
+ifeq ($(CONFIG_ARCH_MX1ADS),y)
+OBJS		+= head-mx1ads.o
+endif
+
+ifeq ($(CONFIG_ARCH_CAMELOT),y)
+OBJS		+= head-epxa10db.o
+endif
+
 ifeq ($(CONFIG_ARCH_FTVPCI),y)
 OBJS		+= head-ftvpci.o
 endif
@@ -84,12 +92,12 @@
 font.o:		$(FONTC)
 		$(CC) $(CFLAGS) -Dstatic= -c -o $@ $(FONTC)
 
-vmlinux.lds:	vmlinux.lds.in
+vmlinux.lds:	vmlinux.lds.in Makefile $(TOPDIR)/arch/$(ARCH)/boot/Makefile $(TOPDIR)/.config
 		@sed "$(SEDFLAGS)" < vmlinux.lds.in > $@
 
 clean:;		rm -f vmlinux core piggy* vmlinux.lds
 
-.PHONY:	vmlinux.lds clean
+.PHONY:	clean
 
 misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c
 
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/head-epxa10db.S linux-2.4.19-pre5/arch/arm/boot/compressed/head-epxa10db.S
--- linux-2.4.19-pre4/arch/arm/boot/compressed/head-epxa10db.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/head-epxa10db.S	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,5 @@
+#include <asm/mach-types.h>
+#include <asm/arch/excalibur.h>
+
+		.section	".start", #alloc, #execinstr
+		mov	r7, #MACH_TYPE_CAMELOT
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/head-mx1ads.S linux-2.4.19-pre5/arch/arm/boot/compressed/head-mx1ads.S
--- linux-2.4.19-pre4/arch/arm/boot/compressed/head-mx1ads.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/head-mx1ads.S	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,4 @@
+#include <asm/mach-types.h>
+
+		.section	".start", #alloc, #execinstr
+		mov	r7, #MACH_TYPE_MX1ADS
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/head-shark.S linux-2.4.19-pre5/arch/arm/boot/compressed/head-shark.S
--- linux-2.4.19-pre4/arch/arm/boot/compressed/head-shark.S	Thu Apr 12 12:03:50 2001
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/head-shark.S	Fri Mar 29 14:49:18 2002
@@ -1,5 +1,5 @@
 /* The head-file for the Shark
- * by Alexander Schulz <aschulz@netwinder.org>
+ * by Alexander Schulz
  *
  * Does the following:
  * - get the memory layout from firmware. This can only be done as long as the mmu
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/head.S linux-2.4.19-pre5/arch/arm/boot/compressed/head.S
--- linux-2.4.19-pre4/arch/arm/boot/compressed/head.S	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/head.S	Fri Mar 29 14:49:18 2002
@@ -18,14 +18,14 @@
  * Please select one of the following when turning on debugging.
  */
 #ifdef DEBUG
-#if 0 /* DC21285-type */
+#if defined(CONFIG_DEBUG_DC21285_PORT)
 		.macro	loadsp,	rb
 		mov	\rb, #0x7c000000
 		.endm
 		.macro	writeb,	rb
 		strb	\rb, [r3, #0x3f8]
 		.endm
-#elif 0 /* RiscPC-type */
+#elif defined(CONFIG_ARCH_RPC)
 		.macro	loadsp,	rb
 		mov	\rb, #0x03000000
 		orr	\rb, \rb, #0x00010000
@@ -33,13 +33,25 @@
 		.macro	writeb,	rb
 		strb	\rb, [r3, #0x3f8 << 2]
 		.endm
-#elif 0 /* integrator-type */
+#elif defined(CONFIG_ARCH_INTEGRATOR)
 		.macro	loadsp, rb
 		mov	\rb, #0x16000000
 		.endm
 		.macro	writeb, rb
 		strb	\rb, [r3, #0]
 		.endm
+#elif defined(CONFIG_ARCH_SA1100)
+		.macro	loadsp, rb
+		mov	\rb, #0x80000000	@ physical base address
+#  if defined(CONFIG_DEBUG_LL_SER3)
+		add	\rb, \rb, #0x00050000	@ Ser3
+#  else
+		add	\rb, \rb, #0x00010000	@ Ser1
+#  endif
+		.endm
+		.macro	writeb, rb
+		str	\rb, [r3, #0x14]	@ UTDR
+		.endm
 #else
 #error no serial architecture defined
 #endif
@@ -64,7 +76,7 @@
 		kphex	r7, 8		/* architecture id */
 		kputc	#':'
 		mrc	p15, 0, r0, c1, c0
-		kphex	r0, 8		/* control reg
+		kphex	r0, 8		/* control reg */
 		kputc	#'\n'
 		kphex	r5, 8		/* decompressed kernel start */
 		kputc	#'-'
@@ -218,7 +230,8 @@
 		ldr     r1, proc_sa1110_type
 		eor	r1, r1, r6
 		movs	r1, r1, lsr #4
-		movne	pc, lr
+@		movne	pc, lr
+		bne	cache_off
 1:
 		sub	r3, r4, #16384		@ Page directory size
 		bic	r3, r3, #0xff		@ Align the pointer
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/misc.c linux-2.4.19-pre5/arch/arm/boot/compressed/misc.c
--- linux-2.4.19-pre4/arch/arm/boot/compressed/misc.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/misc.c	Fri Mar 29 14:49:18 2002
@@ -18,6 +18,8 @@
 
 unsigned int __machine_arch_type;
 
+#include <linux/kernel.h>
+
 #include <asm/uaccess.h>
 #include <asm/arch/uncompress.h>
 #include <asm/proc/uncompress.h>
diff -urN linux-2.4.19-pre4/arch/arm/boot/compressed/ofw-shark.c linux-2.4.19-pre5/arch/arm/boot/compressed/ofw-shark.c
--- linux-2.4.19-pre4/arch/arm/boot/compressed/ofw-shark.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/boot/compressed/ofw-shark.c	Fri Mar 29 14:49:18 2002
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/boot/compressed/ofw-shark.c
  *
- * by Alexander Schulz <aschulz@netwinder.org>
+ * by Alexander Schulz
  *
  * This file is used to get some basic information
  * about the memory layout of the shark we are running
diff -urN linux-2.4.19-pre4/arch/arm/config.in linux-2.4.19-pre5/arch/arm/config.in
--- linux-2.4.19-pre4/arch/arm/config.in	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre5/arch/arm/config.in	Fri Mar 29 14:49:18 2002
@@ -43,6 +43,7 @@
 	 FootBridge		CONFIG_ARCH_FOOTBRIDGE \
 	 Integrator		CONFIG_ARCH_INTEGRATOR \
 	 LinkUp-L7200		CONFIG_ARCH_L7200 \
+	 Motorola-MX1ADS        CONFIG_ARCH_MX1ADS \
 	 RiscPC			CONFIG_ARCH_RPC \
  	 SA1100-based		CONFIG_ARCH_SA1100 \
 	 Shark			CONFIG_ARCH_SHARK" RiscPC
@@ -85,7 +86,14 @@
          32MB   CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash
    bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
 fi
-dep_bool '  Compaq iPAQ H3600' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3600/H3700' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3800' CONFIG_SA1100_H3800 $CONFIG_ARCH_SA1100
+if [ "$CONFIG_SA1100_H3100" = "y" -o "$CONFIG_SA1100_H3600" = "y" -o "$CONFIG_SA1100_H3800" = "y" ]; then
+  define_bool CONFIG_SA1100_H3XXX y
+else
+  define_bool CONFIG_SA1100_H3XXX n
+fi
 #dep_bool '  Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100
 dep_bool '  Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100
 if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then
@@ -93,8 +101,10 @@
 fi
 dep_bool '  FlexaNet' CONFIG_SA1100_FLEXANET $CONFIG_ARCH_SA1100
 dep_bool '  FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100
+dep_bool '  Frodo' CONFIG_SA1100_FRODO $CONFIG_ARCH_SA1100
 dep_bool '  GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100
 dep_bool '  GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100
+dep_bool '  HP Labs BadgePAD 4' CONFIG_SA1100_BADGE4 $CONFIG_ARCH_SA1100
 dep_bool '  HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100
 dep_bool '  HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100
 dep_bool '  Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100
@@ -103,6 +113,8 @@
 dep_bool '  OmniMeter' CONFIG_SA1100_OMNIMETER $CONFIG_ARCH_SA1100
 dep_bool '  Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100
 dep_bool '  PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100
+dep_bool '  PT System 3' CONFIG_SA1100_PT_SYSTEM3 $CONFIG_ARCH_SA1100
+dep_bool '  Shannon' CONFIG_SA1100_SHANNON $CONFIG_ARCH_SA1100
 dep_bool '  Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100
 dep_bool '  Simpad' CONFIG_SA1100_SIMPAD $CONFIG_ARCH_SA1100
 dep_bool '  Tulsa' CONFIG_SA1100_PFS168 $CONFIG_ARCH_SA1100
@@ -116,18 +128,28 @@
      "$CONFIG_SA1100_PFS168" = "y" -o \
      "$CONFIG_SA1100_XP860" = "y" -o \
      "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \
-     "$CONFIG_SA1100_ADSBITSY" = "y" ]; then
+     "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \
+     "$CONFIG_SA1100_ADSBITSY" = "y" -o \
+     "$CONFIG_SA1100_BADGE4" = "y" ]; then
    define_bool CONFIG_SA1111 y
    define_int CONFIG_FORCE_MAX_ZONEORDER 9
 fi
+
+#dep_tristate 'SA1100 USB function support' CONFIG_SA1100_USB $CONFIG_ARCH_SA1100
+#dep_tristate '  Support for SA11x0 USB network link function' CONFIG_SA1100_USB_NETLINK $CONFIG_SA1100_USB
+#dep_tristate '  Support for SA11x0 USB character device emulation' CONFIG_SA1100_USB_CHAR $CONFIG_SA1100_USB
+
+dep_tristate 'Compaq iPAQ Handheld sleeve support' CONFIG_H3600_SLEEVE $CONFIG_SA1100_H3600
 endmenu
 
 mainmenu_option next_comment
 comment 'CLPS711X/EP721X Implementations'
+dep_bool '  AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X
 dep_bool '  CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X
 dep_bool '  CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X
 dep_bool '  EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X
 dep_bool '  P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X
+dep_bool '  FORTUNET' CONFIG_ARCH_FORTUNET $CONFIG_ARCH_CLPS711X
 
 # XXX Maybe these should indicate register compatibility
 # instead of being mutually exclusive.
@@ -205,7 +227,7 @@
      "$CONFIG_ARCH_NEXUSPCI"   = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \
      "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100"   = "y" -o \
      "$CONFIG_ARCH_L7200"      = "y" -o "$CONFIG_ARCH_ANAKIN"	= "y" -o \
-     "$CONFIG_ARCH_CAMELOT"    = "y" ]; then
+     "$CONFIG_ARCH_CAMELOT"    = "y" -o "$CONFIG_ARCH_MX1ADS"   = "y" ]; then
    define_bool CONFIG_CPU_32v4 y
 else
    define_bool CONFIG_CPU_32v4 n
@@ -247,11 +269,17 @@
 fi
 
 # ARM920T
-if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
-   bool 'Support ARM920T processor' CONFIG_CPU_ARM920T
+if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then
+   define_bool CONFIG_CPU_ARM920T y
 else
-   define_bool CONFIG_CPU_ARM920T n
+   if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+      bool 'Support ARM920T processor' CONFIG_CPU_ARM920T
+   else
+      define_bool CONFIG_CPU_ARM920T n
+   fi
 fi
+
+
 if [ "$CONFIG_CPU_ARM920T" = "y" ]; then
    bool '  ARM920T CPU idle' CONFIG_CPU_ARM920_CPU_IDLE
    bool '  ARM920T I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON
@@ -261,6 +289,21 @@
    fi
 fi
 
+# ARM922T
+if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then
+         define_bool CONFIG_CPU_ARM922T y
+else
+         define_bool CONFIG_CPU_ARM922T n
+fi
+if [ "$CONFIG_CPU_ARM922T" = "y" ]; then
+   bool '  ARM922T CPU idle' CONFIG_CPU_ARM922_CPU_IDLE
+   bool '  ARM922T I-Cache on' CONFIG_CPU_ARM922_I_CACHE_ON
+   bool '  ARM922T D-Cache on' CONFIG_CPU_ARM922_D_CACHE_ON
+   if [ "$CONFIG_CPU_ARM922_D_CACHE_ON" = "y" ] ; then
+      bool '  Force write through caches on ARM922T' CONFIG_CPU_ARM922_WRITETHROUGH
+   fi
+fi
+
 # ARM926T
 if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
    bool 'Support ARM926T processor' CONFIG_CPU_ARM926T
@@ -404,7 +447,8 @@
      "$CONFIG_ARCH_P720T" = "y" -o	     \
      "$CONFIG_ARCH_CDB89712" = "y" -o	     \
      "$CONFIG_ARCH_CAMELOT" = "y" -o	     \
-     "$CONFIG_ARCH_ANAKIN" = "y" ]; then
+     "$CONFIG_ARCH_ANAKIN" = "y"  -o         \
+     "$CONFIG_ARCH_MX1ADS" = "y" ]; then
    string 'Default kernel command string' CONFIG_CMDLINE ""
 fi
 if [ "$CONFIG_ARCH_NETWINDER" = "y" -o  \
@@ -554,7 +598,8 @@
         "$CONFIG_ARCH_TBOX" = "y" -o       \
         "$CONFIG_ARCH_CLPS7500" = "y" -o   \
         "$CONFIG_ARCH_P720T" = "y" -o      \
-        "$CONFIG_ARCH_ANAKIN" = "y" ]; then
+        "$CONFIG_ARCH_ANAKIN" = "y" -o      \
+	"$CONFIG_ARCH_MX1ADS" = "y" ]; then
       define_bool CONFIG_PC_KEYMAP y
    fi
    if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
@@ -594,15 +639,19 @@
 # Always compile kernel with framepointer (until 2.4 real comes out)
 # Bug reports aren't much use without this.
 bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER
-bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS
 bool 'Verbose user fault messages' CONFIG_DEBUG_USER
 bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
-bool 'Debug memory allocations' CONFIG_DEBUG_SLAB
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK
 dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
+
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+dep_bool '  Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL
+dep_bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL
+dep_bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL
+dep_bool '  Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL
+dep_bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL
+dep_bool '  Verbose kernel error messages' CONFIG_DEBUG_ERRORS $CONFIG_DEBUG_KERNEL
 # These options are only for real kernel hackers who want to get their hands dirty. 
-dep_bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_EXPERIMENTAL
-dep_bool '  Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
-dep_bool '  kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
+dep_bool '  Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL
+dep_bool '    Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
+dep_bool '    Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
 endmenu
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/badge4 linux-2.4.19-pre5/arch/arm/def-configs/badge4
--- linux-2.4.19-pre4/arch/arm/def-configs/badge4	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/def-configs/badge4	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,1136 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+CONFIG_SA1100_BADGE4=y
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1111=y
+CONFIG_FORCE_MAX_ZONEORDER=9
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+
+#
+# Processor Type
+#
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_PROBE=y
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+CONFIG_PCMCIA_SA1100=y
+CONFIG_NET=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_FASTFPE=m
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_PM is not set
+CONFIG_ARTHUR=m
+CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=0
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=y
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=y
+CONFIG_AIRO_CS=m
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=y
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=y
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+# CONFIG_IRNET is not set
+CONFIG_IRCOMM=y
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_SA1100_FIR=y
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDESCSI=m
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=115200
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_PHILIPSPAR is not set
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+# CONFIG_I2C_BIT_SA1100_GPIO is not set
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=y
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+
+#
+# Other L3 adapters
+#
+CONFIG_L3_SA1111=y
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+CONFIG_RTC=m
+CONFIG_SA1100_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_CRAMFS=m
+CONFIG_TMPFS=y
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+CONFIG_ZLIB_FS_INFLATE=m
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_SA1100=y
+CONFIG_SOUND_UDA1341=y
+# CONFIG_SOUND_ASSABET_UDA1341 is not set
+# CONFIG_SOUND_H3600_UDA1341 is not set
+# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
+CONFIG_SOUND_SA1111_UDA1341=y
+# CONFIG_SOUND_SA1100SSP is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+CONFIG_MCP=y
+CONFIG_MCP_SA1100=y
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+CONFIG_USB_OHCI_SA1111=y
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=y
+CONFIG_USB_BLUETOOTH=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+
+#
+#   Input core support is needed for USB HID
+#
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_DC2XX=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+# CONFIG_USB_STV680 is not set
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_DABUSB=m
+
+#
+# USB Network adaptors
+#
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_CATC=m
+CONFIG_USB_CDCETHER=m
+CONFIG_USB_USBNET=m
+
+#
+# USB port drivers
+#
+CONFIG_USB_USS720=m
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_KLSI is not set
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_RIO500=m
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIVHCI=m
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/flexanet linux-2.4.19-pre5/arch/arm/def-configs/flexanet
--- linux-2.4.19-pre4/arch/arm/def-configs/flexanet	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/def-configs/flexanet	Fri Mar 29 14:49:18 2002
@@ -8,6 +8,8 @@
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
 
 #
 # Code maturity level options
@@ -25,17 +27,19 @@
 #
 # System Type
 #
+# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_SHARK is not set
 
 #
 # Archimedes/A5000 Implementations
@@ -44,22 +48,32 @@
 #
 # Archimedes/A5000 Implementations (select only ONE)
 #
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
 
 #
 # Footbridge Implementations
 #
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
 # CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_BITSY is not set
+# CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_EXTENEX1 is not set
 CONFIG_SA1100_FLEXANET=y
 # CONFIG_SA1100_FREEBIRD is not set
 # CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HUW_WEBPANEL is not set
 # CONFIG_SA1100_ITSY is not set
@@ -68,7 +82,9 @@
 # CONFIG_SA1100_OMNIMETER is not set
 # CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_PFS168 is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_XP860 is not set
@@ -76,11 +92,17 @@
 CONFIG_SA1100_USB=y
 CONFIG_SA1100_USB_NETLINK=y
 # CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_SA1100_FREQUENCY_SCALE is not set
 
 #
 # CLPS711X/EP721X Implementations
 #
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
 # CONFIG_ARCH_ACORN is not set
 # CONFIG_FOOTBRIDGE is not set
 # CONFIG_FOOTBRIDGE_HOST is not set
@@ -97,32 +119,40 @@
 # CONFIG_CPU_ARM710 is not set
 # CONFIG_CPU_ARM720T is not set
 # CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
 # CONFIG_CPU_SA110 is not set
 CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
 CONFIG_DISCONTIGMEM=y
-# CONFIG_CPU_BIG_ENDIAN is not set
 
 #
 # General setup
 #
 # CONFIG_PCI is not set
-# CONFIG_ISA is not set
+CONFIG_ISA=y
 # CONFIG_ISA_DMA is not set
-# CONFIG_CPU_CLOCK is not set
+CONFIG_CPU_FREQ=y
 CONFIG_HOTPLUG=y
 
 #
 # PCMCIA/CardBus support
 #
 CONFIG_PCMCIA=y
+# CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
 CONFIG_PCMCIA_SA1100=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_FASTFPE=y
 CONFIG_KCORE_ELF=y
@@ -130,7 +160,7 @@
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_PM is not set
+CONFIG_PM=y
 # CONFIG_ARTHUR is not set
 CONFIG_CMDLINE=""
 CONFIG_LEDS=y
@@ -149,7 +179,7 @@
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_REDBOOT_PARTS=y
 # CONFIG_MTD_BOOTLDR_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
@@ -165,43 +195,42 @@
 # RAM/ROM/Flash chip drivers
 #
 CONFIG_MTD_CFI=y
-# CONFIG_MTD_CFI_VIRTUAL_ER is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
 CONFIG_MTD_CFI_ADV_OPTIONS=y
 CONFIG_MTD_CFI_NOSWAP=y
 # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
 # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_LART_BIT_SWAP is not set
 # CONFIG_MTD_CFI_GEOMETRY is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
 # CONFIG_MTD_JEDEC is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
 # CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
 CONFIG_MTD_SA1100=y
+# CONFIG_MTD_DC21285 is not set
 # CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_ARMFLASH is not set
+# CONFIG_MTD_PCI is not set
 
 #
 # Self-contained MTD device drivers
 #
+# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -220,11 +249,17 @@
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -235,6 +270,13 @@
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
@@ -258,6 +300,7 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #
@@ -293,42 +336,75 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
 CONFIG_NET_VENDOR_SMC=y
 # CONFIG_WD80x3 is not set
+# CONFIG_ULTRAMCA is not set
 # CONFIG_ULTRA is not set
+# CONFIG_ULTRA32 is not set
 CONFIG_SMC9194=y
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 
 #
@@ -347,8 +423,10 @@
 # CONFIG_PCMCIA_NMCLAN is not set
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
 # CONFIG_NET_PCMCIA_RADIO is not set
-CONFIG_PCMCIA_NETCARD=y
 
 #
 # Amateur Radio support
@@ -378,20 +456,33 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
 # CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
 CONFIG_BLK_DEV_IDECS=y
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
 
 #
 # IDE chipset support/bugfixes
 #
 # CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
 
 #
 # SCSI support
@@ -402,6 +493,10 @@
 # I2O device support
 #
 # CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
@@ -412,6 +507,10 @@
 # Input core support
 #
 # CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Character devices
@@ -419,21 +518,38 @@
 CONFIG_VT=y
 # CONFIG_VT_CONSOLE is not set
 # CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
 CONFIG_SERIAL_SA1100=y
-# CONFIG_SERIAL_SA1100_OLD is not set
 CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SA1100_DEFAULT_BAUDRATE=57600
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=32
-CONFIG_UCB1200=y
-CONFIG_TOUCHSCREEN_UCB1200=y
-CONFIG_AUDIO_UCB1200=y
-CONFIG_ADC_UCB1200=y
-# CONFIG_TOUCHSCREEN_BITSY is not set
-# CONFIG_PROFILER is not set
 
 #
 # I2C support
@@ -441,37 +557,35 @@
 # CONFIG_I2C is not set
 
 #
-# Mice
+# L3 serial bus support
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
 
 #
-# Joysticks
+# Other L3 adapters
 #
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
 
 #
-# Game port support
-#
-
-#
-# Gameport joysticks
-#
-
-#
-# Serial port support
+# Mice
 #
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
 
 #
-# Serial port joysticks
+# Joysticks
 #
+# CONFIG_INPUT_GAMEPORT is not set
 
 #
-# Parallel port joysticks
+# Input core support is needed for gameports
 #
 
 #
-#   Parport support is needed for parallel port joysticks
+# Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
 
@@ -479,6 +593,7 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 CONFIG_SA1100_RTC=y
@@ -509,44 +624,74 @@
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-CONFIG_CRAMFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
 CONFIG_RAMFS=y
 # CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-CONFIG_ROMFS_FS=y
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -562,6 +707,7 @@
 # CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
@@ -573,15 +719,17 @@
 #
 CONFIG_PC_KEYMAP=y
 # CONFIG_VGA_CONSOLE is not set
-CONFIG_FB=y
 
 #
 # Frame-buffer support
 #
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
-# CONFIG_FB_E1355 is not set
+# CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB2=y
@@ -597,28 +745,49 @@
 # Sound
 #
 CONFIG_SOUND=y
-# CONFIG_SOUND_SA1100_SSP is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_SA1100 is not set
+# CONFIG_SOUND_UDA1341 is not set
+# CONFIG_SOUND_ASSABET_UDA1341 is not set
+# CONFIG_SOUND_H3600_UDA1341 is not set
+# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
+# CONFIG_SOUND_SA1111_UDA1341 is not set
+# CONFIG_SOUND_SA1100SSP is not set
 # CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+# CONFIG_SOUND_TVMIXER is not set
 
 #
-# USB support
+# Multimedia Capabilities Port drivers
 #
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
 
 #
-# Miscellaneous USB options
+# USB support
 #
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB is not set
 
 #
 # USB Controllers
@@ -626,15 +795,22 @@
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 # CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
 # CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
@@ -652,40 +828,83 @@
 # CONFIG_USB_DC2XX is not set
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
 #
-# CONFIG_USB_DABUSB is not set
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
 
 #
 # USB Network adaptors
 #
-# CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_NET1080 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_USBNET is not set
 
 #
 # USB port drivers
 #
+# CONFIG_USB_USS720 is not set
 
 #
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
-# USB misc drivers
+# USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 
 #
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_NO_FRAME_POINTER is not set
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
+# CONFIG_NO_PGT_CACHE is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/fortunet linux-2.4.19-pre5/arch/arm/def-configs/fortunet
--- linux-2.4.19-pre4/arch/arm/def-configs/fortunet	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/def-configs/fortunet	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,593 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+CONFIG_ARCH_CLPS711X=y
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+CONFIG_ARCH_FORTUNET=y
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+CONFIG_CPU_ARM720T=y
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+# CONFIG_ARM_THUMB is not set
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FPE_FASTFPE=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+CONFIG_MTD_FORTUNET=y
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+# CONFIG_INET is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET_AUNUDP is not set
+# CONFIG_ECONET_NATIVE is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Synchronous Serial Interface
+#
+# CONFIG_SSI is not set
+# CONFIG_SSI_CLPS711X is not set
+# CONFIG_SSI_JUNO is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+CONFIG_SERIAL_CLPS711X=y
+CONFIG_SERIAL_CLPS711X_CONSOLE=y
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+# CONFIG_DEBUG_LL_SER3 is not set
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/frodo linux-2.4.19-pre5/arch/arm/def-configs/frodo
--- linux-2.4.19-pre4/arch/arm/def-configs/frodo	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/def-configs/frodo	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,618 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1100_FRODO=y
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FPE_FASTFPE=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttySA0,9600 ramdisk_size=4096 root=/dev/ram idebus=33"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=9600
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=16
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=y
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_WAITQ=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/jornada720 linux-2.4.19-pre5/arch/arm/def-configs/jornada720
--- linux-2.4.19-pre4/arch/arm/def-configs/jornada720	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/def-configs/jornada720	Fri Mar 29 14:49:18 2002
@@ -1,11 +1,15 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 CONFIG_ARM=y
 # CONFIG_EISA is not set
 # CONFIG_SBUS is not set
 # CONFIG_MCA is not set
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
 
 #
 # Code maturity level options
@@ -23,24 +27,23 @@
 #
 # System Type
 #
+# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
-# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_SHARK is not set
 
 #
 # Archimedes/A5000 Implementations
 #
-
-#
-# Archimedes/A5000 Implementations (select only ONE)
-#
 # CONFIG_ARCH_ARC is not set
 # CONFIG_ARCH_A5K is not set
 
@@ -58,12 +61,18 @@
 #
 # CONFIG_SA1100_ASSABET is not set
 # CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
 # CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_BITSY is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
 # CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
 # CONFIG_SA1100_FREEBIRD is not set
 # CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
 CONFIG_SA1100_JORNADA720=y
 # CONFIG_SA1100_HUW_WEBPANEL is not set
 # CONFIG_SA1100_ITSY is not set
@@ -72,70 +81,75 @@
 # CONFIG_SA1100_OMNIMETER is not set
 # CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_PFS168 is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_XP860 is not set
 # CONFIG_SA1100_YOPY is not set
 CONFIG_SA1111=y
+CONFIG_FORCE_MAX_ZONEORDER=9
 # CONFIG_SA1100_USB is not set
 # CONFIG_SA1100_USB_NETLINK is not set
 # CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_SA1100_FREQUENCY_SCALE is not set
-# CONFIG_SA1100_VOLTAGE_SCALE is not set
+# CONFIG_REGISTERS is not set
 
 #
 # CLPS711X/EP721X Implementations
 #
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
 # CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
 # CONFIG_ARCH_ACORN is not set
 # CONFIG_FOOTBRIDGE is not set
 # CONFIG_FOOTBRIDGE_HOST is not set
 # CONFIG_FOOTBRIDGE_ADDIN is not set
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
-
-#
-# Processor Type
-#
 # CONFIG_CPU_32v3 is not set
 CONFIG_CPU_32v4=y
 # CONFIG_CPU_ARM610 is not set
 # CONFIG_CPU_ARM710 is not set
 # CONFIG_CPU_ARM720T is not set
 # CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
 # CONFIG_CPU_SA110 is not set
 CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
 CONFIG_DISCONTIGMEM=y
 
 #
 # General setup
 #
-
-#
-# Please ensure that you have read the help on the next option
-#
-# CONFIG_ANGELBOOT is not set
 # CONFIG_PCI is not set
-# CONFIG_ISA is not set
+CONFIG_ISA=y
 # CONFIG_ISA_DMA is not set
+# CONFIG_CPU_FREQ is not set
 CONFIG_HOTPLUG=y
 
 #
 # PCMCIA/CardBus support
 #
 CONFIG_PCMCIA=y
+# CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
 # CONFIG_PCMCIA_CLPS6700 is not set
 CONFIG_PCMCIA_SA1100=y
+# CONFIG_MERCURY_BACKPAQ is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_FASTFPE is not set
+CONFIG_FPE_FASTFPE=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=m
@@ -145,10 +159,8 @@
 # CONFIG_APM is not set
 # CONFIG_ARTHUR is not set
 CONFIG_CMDLINE="keepinitrd"
-# CONFIG_PFS168_CMDLINE is not set
 # CONFIG_LEDS is not set
-# CONFIG_ALIGNMENT_TRAP is not set
-# CONFIG_UCB1200 is not set
+CONFIG_ALIGNMENT_TRAP=y
 
 #
 # Parallel port support
@@ -159,63 +171,72 @@
 # Memory Technology Devices (MTD)
 #
 CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# RAM/ROM Device Drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_BOOTLDR_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
 
 #
-# Linearly Mapped Flash Device Drivers
+# RAM/ROM/Flash chip drivers
 #
 CONFIG_MTD_CFI=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 # CONFIG_MTD_AMDSTD is not set
 # CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_SBC_MEDIAGX is not set
-# CONFIG_MTD_ELAN_104NC is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
 CONFIG_MTD_SA1100=y
+# CONFIG_MTD_H3600_BACKPAQ is not set
 # CONFIG_MTD_DC21285 is not set
 # CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_CSTM_CFI_JEDEC is not set
-# CONFIG_MTD_JEDEC is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
 
 #
-# NAND Flash Device Drivers
+# Self-contained MTD device drivers
 #
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_SPIA is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
 
 #
-# User Modules And Translation Layers
+# NAND Flash Device Drivers
 #
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
+# CONFIG_MTD_NAND is not set
 
 #
 # Plug and Play configuration
@@ -246,6 +267,7 @@
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
 # CONFIG_BLK_DEV_LVM is not set
 
 #
@@ -258,7 +280,7 @@
 # CONFIG_NETLINK_DEV is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
-# CONFIG_FILTER is not set
+CONFIG_FILTER=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -282,10 +304,7 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-
-#
-#
-#
+# CONFIG_VLAN_8021Q is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
@@ -318,7 +337,6 @@
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_ETHERTAP is not set
-# CONFIG_NET_SB1000 is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -329,18 +347,44 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
 
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+CONFIG_WAVELAN=m
+CONFIG_ARLAN=m
+CONFIG_AIRONET4500=m
+CONFIG_AIRONET4500_NONCS=m
+# CONFIG_AIRONET4500_PNP is not set
+# CONFIG_AIRONET4500_PCI is not set
+# CONFIG_AIRONET4500_ISA is not set
+# CONFIG_AIRONET4500_I365 is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices
@@ -366,11 +410,11 @@
 CONFIG_PCMCIA_NMCLAN=m
 CONFIG_PCMCIA_SMC91C92=m
 CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_PCMCIA_AXNET is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR is not set
 CONFIG_NET_PCMCIA_RADIO=y
 # CONFIG_PCMCIA_RAYCS is not set
-# CONFIG_PCMCIA_HERMES is not set
 # CONFIG_PCMCIA_NETWAVE is not set
 CONFIG_PCMCIA_WAVELAN=m
 CONFIG_AIRONET4500_CS=m
@@ -384,10 +428,6 @@
 # IrDA (infrared) support
 #
 CONFIG_IRDA=m
-
-#
-# IrDA protocols
-#
 CONFIG_IRLAN=m
 # CONFIG_IRNET is not set
 CONFIG_IRCOMM=m
@@ -397,28 +437,19 @@
 #
 # Infrared-port device drivers
 #
-
-#
-# SIR device drivers
-#
 # CONFIG_IRTTY_SIR is not set
 # CONFIG_IRPORT_SIR is not set
-
-#
-# FIR device drivers
-#
+# CONFIG_DONGLE is not set
+# CONFIG_USB_IRDA is not set
 # CONFIG_NSC_FIR is not set
 # CONFIG_WINBOND_FIR is not set
 # CONFIG_TOSHIBA_FIR is not set
 # CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
 CONFIG_SA1100_FIR=m
 
 #
-# Dongle support
-#
-# CONFIG_DONGLE is not set
-
-#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=m
@@ -427,10 +458,6 @@
 # IDE, ATA and ATAPI Block devices
 #
 CONFIG_BLK_DEV_IDE=m
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=m
@@ -445,14 +472,10 @@
 # CONFIG_BLK_DEV_COMMERIAL is not set
 # CONFIG_BLK_DEV_TIVO is not set
 CONFIG_BLK_DEV_IDECS=m
-# CONFIG_BLK_DEV_IDECD is not set
+CONFIG_BLK_DEV_IDECD=m
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
@@ -460,6 +483,9 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
 
 #
 # SCSI support
@@ -483,7 +509,13 @@
 #
 # Input core support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
+# CONFIG_INPUT_KEYBDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Character devices
@@ -493,19 +525,37 @@
 CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SA1100_DEFAULT_BAUDRATE=115200
-# CONFIG_TOUCHSCREEN_UCB1200 is not set
-# CONFIG_TOUCHSCREEN_BITSY is not set
-CONFIG_PROFILER=m
-# CONFIG_PFS168_SPI is not set
-# CONFIG_PFS168_DTMF is not set
-# CONFIG_PFS168_MISC is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_NEWTONKBD is not set
 
 #
 # I2C support
@@ -513,6 +563,15 @@
 # CONFIG_I2C is not set
 
 #
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
@@ -524,11 +583,33 @@
 #
 # Joysticks
 #
-# CONFIG_JOYSTICK is not set
-
-#
-# Input core support is needed for joysticks
-#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -553,12 +634,13 @@
 #
 # PCMCIA character devices
 #
-CONFIG_PCMCIA_SERIAL_CS=m
+# CONFIG_PCMCIA_SERIAL_CS is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_V4L2_DEV is not set
 
 #
 # File systems
@@ -568,37 +650,45 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-CONFIG_CRAMFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=2
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+CONFIG_DEVFS_DEBUG=y
+# CONFIG_DRIVERFS_FS is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
@@ -608,6 +698,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
@@ -616,8 +707,7 @@
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
@@ -627,59 +717,22 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_UTF8 is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
 
 #
 # Console drivers
 #
 CONFIG_PC_KEYMAP=y
 # CONFIG_VGA_CONSOLE is not set
-CONFIG_FB=y
 
 #
 # Frame-buffer support
@@ -687,16 +740,17 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_SA1100 is not set
 CONFIG_FB_EPSON1356=y
 # CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_SA1100 is not set
 # CONFIG_FB_VIRTUAL 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_CFB8 is not set
 CONFIG_FBCON_CFB16=y
 # CONFIG_FBCON_CFB24 is not set
 # CONFIG_FBCON_CFB32 is not set
@@ -721,10 +775,10 @@
 # Sound
 #
 CONFIG_SOUND=m
-CONFIG_SOUND_UDA1341=m
-# CONFIG_SOUND_SA1100_SSP is not set
+# CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -733,28 +787,121 @@
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
 # CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_SA1100=m
+# CONFIG_SOUND_UDA1341 is not set
+# CONFIG_SOUND_ASSABET_UDA1341 is not set
+# CONFIG_SOUND_H3600_UDA1341 is not set
+# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
+# CONFIG_SOUND_SA1111_UDA1341 is not set
+# CONFIG_SOUND_SA1100SSP is not set
 # CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_WAVEARTIST is not set
 # CONFIG_SOUND_TVMIXER is not set
 
 #
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_NO_FRAME_POINTER is not set
-CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_DC21285_PORT is not set
 # CONFIG_DEBUG_CLPS711X_UART2 is not set
+# CONFIG_DEBUG_LL_SER3 is not set
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/shannon linux-2.4.19-pre5/arch/arm/def-configs/shannon
--- linux-2.4.19-pre4/arch/arm/def-configs/shannon	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/def-configs/shannon	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,737 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_OBSOLETE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+CONFIG_SA1100_SHANNON=y
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+
+#
+# Processor Type
+#
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttySA0,9600 console=tty1 root=/dev/mtdblock2 init=/linuxrc"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_IQ80310 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=y
+# CONFIG_PCMCIA_NMCLAN is not set
+CONFIG_PCMCIA_SMC91C92=y
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_NET_PCMCIA_RADIO is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=9600
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+
+#
+# Other L3 adapters
+#
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_SERIO is not set
+
+#
+# Joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+CONFIG_SA1100_WATCHDOG=y
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_CMS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_FREEVXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_SA1100=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_SA1100=y
+# CONFIG_SOUND_SA1100SSP is not set
+# CONFIG_SOUND_OSS is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+CONFIG_MCP=y
+CONFIG_MCP_SA1100=y
+CONFIG_MCP_UCB1200=y
+CONFIG_MCP_UCB1200_AUDIO=y
+CONFIG_MCP_UCB1200_TS=y
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+
+#
+# USB Device Class drivers
+#
+
+#
+# USB Human Interface Devices (HID)
+#
+
+#
+# USB Imaging devices
+#
+
+#
+# USB Multimedia devices
+#
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+
+#
+# USB Miscellaneous drivers
+#
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_LL=y
diff -urN linux-2.4.19-pre4/arch/arm/def-configs/system3 linux-2.4.19-pre5/arch/arm/def-configs/system3
--- linux-2.4.19-pre4/arch/arm/def-configs/system3	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/def-configs/system3	Fri Mar 29 14:49:18 2002
@@ -0,0 +1,977 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1100_PT_SYSTEM3=y
+CONFIG_SA1111=y
+CONFIG_FORCE_MAX_ZONEORDER=9
+CONFIG_SA1100_USB=m
+CONFIG_SA1100_USB_NETLINK=m
+CONFIG_SA1100_USB_CHAR=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+
+#
+# Processor Type
+#
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+CONFIG_PCMCIA_SA1100=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="noinitrd root=/dev/mtdblock3"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_BOOTLDR_PARTS=m
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_WD80x3 is not set
+# CONFIG_ULTRAMCA is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRA32 is not set
+CONFIG_SMC9194=m
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=m
+# CONFIG_PCMCIA_NMCLAN is not set
+CONFIG_PCMCIA_SMC91C92=m
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+# CONFIG_NET_PCMCIA_RADIO is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+# CONFIG_IRNET is not set
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+# CONFIG_IRDA_OPTIONS is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_SA1100_FIR=m
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+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_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=38400
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_SA1100_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+CONFIG_USB_OHCI_SA1111=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+CONFIG_USB_USBNET=m
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_WAITQ=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff -urN linux-2.4.19-pre4/arch/arm/kernel/Makefile linux-2.4.19-pre5/arch/arm/kernel/Makefile
--- linux-2.4.19-pre4/arch/arm/kernel/Makefile	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/Makefile	Fri Mar 29 14:49:18 2002
@@ -42,7 +42,8 @@
 
 no-irq-arch	:= $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \
 		   $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \
-		   $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT)
+		   $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \
+		   $(CONFIG_ARCH_MX1ADS)
 
 ifneq ($(findstring y,$(no-irq-arch)),y)
   obj-y		+= irq-arch.o
diff -urN linux-2.4.19-pre4/arch/arm/kernel/armksyms.c linux-2.4.19-pre5/arch/arm/kernel/armksyms.c
--- linux-2.4.19-pre4/arch/arm/kernel/armksyms.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/armksyms.c	Fri Mar 29 14:49:18 2002
@@ -77,12 +77,12 @@
 extern void __do_softirq(void);
 
 #define EXPORT_SYMBOL_ALIAS(sym,orig)		\
- const char __kstrtab_##sym##[]			\
+ const char __kstrtab_##sym[]			\
   __attribute__((section(".kstrtab"))) =	\
     __MODULE_STRING(sym);			\
  const struct module_symbol __ksymtab_##sym	\
   __attribute__((section("__ksymtab"))) =	\
-    { (unsigned long)&##orig, __kstrtab_##sym };
+    { (unsigned long)&orig, __kstrtab_##sym };
 
 /*
  * floating point math emulator support.
@@ -115,7 +115,9 @@
 EXPORT_SYMBOL(system_rev);
 EXPORT_SYMBOL(system_serial_low);
 EXPORT_SYMBOL(system_serial_high);
+#ifdef CONFIG_DEBUG_BUGVERBOSE
 EXPORT_SYMBOL(__bug);
+#endif
 EXPORT_SYMBOL(__bad_xchg);
 EXPORT_SYMBOL(__readwrite_bug);
 EXPORT_SYMBOL(enable_irq);
@@ -229,6 +231,7 @@
 EXPORT_SYMBOL_NOVERS(__udivmoddi4);
 EXPORT_SYMBOL_NOVERS(__udivsi3);
 EXPORT_SYMBOL_NOVERS(__umodsi3);
+EXPORT_SYMBOL_NOVERS(abort);
 
 	/* bitops */
 EXPORT_SYMBOL(set_bit);
diff -urN linux-2.4.19-pre4/arch/arm/kernel/bios32.c linux-2.4.19-pre5/arch/arm/kernel/bios32.c
--- linux-2.4.19-pre4/arch/arm/kernel/bios32.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/bios32.c	Fri Mar 29 14:49:18 2002
@@ -153,8 +153,7 @@
 }
 
 /*
- * PCI IDE controllers use non-standard I/O port
- * decoding, respect it.
+ * PCI IDE controllers use non-standard I/O port decoding, respect it.
  */
 static void __init pci_fixup_ide_bases(struct pci_dev *dev)
 {
@@ -181,9 +180,82 @@
 	pci_write_config_dword(dev, 0x40, 0x80000000);
 }
 
+/*
+ * The CY82C693 needs some rather major fixups to ensure that it does
+ * the right thing.  Idea from the Alpha people, with a few additions.
+ *
+ * We ensure that the IDE base registers are set to 1f0/3f4 for the
+ * primary bus, and 170/374 for the secondary bus.  Also, hide them
+ * from the PCI subsystem view as well so we won't try to perform
+ * our own auto-configuration on them.
+ *
+ * In addition, we ensure that the PCI IDE interrupts are routed to
+ * IRQ 14 and IRQ 15 respectively.
+ *
+ * The above gets us to a point where the IDE on this device is
+ * functional.  However, The CY82C693U _does not work_ in bus
+ * master mode without locking the PCI bus solid.
+ */
+static void __init pci_fixup_cy82c693(struct pci_dev *dev)
+{
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		u32 base0, base1;
+
+		if (dev->class & 0x80) {	/* primary */
+			base0 = 0x1f0;
+			base1 = 0x3f4;
+		} else {			/* secondary */
+			base0 = 0x170;
+			base1 = 0x374;
+		}
+
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+				       base0 | PCI_BASE_ADDRESS_SPACE_IO);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
+				       base1 | PCI_BASE_ADDRESS_SPACE_IO);
+
+		dev->resource[0].start = 0;
+		dev->resource[0].end   = 0;
+		dev->resource[0].flags = 0;
+
+		dev->resource[1].start = 0;
+		dev->resource[1].end   = 0;
+		dev->resource[1].flags = 0;
+	} else if (PCI_FUNC(dev->devfn) == 0) {
+		/*
+		 * Setup IDE IRQ routing.
+		 */
+		pci_write_config_byte(dev, 0x4b, 14);
+		pci_write_config_byte(dev, 0x4c, 15);
+
+		/*
+		 * Disable FREQACK handshake, enable USB.
+		 */
+		pci_write_config_byte(dev, 0x4d, 0x41);
+
+		/*
+		 * Enable PCI retry, and PCI post-write buffer.
+		 */
+		pci_write_config_byte(dev, 0x44, 0x17);
+
+		/*
+		 * Enable ISA master and DMA post write buffering.
+		 */
+		pci_write_config_byte(dev, 0x45, 0x03);
+	}
+}
+
 struct pci_fixup pcibios_fixups[] = {
 	{
 		PCI_FIXUP_HEADER,
+		PCI_VENDOR_ID_CONTAQ,	PCI_DEVICE_ID_CONTAQ_82C693,
+		pci_fixup_cy82c693
+	}, {
+		PCI_FIXUP_HEADER,
+		PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_21142,
+		pci_fixup_dec21142
+	}, {
+		PCI_FIXUP_HEADER,
 		PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_21285,
 		pci_fixup_dec21285
 	}, {
@@ -198,10 +270,6 @@
 		PCI_FIXUP_HEADER,
 		PCI_ANY_ID,		PCI_ANY_ID,
 		pci_fixup_ide_bases
-	}, {
-		PCI_FIXUP_HEADER,
-		PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_21142,
-		pci_fixup_dec21142
 	}, { 0 }
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/kernel/calls.S linux-2.4.19-pre5/arch/arm/kernel/calls.S
--- linux-2.4.19-pre4/arch/arm/kernel/calls.S	Fri Mar 29 14:48:53 2002
+++ linux-2.4.19-pre5/arch/arm/kernel/calls.S	Fri Mar 29 14:49:19 2002
@@ -236,8 +236,27 @@
 		.long	SYMBOL_NAME(sys_mincore)
 /* 220 */	.long	SYMBOL_NAME(sys_madvise)
 		.long	SYMBOL_NAME(sys_fcntl64)
+		.long	SYMBOL_NAME(sys_ni_syscall) /* TUX */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* Security */
 		.long	SYMBOL_NAME(sys_gettid)
+/* 225 */	.long	SYMBOL_NAME(sys_readahead)
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_setxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_lsetxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_fsetxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_getxattr */
+/* 230 */	.long	SYMBOL_NAME(sys_ni_syscall) /* sys_lgetxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_fgetxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_listxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_llistxattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_flistxattr */
+/* 235 */	.long	SYMBOL_NAME(sys_ni_syscall) /* sys_removexattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_lremovexattr */
+		.long	SYMBOL_NAME(sys_ni_syscall) /* sys_fremovexattr */
 		.long	SYMBOL_NAME(sys_tkill)
+		/*
+		 * Please check 2.5 _before_ adding calls here,
+		 * and copy changes to rmk@arm.linux.org.uk.  Thanks.
+		 */
 __syscall_end:
 
 		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
diff -urN linux-2.4.19-pre4/arch/arm/kernel/compat.c linux-2.4.19-pre5/arch/arm/kernel/compat.c
--- linux-2.4.19-pre4/arch/arm/kernel/compat.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/compat.c	Fri Mar 29 14:49:19 2002
@@ -89,10 +89,12 @@
 	}
 
 #ifdef CONFIG_FOOTBRIDGE
-	tag = tag_next(tag);
-	tag->hdr.tag = ATAG_MEMCLK;
-	tag->hdr.size = tag_size(tag_memclk);
-	tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285;
+	if (params->u1.s.mem_fclk_21285) {
+		tag = tag_next(tag);
+		tag->hdr.tag = ATAG_MEMCLK;
+		tag->hdr.size = tag_size(tag_memclk);
+		tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285;
+	}
 #endif
 
 #ifdef CONFIG_ARCH_ACORN
diff -urN linux-2.4.19-pre4/arch/arm/kernel/debug-armv.S linux-2.4.19-pre5/arch/arm/kernel/debug-armv.S
--- linux-2.4.19-pre4/arch/arm/kernel/debug-armv.S	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/debug-armv.S	Fri Mar 29 14:49:19 2002
@@ -164,28 +164,49 @@
 		.endm
 
 #elif defined(CONFIG_ARCH_SA1100)
+
 		.macro	addruart,rx
 		mrc	p15, 0, \rx, c1, c0
 		tst	\rx, #1			@ MMU enabled?
 		moveq	\rx, #0x80000000	@ physical base address
 		movne	\rx, #0xf8000000	@ virtual address
-		@add	\rx, \rx, #0x00050000	@ Ser3
-		add	\rx, \rx, #0x00010000	@ Ser1
+
+		@ We probe for the active serial port here, coherently with
+		@ the comment in include/asm-arm/arch-sa1100/uncompress.h.
+		@ We assume r1 can be clobbered.
+
+		@ see if Ser3 is active
+		add	\rx, \rx, #0x00050000
+		ldr	r1, [\rx, #UTCR3]
+		tst	r1, #UTCR3_TXE
+
+		@ if Ser3 is inactive, then try Ser1
+		addeq	\rx, \rx, #(0x00010000 - 0x00050000)
+		ldreq	r1, [\rx, #UTCR3]
+		tsteq	r1, #UTCR3_TXE
+
+		@ if Ser1 is inactive, then try Ser2
+		addeq	\rx, \rx, #(0x00030000 - 0x00010000)
+		ldreq	r1, [\rx, #UTCR3]
+		tsteq	r1, #UTCR3_TXE
+
+		@ if all ports are inactive, then there is nothing we can do
+		moveq	pc, lr
 		.endm
 
 		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0x14]	@ UTDR
+		str	\rd, [\rx, #UTDR]
 		.endm
 
 		.macro	waituart,rd,rx
-1001:		ldr	\rd, [\rx, #0x20]	@ UTSR1
-		tst	\rd, #1 << 2		@ UTSR1_TNF
+1001:		ldr	\rd, [\rx, #UTSR1]
+		tst	\rd, #UTSR1_TNF
 		beq	1001b
 		.endm
 
 		.macro	busyuart,rd,rx
-1001:		ldr	\rd, [\rx, #0x20]	@ UTSR1
-		tst	\rd, #1 << 0		@ UTSR1_TBY
+1001:		ldr	\rd, [\rx, #UTSR1]
+		tst	\rd, #UTSR1_TBY
 		bne	1001b
 		.endm
 
diff -urN linux-2.4.19-pre4/arch/arm/kernel/dma-arc.c linux-2.4.19-pre5/arch/arm/kernel/dma-arc.c
--- linux-2.4.19-pre4/arch/arm/kernel/dma-arc.c	Wed Jul  4 14:56:44 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/dma-arc.c	Fri Mar 29 14:49:19 2002
@@ -96,7 +96,7 @@
 	/* 10/1/1999 DAG - Presume whether there is an outstanding command? */
 	extern unsigned int fdc1772_fdc_int_done;
 
-	* Explicit! If the int done is 0 then 1 int to go */
+	/* Explicit! If the int done is 0 then 1 int to go */
 	return (fdc1772_fdc_int_done==0)?1:0;
 }
 
diff -urN linux-2.4.19-pre4/arch/arm/kernel/dma.c linux-2.4.19-pre5/arch/arm/kernel/dma.c
--- linux-2.4.19-pre4/arch/arm/kernel/dma.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/dma.c	Fri Mar 29 14:49:19 2002
@@ -275,6 +275,8 @@
 
 #endif
 
+EXPORT_SYMBOL(request_dma);
+EXPORT_SYMBOL(free_dma);
 EXPORT_SYMBOL(enable_dma);
 EXPORT_SYMBOL(disable_dma);
 EXPORT_SYMBOL(set_dma_addr);
diff -urN linux-2.4.19-pre4/arch/arm/kernel/entry-armv.S linux-2.4.19-pre5/arch/arm/kernel/entry-armv.S
--- linux-2.4.19-pre4/arch/arm/kernel/entry-armv.S	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/entry-armv.S	Fri Mar 29 14:49:19 2002
@@ -454,6 +454,31 @@
 		.macro	irq_prio_table
 		.endm
 
+#elif defined(CONFIG_ARCH_MX1ADS)
+
+		.macro	disable_fiq
+		.endm
+#define AITC_NIVECSR   0x40
+		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+		ldr	\irqstat, =IO_ADDRESS(MX1ADS_AITC_BASE)
+		@ Load offset & priority of the highest priority
+		@ interrupt pending.
+		ldr	\irqnr, [\irqstat, #AITC_NIVECSR]
+		@ Shift off the priority leaving the offset or
+		@ "interrupt number"
+		mov	\irqnr, \irqnr, lsr #16
+ 		ldr	\irqstat, =1	@ dummy compare
+		ldr	\base, =0xFFFF		// invalid interrupt
+		cmp	\irqnr, \base
+		bne	1001f
+		ldr	\irqstat, =0
+1001:
+		tst	\irqstat, #1	@ to make the condition code = TRUE
+		.endm
+
+		.macro	irq_prio_table
+		.endm
+
 #elif defined(CONFIG_ARCH_CLPS711X)
 
 #include <asm/hardware/clps7111.h>
@@ -643,14 +668,14 @@
 		mrs	r9, cpsr			@ Enable interrupts if they were
 		tst	r3, #I_BIT
 		biceq	r9, r9, #I_BIT			@ previously
-		mov	r0, r2
+		mov	r0, r2				@ *** remove once everyones in sync
 /*
  * This routine must not corrupt r9
  */
 #ifdef MULTI_CPU
-		ldr	r2, .LCprocfns			@ pass r0, r3 to
+		ldr	r4, .LCprocfns			@ pass r0, r3 to
 		mov	lr, pc				@ processor code
-		ldr	pc, [r2]			@ call processor specific code
+		ldr	pc, [r4]			@ call processor specific code
 #else
 		bl	cpu_data_abort
 #endif
@@ -747,15 +772,16 @@
 		stmia	sp, {r0 - r12}			@ save r0 - r12
 		ldr	r7, .LCabt
 		add	r5, sp, #S_PC
-		ldmia	r7, {r0, r3, r4}		@ Get USR pc, cpsr
-		stmia	r5, {r0, r3, r4}		@ Save USR pc, cpsr, old_r0
+		ldmia	r7, {r2 - r4}			@ Get USR pc, cpsr
+		stmia	r5, {r2 - r4}			@ Save USR pc, cpsr, old_r0
 		stmdb	r5, {sp, lr}^
 		alignment_trap r7, r7, __temp_abt
 		zero_fp
+		mov	r0, r2				@ remove once everyones in sync
 #ifdef MULTI_CPU
-		ldr	r2, .LCprocfns			@ pass r0, r3 to
+		ldr	r4, .LCprocfns			@ pass r0, r3 to
 		mov	lr, pc				@ processor code
-		ldr	pc, [r2]			@ call processor specific code
+		ldr	pc, [r4]			@ call processor specific code
 #else
 		bl	cpu_data_abort
 #endif
diff -urN linux-2.4.19-pre4/arch/arm/kernel/init_task.c linux-2.4.19-pre5/arch/arm/kernel/init_task.c
--- linux-2.4.19-pre4/arch/arm/kernel/init_task.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/init_task.c	Fri Mar 29 14:49:19 2002
@@ -9,7 +9,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
diff -urN linux-2.4.19-pre4/arch/arm/kernel/process.c linux-2.4.19-pre5/arch/arm/kernel/process.c
--- linux-2.4.19-pre4/arch/arm/kernel/process.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/process.c	Fri Mar 29 14:49:19 2002
@@ -24,9 +24,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
-#include <asm/io.h>
 #include <asm/leds.h>
+#include <asm/system.h>
 #include <asm/uaccess.h>
 
 /*
diff -urN linux-2.4.19-pre4/arch/arm/kernel/semaphore.c linux-2.4.19-pre5/arch/arm/kernel/semaphore.c
--- linux-2.4.19-pre4/arch/arm/kernel/semaphore.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre5/arch/arm/kernel/semaphore.c	Fri Mar 29 14:49:19 2002
@@ -210,7 +210,6 @@
 	mov	r0, ip
 	bl	__up
 	ldmfd	sp!, {r0 - r3, pc}^
-
 	");
 
 #else
@@ -248,7 +247,6 @@
 	mov	r0, ip
 	bl	__up
 	ldmfd	sp!, {r0 - r3, pc}
-
 	");
 
 #endif
diff -urN linux-2.4.19-pre4/arch/arm/kernel/signal.c linux-2.4.19-pre5/arch/arm/kernel/signal.c
--- linux-2.4.19-pre4/arch/arm/kernel/signal.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/arm/kernel/signal.c	Fri Mar 29 14:49:19 2002
@@ -344,7 +344,7 @@
 	/*
 	 * This is the X/Open sanctioned signal stack switching.
 	 */
-	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp))
+	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
 		sp = current->sas_ss_sp + current->sas_ss_size;
 
 	/*
@@ -637,7 +637,10 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre4/arch/arm/kernel/traps.c linux-2.4.19-pre5/arch/arm/kernel/traps.c
--- linux-2.4.19-pre4/arch/arm/kernel/traps.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/kernel/traps.c	Fri Mar 29 14:49:19 2002
@@ -25,8 +25,6 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
-#include <asm/atomic.h>
-#include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -53,7 +51,7 @@
  */
 static int verify_stack(unsigned long sp)
 {
-	if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory)
+	if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0))
 		return -EFAULT;
 
 	return 0;
@@ -62,13 +60,15 @@
 /*
  * Dump out the contents of some memory nicely...
  */
-void dump_mem(unsigned long bottom, unsigned long top)
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
 {
 	unsigned long p = bottom & ~31;
 	int i;
 
+	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+
 	for (p = bottom & ~31; p < top;) {
-		printk("%08lx: ", p);
+		printk("%04lx: ", p & 0xffff);
 
 		for (i = 0; i < 8; i++, p += 4) {
 			unsigned int val;
@@ -79,21 +79,11 @@
 				__get_user(val, (unsigned long *)p);
 				printk("%08x ", val);
 			}
-			if (i == 3)
-				printk(" ");
 		}
 		printk ("\n");
 	}
 }
 
-/*
- * These constants are for searching for possible module text
- * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
 static void dump_instr(struct pt_regs *regs)
 {
 	unsigned long addr = instruction_pointer(regs);
@@ -102,7 +92,7 @@
 	int i;
 
 	printk("Code: ");
-	for (i = -2; i < 3; i++) {
+	for (i = -4; i < 1; i++) {
 		unsigned int val, bad;
 
 		if (thumb)
@@ -122,8 +112,7 @@
 
 static void dump_stack(struct task_struct *tsk, unsigned long sp)
 {
-	printk("Stack:\n");
-	dump_mem(sp - 16, 8192+(unsigned long)tsk);
+	dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk);
 }
 
 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
@@ -289,10 +278,9 @@
 		handler[reason], processor_modes[proc_mode]);
 
 	/*
-	 * We need to switch to kernel mode so that we can
-	 * use __get_user to safely read from kernel space.
-	 * Note that we now dump the code first, just in case
-	 * the backtrace kills us.
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
 	 */
 	fs = get_fs();
 	set_fs(KERNEL_DS);
@@ -301,10 +289,8 @@
 	 * Dump out the vectors and stub routines.  Maybe a better solution
 	 * would be to dump them out only if we detect that they are corrupted.
 	 */
-	printk(KERN_CRIT "Vectors:\n");
-	dump_mem(vectors, 0x40);
-	printk(KERN_CRIT "Stubs:\n");
-	dump_mem(vectors + 0x200, 0x4b8);
+	dump_mem(KERN_CRIT "Vectors: ", vectors, vectors + 0x40);
+	dump_mem(KERN_CRIT "Stubs: ", vectors + 0x200, vectors + 0x4b8);
 
 	set_fs(fs);
 
@@ -528,11 +514,6 @@
 
 void abort(void)
 {
-	void *lr = __builtin_return_address(0);
-
-	printk(KERN_CRIT "abort() called from %p!  (Please "
-	       "report to rmk@arm.linux.org.uk)\n", lr);
-
 	BUG();
 
 	/* if that doesn't kill us, halt */
diff -urN linux-2.4.19-pre4/arch/arm/lib/ecard.S linux-2.4.19-pre5/arch/arm/lib/ecard.S
--- linux-2.4.19-pre4/arch/arm/lib/ecard.S	Mon Nov 27 17:07:59 2000
+++ linux-2.4.19-pre5/arch/arm/lib/ecard.S	Fri Mar 29 14:49:19 2002
@@ -12,7 +12,7 @@
 #include <asm/assembler.h>
 #include <asm/hardware.h>
 
-#if defined(CONFIG_CPU_26)
+#ifdef CONFIG_CPU_26
 #define CPSR2SPSR(rt)
 #else
 #define CPSR2SPSR(rt) \
diff -urN linux-2.4.19-pre4/arch/arm/lib/getuser.S linux-2.4.19-pre5/arch/arm/lib/getuser.S
--- linux-2.4.19-pre4/arch/arm/lib/getuser.S	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/lib/getuser.S	Fri Mar 29 14:49:19 2002
@@ -80,8 +80,9 @@
 
 	/* fall through */
 
-__get_user_bad:
+__get_user_bad_8:
 	mov	r2, #0
+__get_user_bad:
 	mov	r1, #0
 	mov	r0, #-14
 	mov	pc, lr
@@ -91,6 +92,6 @@
 	.long	2b, __get_user_bad
 	.long	3b, __get_user_bad
 	.long	4b, __get_user_bad
-	.long	5b, __get_user_bad
-	.long	6b, __get_user_bad
+	.long	5b, __get_user_bad_8
+	.long	6b, __get_user_bad_8
 .previous
diff -urN linux-2.4.19-pre4/arch/arm/lib/io-acorn.S linux-2.4.19-pre5/arch/arm/lib/io-acorn.S
--- linux-2.4.19-pre4/arch/arm/lib/io-acorn.S	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/lib/io-acorn.S	Fri Mar 29 14:49:19 2002
@@ -58,7 +58,7 @@
 @ Proto  : void memc_write(int register, int value);
 @ Returns: nothing
 
-#if defined(CONFIG_CPU_26)
+#ifdef CONFIG_CPU_26
 ENTRY(memc_write)
 		cmp	r0, #7
 		RETINSTR(movgt,pc,lr)
diff -urN linux-2.4.19-pre4/arch/arm/lib/io-shark.c linux-2.4.19-pre5/arch/arm/lib/io-shark.c
--- linux-2.4.19-pre4/arch/arm/lib/io-shark.c	Thu Apr 12 12:20:31 2001
+++ linux-2.4.19-pre5/arch/arm/lib/io-shark.c	Fri Mar 29 14:49:19 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/lib/io-shark.c
  *
- *  by Alexander Schulz <aschulz@netwinder.org>
+ *  by Alexander Schulz
  *
  * derived from:
  * linux/arch/arm/lib/io-ebsa.S
diff -urN linux-2.4.19-pre4/arch/arm/lib/strrchr.S linux-2.4.19-pre5/arch/arm/lib/strrchr.S
--- linux-2.4.19-pre4/arch/arm/lib/strrchr.S	Mon Sep 18 15:15:25 2000
+++ linux-2.4.19-pre5/arch/arm/lib/strrchr.S	Fri Mar 29 14:49:19 2002
@@ -18,7 +18,7 @@
 		mov	r3, #0
 1:		ldrb	r2, [r0], #1
 		teq	r2, r1
-		moveq	r3, r0
+		subeq	r3, r0, #1
 		teq	r2, #0
 		bne	1b
 		mov	r0, r3
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/Makefile linux-2.4.19-pre5/arch/arm/mach-clps711x/Makefile
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/Makefile	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,30 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET		:= clps711x.o
+
+# Object file lists.
+
+obj-y			:= irq.o mm.o time.o
+obj-m			:=
+obj-n			:=
+obj-			:=
+
+export-objs		:= leds-p720t.o
+
+obj-$(CONFIG_ARCH_AUTCPU12) += autcpu12.o
+obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o
+obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
+obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o
+obj-$(CONFIG_ARCH_P720T) += p720t.o
+obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o
+leds-$(CONFIG_ARCH_P720T) += p720t-leds.o
+obj-$(CONFIG_LEDS)	+= $(leds-y)
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/autcpu12.c linux-2.4.19-pre5/arch/arm/mach-clps711x/autcpu12.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/autcpu12.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/autcpu12.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,72 @@
+/*
+ *  linux/arch/arm/mach-clps711x/autcpu12.c
+ *
+ * (c) 2001 Thomas Gleixner, autronix automation <gleixner@autronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/hardware.h>
+#include <asm/sizes.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/arch/autcpu12.h>
+
+extern void clps711x_map_io(void);
+extern void clps711x_init_irq(void);
+
+/*
+ * The on-chip registers are given a size of 1MB so that a section can
+ * be used to map them; this saves a page table.  This is the place to
+ * add mappings for ROM, expansion memory, PCMCIA, etc.  (if static
+ * mappings are chosen for those areas).
+ *
+*/
+
+static struct map_desc autcpu12_io_desc[] __initdata = {
+ /* virtual, physical, length, domain, r, w, c, b */
+ /* memory-mapped extra io and CS8900A Ethernet chip */
+ /* ethernet chip */
+ 	{ AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 1, 1, 0, 0 },
+	
+ 	LAST_DESC
+};
+
+void __init autcpu12_map_io(void)
+{
+        clps711x_map_io();
+        iotable_init(autcpu12_io_desc);
+}
+
+MACHINE_START(AUTCPU12, "autronix autcpu12")
+	MAINTAINER("Thomas Gleixner")
+        BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
+	BOOT_PARAMS(0xc0020000)
+	MAPIO(autcpu12_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/cdb89712.c linux-2.4.19-pre5/arch/arm/mach-clps711x/cdb89712.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/cdb89712.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/cdb89712.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,74 @@
+/*
+ *  linux/arch/arm/mach-clps711x/cdb89712.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+extern void clps711x_init_irq(void);
+extern void clps711x_map_io(void);
+
+/*
+ * Map the CS89712 Ethernet port.  That should be moved to the
+ * ethernet driver, perhaps.
+ */
+static struct map_desc cdb89712_io_desc[] __initdata = {
+	{ ETHER_BASE, ETHER_START, ETHER_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
+	LAST_DESC
+};
+
+static void __init
+fixup_cdb89712(struct machine_desc *desc, struct param_struct *params,
+	    char **cmdline, struct meminfo *mi)
+{
+}
+
+static void __init cdb89712_map_io(void)
+{
+	clps711x_map_io();
+	iotable_init(cdb89712_io_desc);
+}
+
+MACHINE_START(CDB89712, "Cirrus-CDB89712")
+	MAINTAINER("Ray Lehtiniemi")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_cdb89712)
+	MAPIO(cdb89712_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
+
+static int cdb89712_hw_init(void)
+{
+	return 0;
+}
+
+__initcall(cdb89712_hw_init);
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/clep7312.c linux-2.4.19-pre5/arch/arm/mach-clps711x/clep7312.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/clep7312.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/clep7312.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,49 @@
+/*
+ *  linux/arch/arm/mach-clps711x/clep7312.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+extern void clps711x_init_irq(void);
+extern void clps711x_map_io(void); 
+
+static void __init
+fixup_clep7312(struct machine_desc *desc, struct param_struct *params,
+	    char **cmdline, struct meminfo *mi)
+{
+	mi->nr_banks=1;
+	mi->end = 0xc0FFFFFF;
+	mi->bank[0].start = 0xc0000000;
+	mi->bank[0].size = 0x01000000;
+	mi->bank[0].node = 0;
+}
+
+
+MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
+	MAINTAINER("Nobody")
+        BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_clep7312)
+	MAPIO(clps711x_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/dma.c linux-2.4.19-pre5/arch/arm/mach-clps711x/dma.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/dma.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,35 @@
+/*
+ *  linux/arch/arm/mach-clps711x/dma.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/dma.h>
+
+void __init arch_dma_init(dma_t *dma)
+{
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/edb7211-arch.c linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-arch.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/edb7211-arch.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-arch.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,59 @@
+/*
+ *  linux/arch/arm/mach-clps711x/arch-edb7211.c
+ *
+ *  Copyright (C) 2000, 2001 Blue Mug, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+extern void clps711x_init_irq(void);
+extern void edb7211_map_io(void);
+
+static void __init
+fixup_edb7211(struct machine_desc *desc, struct param_struct *params,
+	      char **cmdline, struct meminfo *mi)
+{
+	/*
+	 * Bank start addresses are not present in the information
+	 * passed in from the boot loader.  We could potentially
+	 * detect them, but instead we hard-code them.
+	 *
+	 * Banks sizes _are_ present in the param block, but we're
+	 * not using that information yet.
+	 */
+	mi->bank[0].start = 0xc0000000;
+	mi->bank[0].size = 8*1024*1024;
+	mi->bank[0].node = 0;
+	mi->bank[1].start = 0xc1000000;
+	mi->bank[1].size = 8*1024*1024;
+	mi->bank[1].node = 1;
+	mi->nr_banks = 2;
+}
+
+MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
+	MAINTAINER("Jon McClintock")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
+	BOOT_PARAMS(0xc0020100)	/* 0xc0000000 - 0xc001ffff can be video RAM */
+	FIXUP(fixup_edb7211)
+	MAPIO(edb7211_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/edb7211-mm.c linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-mm.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/edb7211-mm.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/edb7211-mm.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,74 @@
+/*
+ *  linux/arch/arm/mach-clps711x/mm.c
+ *
+ *  Extra MM routines for the EDB7211 board
+ *
+ *  Copyright (C) 2000, 2001 Blue Mug, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+ 
+#include <asm/mach/map.h>
+
+#define MB1 1048576	/* one megabyte == size of an MMU section */
+
+extern void clps711x_map_io(void);
+
+/*
+ * The on-chip registers are given a size of 1MB so that a section can
+ * be used to map them; this saves a page table.  This is the place to
+ * add mappings for ROM, expansion memory, PCMCIA, etc.  (if static
+ * mappings are chosen for those areas).
+ *
+ * Here is a physical memory map (to be fleshed out later):
+ *
+ * Physical Address  Size  Description
+ * ----------------- ----- ---------------------------------
+ * c0000000-c001ffff 128KB reserved for video RAM [1]
+ * c0020000-c0023fff  16KB parameters (see Documentation/arm/Setup)
+ * c0024000-c0027fff  16KB swapper_pg_dir (task 0 page directory)
+ * c0028000-...            kernel image (TEXTADDR)
+ *
+ * [1] Unused pages should be given back to the VM; they are not yet.
+ *     The parameter block should also be released (not sure if this
+ *     happens).
+ */
+static struct map_desc edb7211_io_desc[] __initdata = {
+ /* virtual, physical, length, domain, r, w, c, b */
+
+ /* memory-mapped extra keyboard row and CS8900A Ethernet chip */
+ { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 1, 1, 0, 0 }, 
+ { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 1, 1, 0, 0 },
+
+ /* flash banks */
+ { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 },
+ { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 },
+
+ LAST_DESC
+};
+
+void __init edb7211_map_io(void)
+{
+        clps711x_map_io();
+        iotable_init(edb7211_io_desc);
+}
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/fortunet.c linux-2.4.19-pre5/arch/arm/mach-clps711x/fortunet.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/fortunet.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/fortunet.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,81 @@
+/*
+ *  linux/arch/arm/mach-clps711x/fortunet.c
+ *
+ *  Derived from linux/arch/arm/mach-integrator/arch.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/amba_kmi.h>
+
+extern void clps711x_map_io(void);
+extern void clps711x_init_irq(void);
+
+struct meminfo memmap = { 1, 0xC1000000, {{0xC0000000,0x01000000,0}}};
+
+typedef struct tag_IMAGE_PARAMS
+{
+	int	ramdisk_ok;
+	int	ramdisk_address;
+	int	ramdisk_size;
+	int	ram_size;
+	int	extra_param_type;
+	int	extra_param_ptr;
+	int	command_line;
+} IMAGE_PARAMS;
+
+#define IMAGE_PARAMS_PHYS	0xC01F0000
+
+static void __init
+fortunet_fixup(struct machine_desc *desc, struct param_struct *params,
+		 char **cmdline, struct meminfo *mi)
+{
+	IMAGE_PARAMS *ip;
+	ip = (IMAGE_PARAMS *)__phys_to_virt(IMAGE_PARAMS_PHYS);
+	*cmdline = (char *)__phys_to_virt(ip->command_line);
+#ifdef CONFIG_BLK_DEV_INITRD
+	if(ip->ramdisk_ok)
+	{
+		initrd_start = __phys_to_virt(ip->ramdisk_address);
+		initrd_end = initrd_start + ip->ramdisk_size;
+	}
+#endif
+	memmap.bank[0].size = ip->ram_size;
+	memmap.end = ip->ram_size+0xC0000000;
+	*mi = memmap;
+}
+
+MACHINE_START(FORTUNET, "ARM-FortuNet")
+	MAINTAINER("FortuNet Inc.")
+        BOOT_MEM(0xc0000000, 0x80000000, 0xf0000000)
+	BOOT_PARAMS(0x00000000)
+	FIXUP(fortunet_fixup)
+	MAPIO(clps711x_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/irq.c linux-2.4.19-pre5/arch/arm/mach-clps711x/irq.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/irq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/irq.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,138 @@
+/*
+ *  linux/arch/arm/mach-clps711x/irq.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+
+#include <asm/mach/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/hardware/clps7111.h>
+
+static void mask_irq_int1(unsigned int irq)
+{
+	u32 intmr1;
+
+	intmr1 = clps_readl(INTMR1);
+	intmr1 &= ~(1 << irq);
+	clps_writel(intmr1, INTMR1);
+}
+
+static void mask_ack_irq_int1(unsigned int irq)
+{
+	u32 intmr1;
+
+	intmr1 = clps_readl(INTMR1);
+	intmr1 &= ~(1 << irq);
+	clps_writel(intmr1, INTMR1);
+
+	switch (irq) {
+	case IRQ_CSINT:  clps_writel(0, COEOI);  break;
+	case IRQ_TC1OI:  clps_writel(0, TC1EOI); break;
+	case IRQ_TC2OI:  clps_writel(0, TC2EOI); break;
+	case IRQ_RTCMI:  clps_writel(0, RTCEOI); break;
+	case IRQ_TINT:   clps_writel(0, TEOI);   break;
+	case IRQ_UMSINT: clps_writel(0, UMSEOI); break;
+	}
+}
+
+static void unmask_irq_int1(unsigned int irq)
+{
+	u32 intmr1;
+
+	intmr1 = clps_readl(INTMR1);
+	intmr1 |= 1 << irq;
+	clps_writel(intmr1, INTMR1);
+}
+
+static void mask_irq_int2(unsigned int irq)
+{
+	u32 intmr2;
+
+	intmr2 = clps_readl(INTMR2);
+	intmr2 &= ~(1 << (irq - 16));
+	clps_writel(intmr2, INTMR2);
+}
+
+static void mask_ack_irq_int2(unsigned int irq)
+{
+	u32 intmr2;
+
+	intmr2 = clps_readl(INTMR2);
+	intmr2 &= ~(1 << (irq - 16));
+	clps_writel(intmr2, INTMR2);
+
+	switch (irq) {
+	case IRQ_KBDINT: clps_writel(0, KBDEOI); break;
+	}
+}
+
+static void unmask_irq_int2(unsigned int irq)
+{
+	u32 intmr2;
+
+	intmr2 = clps_readl(INTMR2);
+	intmr2 |= 1 << (irq - 16);
+	clps_writel(intmr2, INTMR2);
+}
+
+void __init clps711x_init_irq(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < NR_IRQS; i++) {
+	        if (INT1_IRQS & (1 << i)) {
+		        irq_desc[i].valid	= 1;
+			irq_desc[i].probe_ok	= 1;
+			irq_desc[i].mask_ack	= (INT1_ACK_IRQS & (1 << i)) ?
+						   mask_ack_irq_int1 :
+						   mask_irq_int1;
+			irq_desc[i].mask	= mask_irq_int1;
+			irq_desc[i].unmask	= unmask_irq_int1;
+		}
+		if (INT2_IRQS & (1 << i)) {
+		        irq_desc[i].valid	= 1;
+			irq_desc[i].probe_ok	= 1;
+			irq_desc[i].mask_ack	= (INT2_ACK_IRQS & (1 << i)) ?
+						   mask_ack_irq_int2 :
+						   mask_irq_int2;
+			irq_desc[i].mask	= mask_irq_int2;
+			irq_desc[i].unmask	= unmask_irq_int2;
+		}			
+	}
+
+	/*
+	 * Disable interrupts
+	 */
+	clps_writel(0, INTMR1);
+	clps_writel(0, INTMR2);
+
+	/*
+	 * Clear down any pending interrupts
+	 */
+	clps_writel(0, COEOI);
+	clps_writel(0, TC1EOI);
+	clps_writel(0, TC2EOI);
+	clps_writel(0, RTCEOI);
+	clps_writel(0, TEOI);
+	clps_writel(0, UMSEOI);
+	clps_writel(0, SYNCIO);
+	clps_writel(0, KBDEOI);
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/mm.c linux-2.4.19-pre5/arch/arm/mach-clps711x/mm.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/mm.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/mm.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,70 @@
+/*
+ *  linux/arch/arm/mach-clps711x/mm.c
+ *
+ *  Generic MM setup for the CLPS711x-based machines.
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/bootmem.h>
+
+#include <asm/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/clps7111.h>
+
+#if 0 //def CONFIG_DISCONTIGMEM
+  
+/*
+ * The assumption of maximum 4 discontiguous memory banks is present
+ * in several places in the ARM kernel, including the parameter block
+ * (this affects boot loaders, too).  Banks do not necessarily
+ * correspond 1:1 with NUMA nodes, although they usually will,
+ * especially if they are widely discontiguous.
+ *
+ *  - note that the parameter block is depreciated for new implementations
+ *  - also note that discontig_node_data is actually used
+ *    -- rmk 
+ */
+
+static bootmem_data_t node_bootmem_data[4];
+
+pg_data_t clps711x_node_data[4] = {
+        { bdata: &node_bootmem_data[0] },
+        { bdata: &node_bootmem_data[1] },
+        { bdata: &node_bootmem_data[2] },
+        { bdata: &node_bootmem_data[3] },
+};
+
+#endif
+
+/*
+ * This maps the generic CLPS711x registers
+ */
+static struct map_desc clps711x_io_desc[] __initdata = {
+ { CLPS7111_VIRT_BASE,	CLPS7111_PHYS_BASE,	1048576, DOMAIN_IO, 0, 1 },
+ LAST_DESC
+};
+
+void __init clps711x_map_io(void)
+{
+	iotable_init(clps711x_io_desc);
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/p720t-leds.c linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t-leds.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/p720t-leds.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t-leds.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,67 @@
+/*
+ *  linux/arch/arm/mach-clps711x/leds.c
+ *
+ *  Integrator LED control routines
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/clps7111.h>
+#include <asm/hardware/ep7212.h>
+
+static void p720t_leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+	u32 pddr;
+
+	local_irq_save(flags);
+	switch(ledevt) {
+	case led_idle_start:
+		break;
+
+	case led_idle_end:
+		break;
+
+	case led_timer:
+		pddr = clps_readb(PDDR);
+		clps_writeb(pddr ^ 1, PDDR);
+		break;
+
+	default:
+		break;
+	}
+
+	local_irq_restore(flags);
+}
+
+static int __init leds_init(void)
+{
+	if (machine_is_p720t())
+		leds_event = p720t_leds_event;
+
+	return 0;
+}
+
+__initcall(leds_init);
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/p720t.c linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/p720t.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/p720t.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,118 @@
+/*
+ *  linux/arch/arm/mach-clps711x/p720t.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/syspld.h>
+
+extern void clps711x_init_irq(void);
+extern void clps711x_map_io(void);
+
+/*
+ * Map the P720T system PLD.  It occupies two address spaces:
+ *  SYSPLD_PHYS_BASE and SYSPLD_PHYS_BASE + 0x00400000
+ * We map both here.
+ */
+static struct map_desc p720t_io_desc[] __initdata = {
+	{ SYSPLD_VIRT_BASE,	SYSPLD_PHYS_BASE, 1048576, DOMAIN_IO, 0, 1 },
+	{ 0xfe400000,		0x10400000,	  1048576, DOMAIN_IO, 0, 1 },
+	LAST_DESC
+};
+
+static void __init
+fixup_p720t(struct machine_desc *desc, struct param_struct *params,
+	    char **cmdline, struct meminfo *mi)
+{
+	struct tag *tag = (struct tag *)params;
+
+	/*
+	 * Our bootloader doesn't setup any tags (yet).
+	 */
+	if (tag->hdr.tag != ATAG_CORE) {
+		tag->hdr.tag = ATAG_CORE;
+		tag->hdr.size = tag_size(tag_core);
+		tag->u.core.flags = 0;
+		tag->u.core.pagesize = PAGE_SIZE;
+		tag->u.core.rootdev = 0x0100;
+
+		tag = tag_next(tag);
+		tag->hdr.tag = ATAG_MEM;
+		tag->hdr.size = tag_size(tag_mem32);
+		tag->u.mem.size = 4096;
+		tag->u.mem.start = PHYS_OFFSET;
+
+		tag = tag_next(tag);
+		tag->hdr.tag = ATAG_NONE;
+		tag->hdr.size = 0;
+	}
+}
+
+static void __init p720t_map_io(void)
+{
+	clps711x_map_io();
+	iotable_init(p720t_io_desc);
+}
+
+MACHINE_START(P720T, "ARM-Prospector720T")
+	MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_p720t)
+	MAPIO(p720t_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
+
+static int p720t_hw_init(void)
+{
+	/*
+	 * Power down as much as possible in case we don't
+	 * have the drivers loaded.
+	 */
+	PLD_LCDEN = 0;
+	PLD_PWR  &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
+
+	PLD_KBD   = 0;
+	PLD_IO    = 0;
+	PLD_IRDA  = 0;
+	PLD_CODEC = 0;
+	PLD_TCH   = 0;
+	PLD_SPI   = 0;
+#ifndef CONFIG_DEBUG_LL
+	PLD_COM2  = 0;
+	PLD_COM1  = 0;
+#endif
+
+	return 0;
+}
+
+__initcall(p720t_hw_init);
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-clps711x/time.c linux-2.4.19-pre5/arch/arm/mach-clps711x/time.c
--- linux-2.4.19-pre4/arch/arm/mach-clps711x/time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-clps711x/time.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,54 @@
+/*
+ *  linux/arch/arm/mach-clps711x/time.c
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/clps7111.h>
+
+extern unsigned long (*gettimeoffset)(void);
+
+/*
+ * gettimeoffset() returns time since last timer tick, in usecs.
+ *
+ * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+ * 'tick' is usecs per jiffy.
+ */
+static unsigned long clps711x_gettimeoffset(void)
+{
+	unsigned long hwticks;
+	hwticks = LATCH - (clps_readl(TC2D) & 0xffff);	/* since last underflow */
+	return (hwticks * tick) / LATCH;
+}
+
+void __init clps711x_setup_timer(void)
+{
+	unsigned int syscon;
+
+	gettimeoffset = clps711x_gettimeoffset;
+
+	syscon = clps_readl(SYSCON1);
+	syscon |= SYSCON1_TC2S | SYSCON1_TC2M;
+	clps_writel(syscon, SYSCON1);
+
+	clps_writel(LATCH-1, TC2D); /* 512kHz / 100Hz - 1 */
+
+	xtime.tv_sec = clps_readl(RTCDR);
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-ebsa110/io.c linux-2.4.19-pre5/arch/arm/mach-ebsa110/io.c
--- linux-2.4.19-pre4/arch/arm/mach-ebsa110/io.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-ebsa110/io.c	Fri Mar 29 14:49:19 2002
@@ -139,7 +139,11 @@
 	 ((p) >> 3) == (0x2f8 >> 3) || \
 	 ((p) >> 3) == (0x378 >> 3))
 
-u8 __inb(int port)
+/*
+ * We're addressing an 8 or 16-bit peripheral which tranfers
+ * odd addresses on the low ISA byte lane.
+ */
+u8 __inb8(unsigned int port)
 {
 	u32 ret;
 
@@ -162,7 +166,11 @@
 	return ret;
 }
 
-u16 __inw(int port)
+/*
+ * We're addressing a 16-bit peripheral which transfers odd
+ * addresses on the high ISA byte lane.
+ */
+u8 __inb16(unsigned int port)
 {
 	u32 ret;
 
@@ -170,13 +178,33 @@
 	 * The SuperIO registers use sane addressing techniques...
 	 */
 	if (SUPERIO_PORT(port))
-		ret = __arch_getw(ISAIO_BASE + (port << 2));
+		ret = __arch_getb(ISAIO_BASE + (port << 2));
 	else {
 		u32 a = ISAIO_BASE + ((port & ~1) << 1);
 
 		/*
 		 * Shame nothing else does
 		 */
+		ret = __arch_getb(a + (port & 1));
+	}
+	return ret;
+}
+
+u16 __inw(unsigned int port)
+{
+	u32 ret;
+
+	/*
+	 * The SuperIO registers use sane addressing techniques...
+	 */
+	if (SUPERIO_PORT(port) || port & 1)
+		ret = __arch_getw(ISAIO_BASE + (port << 2));
+	else {
+		u32 a = ISAIO_BASE + (port << 1);
+
+		/*
+		 * Shame nothing else does
+		 */
 		if (port & 1)
 			BUG();
 
@@ -185,17 +213,27 @@
 	return ret;
 }
 
-u32 __inl(int port)
+/*
+ * Fake a 32-bit read with two 16-bit reads.  Needed for 3c589.
+ */
+u32 __inl(unsigned int port)
 {
-	BUG();
-	return 0;
+	u32 a;
+
+	if (SUPERIO_PORT(port) || port & 3)
+		BUG();
+
+	a = ISAIO_BASE + (port << 1);
+
+	return __arch_getw(a) | __arch_getw(a + 4) << 16;
 }
 
-EXPORT_SYMBOL(__inb);
+EXPORT_SYMBOL(__inb8);
+EXPORT_SYMBOL(__inb16);
 EXPORT_SYMBOL(__inw);
 EXPORT_SYMBOL(__inl);
 
-void __outb(u8 val, int port)
+void __outb8(u8 val, unsigned int port)
 {
 	/*
 	 * The SuperIO registers use sane addressing techniques...
@@ -215,7 +253,24 @@
 	}
 }
 
-void __outw(u16 val, int port)
+void __outb16(u8 val, unsigned int port)
+{
+	/*
+	 * The SuperIO registers use sane addressing techniques...
+	 */
+	if (SUPERIO_PORT(port))
+		__arch_putb(val, ISAIO_BASE + (port << 2));
+	else {
+		u32 a = ISAIO_BASE + ((port & ~1) << 1);
+
+		/*
+		 * Shame nothing else does
+		 */
+		__arch_putb(val, a + (port & 1));
+	}
+}
+
+void __outw(u16 val, unsigned int port)
 {
 	u32 off;
 
@@ -225,7 +280,7 @@
 	if (SUPERIO_PORT(port))
 		off = port << 2;
 	else {
-		off = (port & ~1) << 1;
+		off = port << 1;
 		if (port & 1)
 			BUG();
 
@@ -233,12 +288,13 @@
 	__arch_putw(val, ISAIO_BASE + off);
 }
 
-void __outl(u32 val, int port)
+void __outl(u32 val, unsigned int port)
 {
 	BUG();
 }
 
-EXPORT_SYMBOL(__outb);
+EXPORT_SYMBOL(__outb8);
+EXPORT_SYMBOL(__outb16);
 EXPORT_SYMBOL(__outw);
 EXPORT_SYMBOL(__outl);
 
@@ -315,12 +371,29 @@
 EXPORT_SYMBOL(outsw);
 EXPORT_SYMBOL(insw);
 
+/*
+ * We implement these as 16-bit insw/outsw, mainly for
+ * 3c589 cards.
+ */
 void outsl(unsigned int port, const void *from, int len)
 {
-	panic("outsl not supported on this architecture");
+	u32 off = port << 1;
+
+	if (SUPERIO_PORT(port) || port & 3)
+		BUG();
+
+	__raw_writesw(ISAIO_BASE + off, from, len << 1);
 }
 
 void insl(unsigned int port, void *from, int len)
 {
-	panic("insl not supported on this architecture");
+	u32 off = port << 1;
+
+	if (SUPERIO_PORT(port) || port & 3)
+		BUG();
+
+	__raw_readsw(ISAIO_BASE + off, from, len << 1);
 }
+
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insl);
diff -urN linux-2.4.19-pre4/arch/arm/mach-epxa10db/arch.c linux-2.4.19-pre5/arch/arm/mach-epxa10db/arch.c
--- linux-2.4.19-pre4/arch/arm/mach-epxa10db/arch.c	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/mach-epxa10db/arch.c	Fri Mar 29 14:49:19 2002
@@ -18,7 +18,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
diff -urN linux-2.4.19-pre4/arch/arm/mach-epxa10db/mm.c linux-2.4.19-pre5/arch/arm/mach-epxa10db/mm.c
--- linux-2.4.19-pre4/arch/arm/mach-epxa10db/mm.c	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/mach-epxa10db/mm.c	Fri Mar 29 14:49:19 2002
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/sizes.h>
  
 #include <asm/mach/map.h>
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-integrator/pci_v3.c linux-2.4.19-pre5/arch/arm/mach-integrator/pci_v3.c
--- linux-2.4.19-pre4/arch/arm/mach-integrator/pci_v3.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-integrator/pci_v3.c	Fri Mar 29 14:49:19 2002
@@ -20,6 +20,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -411,12 +412,19 @@
 	flags:	IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
-void __init pci_v3_setup_resources(struct resource **resource)
+int __init pci_v3_setup_resources(struct resource **resource)
 {
-	if (request_resource(&iomem_resource, &non_mem))
-		printk("PCI: unable to allocate non-prefetchable memory region\n");
-	if (request_resource(&iomem_resource, &pre_mem))
-		printk("PCI: unable to allocate prefetchable memory region\n");
+	if (request_resource(&iomem_resource, &non_mem)) {
+		printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
+		       "memory region\n");
+		return -EBUSY;
+	}
+	if (request_resource(&iomem_resource, &pre_mem)) {
+		release_resource(&non_mem);
+		printk(KERN_ERR "PCI: unable to allocate prefetchable "
+		       "memory region\n");
+		return -EBUSY;
+	}
 
 	/*
 	 * bus->resource[0] is the IO resource for this bus
@@ -426,6 +434,8 @@
 	resource[0] = &ioport_resource;
 	resource[1] = &non_mem;
 	resource[2] = &pre_mem;
+
+	return 1;
 }
 
 /*
@@ -433,18 +443,23 @@
  * means I can't get additional information on the reason for the pm2fb
  * problems.  I suppose I'll just have to mind-meld with the machine. ;)
  */
-#define SC_PCI     (IO_ADDRESS(INTEGRATOR_SC_PCIENABLE))
-#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE+0x20))
-#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE+0x24))
+#define SC_PCI     (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET)
+#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20)
+#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24)
 
 static int v3_fault(unsigned long addr, struct pt_regs *regs)
 {
 	unsigned long pc = instruction_pointer(regs);
 	unsigned long instr = *(unsigned long *)pc;
+#if 0
+	char buf[128];
 
-	printk("V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
+	sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
 		addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
 		v3_readb(V3_LB_ISTAT));
+	printk(KERN_DEBUG "%s", buf);
+	printascii(buf);
+#endif
 
 	v3_writeb(V3_LB_ISTAT, 0);
 	__raw_writel(3, SC_PCI);
@@ -467,11 +482,20 @@
 		return 0;
 	}
 
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+		return 0;
+	}
+
 	return 1;
 }
 
 static void v3_irq(int irq, void *devid, struct pt_regs *regs)
 {
+#ifdef CONFIG_DEBUG_LL
 	unsigned long pc = instruction_pointer(regs);
 	unsigned long instr = *(unsigned long *)pc;
 	char buf[128];
@@ -480,10 +504,13 @@
 		pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
 		v3_readb(V3_LB_ISTAT));
 	printascii(buf);
+#endif
 
+	v3_writew(V3_PCI_STAT, 0xf000);
 	v3_writeb(V3_LB_ISTAT, 0);
 	__raw_writel(3, SC_PCI);
 
+#ifdef CONFIG_DEBUG_LL
 	/*
 	 * If the instruction being executed was a read,
 	 * make it look like it read all-ones.
@@ -493,17 +520,9 @@
 		sprintf(buf, "   reg%d = %08lx\n", reg, regs->uregs[reg]);
 		printascii(buf);
 	}
+#endif
 }
 
-static struct irqaction v3_int = {
-	name: "V3",
-	handler: v3_irq,
-};
-static struct irqaction v3_int2 = {
-	name: "V3TM",
-	handler: v3_irq,
-};
-
 extern int (*external_fault)(unsigned long addr, struct pt_regs *regs);
 
 /*
@@ -514,6 +533,8 @@
 {
 	unsigned int pci_cmd;
 	unsigned long flags;
+	unsigned int temp;
+	int ret;
 
 	/*
 	 * Hook in our fault handler for PCI errors
@@ -523,6 +544,12 @@
 	spin_lock_irqsave(&v3_lock, flags);
 
 	/*
+	 * Unlock V3 registers, but only if they were previously locked.
+	 */
+	if (v3_readw(V3_SYSTEM) & V3_SYSTEM_M_LOCK)
+		v3_writew(V3_SYSTEM, 0xa05f);
+
+	/*
 	 * Setup window 0 - PCI non-prefetchable memory
 	 *  Local: 0x40000000 Bus: 0x00000000 Size: 256MB
 	 */
@@ -548,6 +575,45 @@
 			V3_LB_BASE_ENABLE);
 	v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0));
 
+	/*
+	 * Disable PCI to host IO cycles
+	 */
+	temp = v3_readw(V3_PCI_CFG) & ~V3_PCI_CFG_M_I2O_EN;
+	temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS;
+	v3_writew(V3_PCI_CFG, temp);
+
+	printk(KERN_DEBUG "FIFO_CFG: %04x  FIFO_PRIO: %04x\n",
+		v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY));
+
+	/*
+	 * Set the V3 FIFO such that writes have higher priority than
+	 * reads, and local bus write causes local bus read fifo flush.
+	 * Same for PCI.
+	 */
+	v3_writew(V3_FIFO_PRIORITY, 0x0a0a);
+
+	/*
+	 * Re-lock the system register.
+	 */
+	temp = v3_readw(V3_SYSTEM) | V3_SYSTEM_M_LOCK;
+	v3_writew(V3_SYSTEM, temp);
+
+	/*
+	 * Clear any error conditions, and enable write errors.
+	 */
+	v3_writeb(V3_LB_ISTAT, 0);
+	v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10));
+	v3_writeb(V3_LB_IMASK, 0x28);
+	__raw_writel(3, SC_PCI);
+
+	/*
+	 * Grab the PCI error interrupt.
+	 */
+	ret = request_irq(IRQ_V3INT, v3_irq, 0, "V3 error", NULL);
+	if (ret)
+		printk(KERN_ERR "PCI: unable to grab PCI error "
+		       "interrupt: %d\n", ret);
+
 	spin_unlock_irqrestore(&v3_lock, flags);
 
 	pci_scan_bus(0, &pci_v3_ops, sysdata);
@@ -557,18 +623,13 @@
 
 	v3_writew(V3_PCI_CMD, pci_cmd);
 
-	/*
-	 * Clear any error conditions.
-	 */
-	__raw_writel(3, SC_PCI);
-	v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10));
-	v3_writeb(V3_LB_ISTAT, 0);
+	v3_writeb(V3_LB_ISTAT, ~0x40);
 	v3_writeb(V3_LB_IMASK, 0x68);
 
-	printk("LB_CFG: %04x LB_ISTAT: %02x LB_IMASK: %02x\n",
-		v3_readw(V3_LB_CFG),
-		v3_readb(V3_LB_ISTAT),
-		v3_readb(V3_LB_IMASK));
-	setup_arm_irq(IRQ_V3INT, &v3_int);
-//	setup_arm_irq(IRQ_LBUSTIMEOUT, &v3_int2);
+#if 0
+	ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
+	if (ret)
+		printk(KERN_ERR "PCI: unable to grab local bus timeout ".
+		       "interrupt: %d\n", ret);
+#endif
 }
diff -urN linux-2.4.19-pre4/arch/arm/mach-mx1ads/Makefile linux-2.4.19-pre5/arch/arm/mach-mx1ads/Makefile
--- linux-2.4.19-pre4/arch/arm/mach-mx1ads/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/Makefile	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,20 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET		:= mx1ads.o
+
+# Object file lists.
+
+obj-y			:= arch.o cpu.o irq.o mm.o time.o
+obj-m			:=
+obj-n			:=
+obj-			:=
+
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/arch/arm/mach-mx1ads/arch.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/arch.c
--- linux-2.4.19-pre4/arch/arm/mach-mx1ads/arch.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/arch.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,59 @@
+/*
+ *  linux/arch/arm/mach-mx1ads/arch.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/amba_kmi.h>
+
+extern void mx1ads_map_io(void);
+extern void mx1ads_init_irq(void);
+
+
+static void __init
+mx1ads_fixup(struct machine_desc *desc, struct param_struct *unused,
+		 char **cmdline, struct meminfo *mi)
+{
+}
+
+MACHINE_START(MX1ADS, "Motorola MX1ADS")
+	MAINTAINER("Shane Nay")
+#ifdef CONFIG_ARCH_MX1ADS_SRAM
+	BOOT_MEM(0x12000000, 0x00200000, 0xf0200000)
+#else
+	BOOT_MEM(0x08000000, 0x00200000, 0xf0200000)
+#endif
+	FIXUP(mx1ads_fixup)
+	MAPIO(mx1ads_map_io)
+	INITIRQ(mx1ads_init_irq)
+MACHINE_END
+
+#if 0
+
+#endif
diff -urN linux-2.4.19-pre4/arch/arm/mach-mx1ads/cpu.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/cpu.c
--- linux-2.4.19-pre4/arch/arm/mach-mx1ads/cpu.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/cpu.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,34 @@
+/*
+ *  linux/arch/arm/mach-mx1ads/cpu.c
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ *  $Id: cpu.c,v 1.2 2001/09/22 12:11:17 rmk Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * CPU support functions
+ */
+
+/*  FIXME-
+ *  Add support for clock change on the fly.  (Power)
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+
+static int __init cpu_init(void)
+{
+	return 0;
+}
+
+__initcall(cpu_init);
diff -urN linux-2.4.19-pre4/arch/arm/mach-mx1ads/irq.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/irq.c
--- linux-2.4.19-pre4/arch/arm/mach-mx1ads/irq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/irq.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,73 @@
+/*
+ *  linux/arch/arm/mach-mx1ads/irq.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+/*
+ *
+ * We simply use the ENABLE DISABLE registers inside of the MX1
+ * to turn on/off specific interrupts.  FIXME- We should
+ * also add support for the accelerated interrupt controller
+ * by putting offets to irq jump code in the appropriate
+ * places.
+ *
+ */
+
+#define INTENNUM_OFF              0x8
+#define INTDISNUM_OFF             0xC
+
+#define VA_AITC_BASE              IO_ADDRESS(MX1ADS_AITC_BASE)
+#define MX1ADS_AITC_INTDISNUM     (VA_AITC_BASE + INTDISNUM_OFF)
+#define MX1ADS_AITC_INTENNUM      (VA_AITC_BASE + INTENNUM_OFF)
+
+static void
+mx1ads_mask_irq(unsigned int irq)
+{
+	__raw_writel(irq, MX1ADS_AITC_INTDISNUM);
+}
+
+static void
+mx1ads_unmask_irq(unsigned int irq)
+{
+	__raw_writel(irq, MX1ADS_AITC_INTENNUM);
+}
+
+void __init
+mx1ads_init_irq(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].valid = 1;
+		irq_desc[i].probe_ok = 1;
+		irq_desc[i].mask_ack = mx1ads_mask_irq;
+		irq_desc[i].mask = mx1ads_mask_irq;
+		irq_desc[i].unmask = mx1ads_unmask_irq;
+	}
+
+	/* Disable all interrupts initially. */
+	/* In MX1 this is done in the bootloader. */
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-mx1ads/mm.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/mm.c
--- linux-2.4.19-pre4/arch/arm/mach-mx1ads/mm.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/mm.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,45 @@
+/*
+ *  linux/arch/arm/mach-mx1ads/mm.c
+ *
+ *  Copyright (C) 1999,2000 Arm Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+
+
+
+static struct map_desc mx1ads_io_desc[] __initdata = {
+
+  { IO_ADDRESS(MX1ADS_SRAM_BASE),     MX1ADS_SRAM_BASE,      SZ_128K   , DOMAIN_IO, 0, 1},
+  { IO_ADDRESS(MX1ADS_IO_BASE),       MX1ADS_IO_BASE,        SZ_256K   , DOMAIN_IO, 0, 1},
+  LAST_DESC
+};
+
+void __init mx1ads_map_io(void)
+{
+	iotable_init(mx1ads_io_desc);
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-mx1ads/time.c linux-2.4.19-pre5/arch/arm/mach-mx1ads/time.c
--- linux-2.4.19-pre4/arch/arm/mach-mx1ads/time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-mx1ads/time.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,45 @@
+/*
+ *  linux/arch/arm/mach-mx1ads/time.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+
+extern int (*set_rtc)(void);
+
+/* FIXME-
+ * When we have an external RTC part,
+ * put the mapping in for that part.
+ *
+ * The internal RTC within the MX1 is not sufficient
+ * for tracking time other than time of day, or
+ * date over very short periods of time.
+ *
+ */
+
+static int mx1ads_set_rtc(void)
+{
+	return 0;
+}
+
+static int mx1ads_rtc_init(void)
+{
+	xtime.tv_sec = 0;
+
+	set_rtc = mx1ads_set_rtc;
+
+	return 0;
+}
+
+__initcall(mx1ads_rtc_init);
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/Makefile linux-2.4.19-pre5/arch/arm/mach-sa1100/Makefile
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/Makefile	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/Makefile	Fri Mar 29 14:49:19 2002
@@ -9,20 +9,19 @@
 
 O_TARGET		:= sa1100.o
 
-obj-y :=
+# Common support (must be linked before board specific support)
+obj-y := generic.o irq.o dma-sa1100.o
 obj-m :=
 obj-n :=
 obj-  :=
 
-export-objs :=	assabet.o dma-sa1100.o dma-sa1111.o freebird.o generic.o \
-		h3600.o huw_webpanel.o irq.o pcipool.o sa1111-pcibuf.o   \
-		yopy.o
+export-objs :=	assabet.o dma-sa1100.o dma-sa1111.o \
+		flexanet.o freebird.o generic.o h3600.o \
+		huw_webpanel.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \
+		system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o
 
 # These aren't present yet, and prevents a plain -ac kernel building.
-# hwtimer.o usb_ctl.o usb_recv.o usb_send.o
-
-# Common support (must be linked before board specific support)
-obj-y += generic.o irq.o dma-sa1100.o
+# hwtimer.o
 
 # This needs to be cleaned up.  We probably need to have SA1100
 # and SA1110 config symbols.
@@ -31,6 +30,7 @@
 ifeq ($(CONFIG_CPU_FREQ),y)
 obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o
 obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o
+obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o
 obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o
 endif
 
@@ -42,11 +42,13 @@
 obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o
 obj-$(CONFIG_SA1100_ASSABET) += assabet.o
 obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o
+obj-$(CONFIG_SA1100_BADGE4) +=  badge4.o
 obj-$(CONFIG_SA1100_BRUTUS) += brutus.o
 obj-$(CONFIG_SA1100_CERF) += cerf.o
 obj-$(CONFIG_SA1100_EMPEG) += empeg.o
 obj-$(CONFIG_SA1100_FLEXANET) += flexanet.o
 obj-$(CONFIG_SA1100_FREEBIRD) += freebird.o
+obj-$(CONFIG_SA1100_FRODO) += frodo.o
 obj-$(CONFIG_SA1100_GRAPHICSCLIENT) += graphicsclient.o
 obj-$(CONFIG_SA1100_GRAPHICSMASTER) += graphicsmaster.o
 obj-$(CONFIG_SA1100_H3600) += h3600.o
@@ -59,6 +61,8 @@
 obj-$(CONFIG_SA1100_PANGOLIN) += pangolin.o
 obj-$(CONFIG_SA1100_PFS168) += pfs168.o
 obj-$(CONFIG_SA1100_PLEB) += pleb.o
+obj-$(CONFIG_SA1100_PT_SYSTEM3) += system3.o
+obj-$(CONFIG_SA1100_SHANNON) += shannon.o
 obj-$(CONFIG_SA1100_SHERMAN) += sherman.o
 obj-$(CONFIG_SA1100_SIMPAD) += simpad.o
 obj-$(CONFIG_SA1100_VICTOR) += victor.o
@@ -72,14 +76,27 @@
 leds-$(CONFIG_SA1100_BRUTUS) += leds-brutus.o
 leds-$(CONFIG_SA1100_CERF) += leds-cerf.o
 leds-$(CONFIG_SA1100_FLEXANET) += leds-flexanet.o
+leds-$(CONFIG_SA1100_FRODO) += leds-frodo.o
 leds-$(CONFIG_SA1100_GRAPHICSCLIENT) += leds-graphicsclient.o
 leds-$(CONFIG_SA1100_GRAPHICSMASTER) += leds-graphicsmaster.o
 leds-$(CONFIG_SA1100_LART) += leds-lart.o
 leds-$(CONFIG_SA1100_PFS168) += leds-pfs168.o
 leds-$(CONFIG_SA1100_SIMPAD) += leds-simpad.o  
+leds-$(CONFIG_SA1100_PT_SYSTEM3) += leds-system3.o
 obj-$(CONFIG_LEDS) += $(leds-y)
 
+# SA1110 USB client support
+list-multi += sa1100usb_core.o
+sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o
+obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o
+obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o
+obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o
+
 # Miscelaneous functions
 obj-$(CONFIG_PM) += pm.o sleep.o
 
 include $(TOPDIR)/Rules.make
+
+sa1100usb_core.o: $(sa1100usb_core-objs)
+	$(LD) -r -o $@ $(sa1100usb_core-objs)
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/adsbitsy.c linux-2.4.19-pre5/arch/arm/mach-sa1100/adsbitsy.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/adsbitsy.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/adsbitsy.c	Fri Mar 29 14:49:19 2002
@@ -53,7 +53,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	ret = sa1111_probe();
+	ret = sa1111_probe(ADSBITSY_SA1111_BASE);
 	if (ret < 0)
 		return ret;
 
@@ -94,7 +94,7 @@
 	sa1110_mb_enable();
 
 	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_RISING_EDGE);
-	sa1111_init_irq(SA1100_GPIO_TO_IRQ(0));
+	sa1111_init_irq(IRQ_GPIO0);
 
 	return 0;
 }
@@ -126,8 +126,8 @@
 
 static struct map_desc adsbitsy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
-  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1111 */
+  { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
   LAST_DESC
 };
 
@@ -135,24 +135,15 @@
 {
 	if (port->mapbase == _Ser1UTCR0) {
 		Ser1SDCR0 |= SDCR0_UART;
-		// Set RTS Output and High (should be done in the set_mctrl fn)
-		GPDR |= GPIO_GPIO15;
-		GPCR |= GPIO_GPIO15;
-		// Set CTS Input
-		GPDR &= ~GPIO_GPIO14;
+#error Fixme	// Set RTS High (should be done in the set_mctrl fn)
+		GPCR = GPIO_GPIO15;
 	} else if (port->mapbase == _Ser2UTCR0) {
 		Ser2UTCR4 = Ser2HSCR0 = 0;
-		// Set RTS Output and High (should be done in the set_mctrl fn)
-		GPDR |= GPIO_GPIO17;
-		GPCR |= GPIO_GPIO17;
-		// Set CTS Input
-		GPDR &= ~GPIO_GPIO16;
+#error Fixme	// Set RTS High (should be done in the set_mctrl fn)
+		GPCR = GPIO_GPIO17;
 	} else if (port->mapbase == _Ser2UTCR0) {
-		// Set RTS Output and High (should be done in the set_mctrl fn)
-		GPDR |= GPIO_GPIO19;
-		GPCR |= GPIO_GPIO19;
-		// Set CTS Input
-		GPDR &= ~GPIO_GPIO18;
+#error Fixme	// Set RTS High (should be done in the set_mctrl fn)
+		GPCR = GPIO_GPIO19;
 	}
 	return 0;
 }
@@ -166,10 +157,12 @@
 	sa1100_map_io();
 	iotable_init(adsbitsy_io_desc);
 
-	sa1110_register_uart_fns(&adsbitsy_port_fns);
+	sa1100_register_uart_fns(&adsbitsy_port_fns);
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
 	sa1100_register_uart(2, 2);
+	GPDR |= GPIO_GPIO15 | GPIO_GPIO17 | GPIO_GPIO19;
+	GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO16 | GPIO_GPIO18);
 }
 
 MACHINE_START(ADSBITSY, "ADS Bitsy")
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/assabet.c linux-2.4.19-pre5/arch/arm/mach-sa1100/assabet.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/assabet.c	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/assabet.c	Fri Mar 29 14:49:19 2002
@@ -31,16 +31,48 @@
 
 #include "generic.h"
 
+#define ASSABET_BCR_DB1110 \
+	(ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+	 ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
+	 ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
+	 ASSABET_BCR_IRDA_MD0)
+
+#define ASSABET_BCR_DB1111 \
+	(ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+	 ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
+	 ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
+	 ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
+	 ASSABET_BCR_IRDA_MD0   | ASSABET_BCR_CF_RST)
 
-unsigned long BCR_value = ASSABET_BCR_DB1110;
 unsigned long SCR_value = ASSABET_SCR_INIT;
-EXPORT_SYMBOL(BCR_value);
 EXPORT_SYMBOL(SCR_value);
 
+static unsigned long BCR_value = ASSABET_BCR_DB1110;
+
+void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	BCR_value = (BCR_value & ~mask) | val;
+	ASSABET_BCR = BCR_value;
+	local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(ASSABET_BCR_frob);
+
 
 static int __init assabet_init(void)
 {
-	if (machine_is_assabet() && machine_has_neponset()) {
+	if (!machine_is_assabet())
+		return -EINVAL;
+
+	/*
+	 * Set the IRQ edges
+	 */
+	set_GPIO_IRQ_edge(GPIO_GPIO23, GPIO_RISING_EDGE);	/* UCB1300 */
+
+	if (machine_has_neponset()) {
 		/*
 		 * Angel sets this, but other bootloaders may not.
 		 *
@@ -55,6 +87,7 @@
 			"hasn't been configured in the kernel\n" );
 #endif
 	}
+
 	return 0;
 }
 
@@ -87,18 +120,18 @@
  * repeat it here because the kernel may not be loaded as a zImage, and
  * also because it's a hassle to communicate the SCR value to the kernel
  * from the decompressor.
+ *
+ * Note that IRQs are guaranteed to be disabled.
  */
 static void __init get_assabet_scr(void)
 {
-	unsigned long flags, scr, i;
+	unsigned long scr, i;
 
-	local_irq_save(flags);
 	GPDR |= 0x3fc;			/* Configure GPIO 9:2 as outputs */
 	GPSR = 0x3fc;			/* Write 0xFF to GPIO 9:2 */
 	GPDR &= ~(0x3fc);		/* Configure GPIO 9:2 as inputs */
 	for(i = 100; i--; scr = GPLR);	/* Read GPIO 9:2 */
 	GPDR |= 0x3fc;			/*  restore correct pin direction */
-	local_irq_restore(flags);
 	scr &= 0x3fc;			/* save as system configuration byte. */
 	SCR_value = scr;
 }
@@ -174,9 +207,9 @@
 
 static struct map_desc assabet_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
   /*  f3000000 - neponset system registers */
   /*  f4000000 - neponset SA1111 registers */
   LAST_DESC
@@ -186,19 +219,18 @@
 {
 	if (port->mapbase == _Ser1UTCR0) {
 		if (state)
-			ASSABET_BCR_clear(ASSABET_BCR_RS232EN);
+			ASSABET_BCR_clear(ASSABET_BCR_RS232EN |
+					  ASSABET_BCR_COM_RTS |
+					  ASSABET_BCR_COM_DTR);
 		else
-			ASSABET_BCR_set(ASSABET_BCR_RS232EN);
+			ASSABET_BCR_set(ASSABET_BCR_RS232EN |
+					ASSABET_BCR_COM_RTS |
+					ASSABET_BCR_COM_DTR);
 	}
 }
 
 /*
- * Note! this can be called from IRQ context.
- * FIXME: You _need_ to handle ASSABET_BCR carefully, which doesn't
- * happen at the moment.  Suggest putting interrupt save/restore
- * in ASSABET_BCR_set/clear.
- *
- * NB: Assabet uses COM_RTS and COM_DTR for both UART1 (com port)
+ * Assabet uses COM_RTS and COM_DTR for both UART1 (com port)
  * and UART3 (radio module).  We only handle them for UART1 here.
  */
 static void assabet_set_mctrl(struct uart_port *port, u_int mctrl)
@@ -207,21 +239,21 @@
 		u_int set = 0, clear = 0;
 
 		if (mctrl & TIOCM_RTS)
-			set |= ASSABET_BCR_COM_RTS;
-		else
 			clear |= ASSABET_BCR_COM_RTS;
+		else
+			set |= ASSABET_BCR_COM_RTS;
 
 		if (mctrl & TIOCM_DTR)
-			set |= ASSABET_BCR_COM_DTR;
-		else
 			clear |= ASSABET_BCR_COM_DTR;
+		else
+			set |= ASSABET_BCR_COM_DTR;
 
 		ASSABET_BCR_clear(clear);
 		ASSABET_BCR_set(set);
 	}
 }
 
-static int assabet_get_mctrl(struct uart_port *port)
+static u_int assabet_get_mctrl(struct uart_port *port)
 {
 	u_int ret = 0;
 	u_int bsr = ASSABET_BSR;
@@ -312,11 +344,7 @@
 	PWER = PWER_GPIO0;
 	PGSR = 0;
 	PCFR = 0;
-
-	/*
-	 * Clear all possible wakeup reasons.
-	 */
-	RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
+	PSDR = 0;
 }
 
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/badge4.c linux-2.4.19-pre5/arch/arm/mach-sa1100/badge4.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/badge4.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/badge4.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,213 @@
+/*
+ * linux/arch/arm/mach-sa1100/badge4.c
+ *
+ * BadgePAD 4 specific initialization
+ *
+ *   Tim Connors <connors@hpl.hp.com>
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include "generic.h"
+#include "sa1111.h"
+
+static int __init badge4_sa1111_init(void)
+{
+	int ret;
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state
+	 */
+	sa1110_mb_disable();
+
+	/*
+	 * Probe for SA1111.
+	 */
+	ret = sa1111_probe(BADGE4_SA1111_BASE);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
+	SKPCR |= SKPCR_DCLKEN;
+
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	set_GPIO_IRQ_edge(BADGE4_GPIO_INT_1111, GPIO_RISING_EDGE);
+	sa1111_init_irq(BADGE4_IRQ_GPIO_SA1111);
+
+	return 0;
+}
+
+static int __init badge4_init(void)
+{
+	int ret;
+
+	if (!machine_is_badge4())
+		return -ENODEV;
+
+	ret = badge4_sa1111_init();
+	if (ret < 0)
+		printk(KERN_ERR __FUNCTION__
+		       ": SA-1111 initialization failed (%d)\n", ret);
+
+	/* N.B, according to rmk this is the singular place that GPDR
+           should be set */
+
+	/* Video expansion */
+	GPCR  = (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 |
+		 BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 |
+		 BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 |
+		 BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID |
+		 BADGE4_GPIO_GPC_VID);
+	GPDR |= (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 |
+		 BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 |
+		 BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 |
+		 BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID |
+		 BADGE4_GPIO_GPC_VID);
+
+	/* SDRAM SPD i2c */
+	GPCR  = (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL);
+	GPDR |= (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL);
+
+	/* uart */
+	GPCR  = (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2);
+	GPDR |= (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2);
+
+	/* drives CPLD muxsel0 input */
+	GPCR  = BADGE4_GPIO_MUXSEL0;
+	GPDR |= BADGE4_GPIO_MUXSEL0;
+
+	/* test points */
+	GPCR  = (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 |
+		 BADGE4_GPIO_TESTPT_J5);
+	GPDR |= (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 |
+		 BADGE4_GPIO_TESTPT_J5);
+
+	/* drives CPLD sdram type inputs; this shouldn't be needed;
+           bootloader left it this way. */
+	GPDR |= (BADGE4_GPIO_SDTYP0 | BADGE4_GPIO_SDTYP1);
+
+  	/* 5V supply rail. */
+  	GPCR  = BADGE4_GPIO_PCMEN5V;		/* initially off */
+   	GPDR |= BADGE4_GPIO_PCMEN5V;
+
+	/* drives SA1111 reset pin; this shouldn't be needed;
+           bootloader left it this way. */
+	GPSR  = BADGE4_GPIO_SA1111_NRST;
+	GPDR |= BADGE4_GPIO_SA1111_NRST;
+
+	return 0;
+}
+
+__initcall(badge4_init);
+
+
+static unsigned badge4_5V_bitmap = 0;
+
+void badge4_set_5V(unsigned subsystem, int on)
+{
+	unsigned long flags;
+	unsigned old_5V_bitmap;
+
+	local_irq_save(flags);
+
+	old_5V_bitmap = badge4_5V_bitmap;
+
+	if (on) {
+		badge4_5V_bitmap |= subsystem;
+	} else {
+		badge4_5V_bitmap &= ~subsystem;
+	}
+
+	/* detect on->off and off->on transitions */
+	if ((!old_5V_bitmap) && (badge4_5V_bitmap)) {
+		/* was off, now on */
+		printk(KERN_INFO __FUNCTION__ ": enabling 5V supply rail\n");
+		GPSR = BADGE4_GPIO_PCMEN5V;
+	} else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) {
+		/* was on, now off */
+		printk(KERN_INFO __FUNCTION__ ": disabling 5V supply rail\n");
+		GPCR = BADGE4_GPIO_PCMEN5V;
+	}
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(badge4_set_5V);
+
+
+static void __init
+fixup_badge4(struct machine_desc *desc, struct param_struct *params,
+	    char **cmdline, struct meminfo *mi)
+{
+	/* nothing needed here */
+}
+
+static struct map_desc badge4_io_desc[] __initdata = {
+  /*  virtual    physical    length      domain   r w c b		   */
+  {0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0,1,0,0},/* Flash bank 0 */
+  {0xf1000000, 0x08000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SRAM  bank 1 */
+  {0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SRAM  bank 2 */
+  {0xf4000000, 0x48000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SA-1111      */
+  LAST_DESC
+};
+
+static void __init badge4_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(badge4_io_desc);
+
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1);
+}
+
+MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_badge4)
+	MAPIO(badge4_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/cerf.c linux-2.4.19-pre5/arch/arm/mach-sa1100/cerf.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/cerf.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/cerf.c	Fri Mar 29 14:49:19 2002
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-sa1100/cerf.c
  */
-
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
@@ -16,20 +16,22 @@
 #include "generic.h"
 
 
-static void __init cerf_init_irq (void)
+static void __init cerf_init_irq(void)
 {
-  sa1100_init_irq();
+	sa1100_init_irq();
 
-  /* Need to register these as rising edge interrupts
-   * For standard 16550 serial driver support
-   * Basically - I copied it from pfs168.c :)
-   */
+	/* Need to register these as rising edge interrupts
+	 * For standard 16550 serial driver support
+	 * Basically - I copied it from pfs168.c :)
+	 */
 #ifdef CONFIG_SA1100_CERF_CPLD
-  set_GPIO_IRQ_edge(GPIO_GPIO(3), GPIO_RISING_EDGE); /* PDA Full serial port */
-  set_GPIO_IRQ_edge(GPIO_GPIO(2), GPIO_RISING_EDGE); /* PDA Bluetooth */
-  GPDR &= ~(GPIO_GPIO(3)); /* Set the direction of serial port GPIO pin to in */
-  GPDR &= ~(GPIO_GPIO(2)); /* Set the direction of bluetooth GPIO pin to in */
+	/* PDA Full serial port */
+	set_GPIO_IRQ_edge(GPIO_GPIO3, GPIO_RISING_EDGE);
+	/* PDA Bluetooth */
+	set_GPIO_IRQ_edge(GPIO_GPIO2, GPIO_RISING_EDGE);
 #endif /* CONFIG_SA1100_CERF_CPLD */
+
+	set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE);
 }
 
 static void __init
@@ -37,22 +39,20 @@
 	   char **cmdline, struct meminfo *mi)
 {
 #if defined(CONFIG_SA1100_CERF_64MB)
-        // 64MB RAM
-        SET_BANK( 0, 0xc0000000, 64*1024*1024 );
-        mi->nr_banks = 1;
-#elif defined(CONFIG_SA1100_CERF_32MB)	// 32MB RAM
+	SET_BANK( 0, 0xc0000000, 64*1024*1024 );
+	mi->nr_banks = 1;
+#elif defined(CONFIG_SA1100_CERF_32MB)
 	SET_BANK( 0, 0xc0000000, 32*1024*1024 );
 	mi->nr_banks = 1;
-#elif defined(CONFIG_SA1100_CERF_16MB)	// 16Meg Ram.
+#elif defined(CONFIG_SA1100_CERF_16MB)
 	SET_BANK( 0, 0xc0000000, 8*1024*1024 );
 	SET_BANK( 1, 0xc8000000, 8*1024*1024 );
 	mi->nr_banks = 2;
 #elif defined(CONFIG_SA1100_CERF_8MB)
-        // 8Meg Ram.
-        SET_BANK( 0, 0xc0000000, 8*1024*1024 );
-        mi->nr_banks = 1;
+	SET_BANK( 0, 0xc0000000, 8*1024*1024 );
+	mi->nr_banks = 1;
 #else
-       #error "Undefined memory size for Cerfboard."
+#error "Undefined memory size for Cerfboard."
 #endif
 
 //	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
@@ -62,13 +62,13 @@
 }
 
 static struct map_desc cerf_io_desc[] __initdata = {
-  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Ethernet Chip */
+  /* virtual	 physical    length	 domain     r  w  c  b */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Crystal Ethernet Chip */
 #ifdef CONFIG_SA1100_CERF_CPLD
-  { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD Chip */
-  { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Bluetooth */
-  { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Serial */
+  { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD Chip */
+  { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Bluetooth */
+  { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Serial */
 #endif
   LAST_DESC
 };
@@ -78,13 +78,19 @@
 	sa1100_map_io();
 	iotable_init(cerf_io_desc);
 
-        sa1100_register_uart(0, 3);
+	sa1100_register_uart(0, 3);
 #ifdef CONFIG_SA1100_CERF_IRDA_ENABLED
 	sa1100_register_uart(1, 1);
 #else
 	sa1100_register_uart(1, 2);
 	sa1100_register_uart(2, 1);
 #endif
+
+	/* set some GPDR bits here while it's safe */
+	GPDR |= GPIO_CF_RESET;
+#ifdef CONFIG_SA1100_CERF_CPLD
+	GPDR |= GPIO_PWR_SHUTDOWN;
+#endif
 }
 
 MACHINE_START(CERF, "Intrinsyc's Cerf Family of Products")
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/cpu-sa1100.c linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1100.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/cpu-sa1100.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1100.c	Fri Mar 29 14:49:19 2002
@@ -90,7 +90,8 @@
 
 #include <asm/hardware.h>
 
-
+extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
+extern unsigned int sa11x0_validatespeed(unsigned int khz);
 
 
 typedef struct {
@@ -219,14 +220,22 @@
 };
 
 
-
+static void sa1100_setspeed(unsigned int khz)
+{
+	PPCR = sa11x0_freq_to_ppcr(khz);
+}
 
 static int __init sa1100_dram_init(void)
 {
-	return cpufreq_register_notifier(&sa1100_dram_block);
-}
+	int ret = -ENODEV;
 
+	if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) {
+		ret = cpufreq_register_notifier(&sa1100_dram_block);
 
+		cpufreq_setfunctions(sa11x0_validatespeed, sa1100_setspeed);
+	}
 
+	return ret;
+}
 
 __initcall(sa1100_dram_init);
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/cpu-sa1110.c linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1110.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/cpu-sa1110.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/cpu-sa1110.c	Fri Mar 29 14:49:19 2002
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *
- *  $Id: cpu-sa1110.c,v 1.5 2001/09/10 13:25:58 rmk Exp $
+ *  $Id: cpu-sa1110.c,v 1.6 2001/10/22 11:53:47 rmk Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -29,14 +29,8 @@
 
 #undef DEBUG
 
-extern u_int processor_id;
-
-#define CPU_REVISION	(processor_id & 15)
-#define CPU_SA1110_A0	(0)
-#define CPU_SA1110_B0	(4)
-#define CPU_SA1110_B1	(5)
-#define CPU_SA1110_B2	(6)
-#define CPU_SA1110_B4	(8)
+extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
+extern unsigned int sa11x0_validatespeed(unsigned int khz);
 
 struct sdram_params {
 	u_char  rows;		/* bits				 */
@@ -48,6 +42,12 @@
 	u_short refresh;	/* refresh time for array (us)	 */
 };
 
+struct sdram_info {
+	u_int	mdcnfg;
+	u_int	mdrefr;
+	u_int	mdcas[3];
+};
+
 static struct sdram_params tc59sm716_cl2_params __initdata = {
 	rows:		    12,
 	tck:		    10,
@@ -68,6 +68,16 @@
 	cas_latency:	     3,
 };
 
+static struct sdram_params samsung_k4s641632d_tc75 __initdata = {
+	rows:		    14,
+	tck:		     9,
+	trcd:		    27,
+	trp:		    20,
+	twr:		     9,
+	refresh:	 64000,
+	cas_latency:	     3,
+};
+
 static struct sdram_params sdram_params;
 
 /*
@@ -95,10 +105,11 @@
 	mdcas[1]  = mdcas[2] = 0x55555555 << (shift & 1);
 }
 
-static void sdram_update_timing(u_int cpu_khz, struct sdram_params *sdram)
+static void
+sdram_calculate_timing(struct sdram_info *sd, u_int cpu_khz,
+		       struct sdram_params *sdram)
 {
-	u_int mdcnfg, mdrefr, mdcas[3], mem_khz, sd_khz, trp, twr;
-	unsigned long flags;
+	u_int mem_khz, sd_khz, trp, twr;
 
 	mem_khz = cpu_khz / 2;
 	sd_khz = mem_khz;
@@ -114,7 +125,7 @@
 	    (CPU_REVISION < CPU_SA1110_B2 && sd_khz < 62000))
 		sd_khz /= 2;
 
-	mdcnfg = MDCNFG & 0x007f007f;
+	sd->mdcnfg = MDCNFG & 0x007f007f;
 
 	twr = ns_to_cycles(sdram->twr, mem_khz);
 
@@ -123,53 +134,26 @@
 	if (trp < 1)
 		trp = 1;
 
-	mdcnfg |= trp << 8;
-	mdcnfg |= trp << 24;
-	mdcnfg |= sdram->cas_latency << 12;
-	mdcnfg |= sdram->cas_latency << 28;
-	mdcnfg |= twr << 14;
-	mdcnfg |= twr << 30;
+	sd->mdcnfg |= trp << 8;
+	sd->mdcnfg |= trp << 24;
+	sd->mdcnfg |= sdram->cas_latency << 12;
+	sd->mdcnfg |= sdram->cas_latency << 28;
+	sd->mdcnfg |= twr << 14;
+	sd->mdcnfg |= twr << 30;
 
-	mdrefr = MDREFR & 0xffbffff0;
-	mdrefr |= 7;
+	sd->mdrefr = MDREFR & 0xffbffff0;
+	sd->mdrefr |= 7;
 
 	if (sd_khz != mem_khz)
-		mdrefr |= MDREFR_K1DB2;
+		sd->mdrefr |= MDREFR_K1DB2;
 
 	/* initial number of '1's in MDCAS + 1 */
-	set_mdcas(mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz));
+	set_mdcas(sd->mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz));
 
 #ifdef DEBUG
-	mdelay(250);
 	printk("MDCNFG: %08x MDREFR: %08x MDCAS0: %08x MDCAS1: %08x MDCAS2: %08x\n",
-		mdcnfg, mdrefr, mdcas[0], mdcas[1], mdcas[2]);
+		sd->mdcnfg, sd->mdrefr, sd->mdcas[0], sd->mdcas[1], sd->mdcas[2]);
 #endif
-
-	/*
-	 * Reprogram the DRAM timings with interrupts disabled, and
-	 * ensure that we are doing this within a complete cache line.
-	 * This means that we won't access SDRAM for the duration of
-	 * the programming.
-	 */
-	local_irq_save(flags);
-	asm("mcr p15, 0, %0, c10, c4" : : "r" (0));
-	udelay(10);
-	__asm__("
-		b	1f
-		.align	5
-1:		str	%3, [%1, #28]		@ MDREFR
-		str	%4, [%1, #4]		@ MDCAS0
-		str	%5, [%1, #8]		@ MDCAS1
-		str	%6, [%1, #12]		@ MDCAS2
-		str	%2, [%1, #0]		@ MDCNFG
-		ldr	%0, [%1, #0]
-		nop
-		nop"
-		: "=&r" (mdcnfg)
-		: "r" (io_p2v(_MDCNFG)),
-		  "0" (mdcnfg), "r" (mdrefr),
-		  "r" (mdcas[0]), "r" (mdcas[1]), "r" (mdcas[2]));
-	local_irq_restore(flags);
 }
 
 /*
@@ -203,65 +187,92 @@
 	sdram_set_refresh(dri);
 }
 
-static int
-sdram_notifier(struct notifier_block *nb, unsigned long val, void *data)
+/*
+ * Ok, set the CPU frequency.  Since we've done the validation
+ * above, we can match for an exact frequency.  If we don't find
+ * an exact match, we will to set the lowest frequency to be safe.
+ */
+static void sa1110_setspeed(unsigned int khz)
 {
-	struct cpufreq_info *ci = data;
 	struct sdram_params *sdram = &sdram_params;
+	struct sdram_info sd;
+	unsigned long flags;
+	unsigned int ppcr, unused;
 
-	/* were we initialised? */
-	if (sdram->cas_latency == 0) {
-		struct cpufreq_minmax *m = data;
-		m->min_freq = m->max_freq = m->cur_freq;
-		return 0;
-	}
+	ppcr = sa11x0_freq_to_ppcr(khz);
+	sdram_calculate_timing(&sd, khz, sdram);
 
-	switch (val) {
-	case CPUFREQ_MINMAX:
-		/*
-		 * until we work out why the assabet
-		 * crashes below 147.5MHz...
-		 */
-		cpufreq_updateminmax(data, 147500, -1);
-		break;
-
-	case CPUFREQ_PRECHANGE:
-		/*
-		 * The clock could be going away for some time.
-		 * Set the SDRAMs to refresh rapidly (every 64
-		 * memory clock cycles).  To get through the
-		 * whole array, we need to wait 262144 mclk cycles.
-		 * We wait 20ms to be safe.
-		 */
-		sdram_set_refresh(2);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(20 * HZ / 1000);
-
-		if (ci->old_freq < ci->new_freq)
-			sdram_update_timing(ci->new_freq, sdram);
-		break;
-
-	case CPUFREQ_POSTCHANGE:
-		if (ci->old_freq > ci->new_freq)
-			sdram_update_timing(ci->new_freq, sdram);
-		sdram_update_refresh(ci->new_freq, sdram);
-		break;
+#if 0
+	/*
+	 * These values are wrong according to the SA1110 documentation
+	 * and errata, but they seem to work.  Need to get a storage
+	 * scope on to the SDRAM signals to work out why.
+	 */
+	if (khz < 147500) {
+		sd.mdrefr |= MDREFR_K1DB2;
+		sd.mdcas[0] = 0xaaaaaa7f;
+	} else {
+		sd.mdrefr &= ~MDREFR_K1DB2;
+		sd.mdcas[0] = 0xaaaaaa9f;
 	}
-	return 0;
-}
+	sd.mdcas[1] = 0xaaaaaaaa;
+	sd.mdcas[2] = 0xaaaaaaaa;
+#endif
+	/*
+	 * The clock could be going away for some time.  Set the SDRAMs
+	 * to refresh rapidly (every 64 memory clock cycles).  To get
+	 * through the whole array, we need to wait 262144 mclk cycles.
+	 * We wait 20ms to be safe.
+	 */
+	sdram_set_refresh(2);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(20 * HZ / 1000);
 
-static struct notifier_block sa1110_clkchg_block = {
-	notifier_call:	sdram_notifier,
-};
+	/*
+	 * Reprogram the DRAM timings with interrupts disabled, and
+	 * ensure that we are doing this within a complete cache line.
+	 * This means that we won't access SDRAM for the duration of
+	 * the programming.
+	 */
+	local_irq_save(flags);
+	asm("mcr p15, 0, %0, c10, c4" : : "r" (0));
+	udelay(10);
+	__asm__ __volatile__("
+		b	2f
+		.align	5
+1:		str	%3, [%1, #0]		@ MDCNFG
+		str	%4, [%1, #28]		@ MDREFR
+		str	%5, [%1, #4]		@ MDCAS0
+		str	%6, [%1, #8]		@ MDCAS1
+		str	%7, [%1, #12]		@ MDCAS2
+		str	%8, [%2, #0]		@ PPCR
+		ldr	%0, [%1, #0]
+		b	3f
+2:		b	1b
+3:		nop
+		nop"
+		: "=&r" (unused)
+		: "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg),
+		  "r" (sd.mdrefr), "r" (sd.mdcas[0]),
+		  "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr));
+	local_irq_restore(flags);
 
-static int __init sa1110_sdram_init(void)
+	/*
+	 * Now, return the SDRAM refresh back to normal.
+	 */
+	sdram_update_refresh(khz, sdram);
+}
+
+static int __init sa1110_clk_init(void)
 {
 	struct sdram_params *sdram = NULL;
-	unsigned int cur_freq = cpufreq_get(smp_processor_id());
 
 	if (machine_is_assabet())
 		sdram = &tc59sm716_cl3_params;
 
+	if (machine_is_pt_system3())
+		sdram = &samsung_k4s641632d_tc75;
+
 	if (sdram) {
 		printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
 			" twr: %d refresh: %d cas_latency: %d\n",
@@ -270,11 +281,11 @@
 
 		memcpy(&sdram_params, sdram, sizeof(sdram_params));
 
-		sdram_update_timing(cur_freq, &sdram_params);
-		sdram_update_refresh(cur_freq, &sdram_params);
+		sa1110_setspeed(cpufreq_get(0));
+		cpufreq_setfunctions(sa11x0_validatespeed, sa1110_setspeed);
 	}
 
-	return cpufreq_register_notifier(&sa1110_clkchg_block);
+	return 0;
 }
 
-__initcall(sa1110_sdram_init);
+__initcall(sa1110_clk_init);
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/dma-sa1100.c linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1100.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/dma-sa1100.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1100.c	Fri Mar 29 14:49:19 2002
@@ -147,6 +147,19 @@
 		}
 
 		/*
+		 * This improves latency if there are some active spinning
+		 * buffers.  We kill them altogether.
+		 */
+		if (dma->spin_ref > 0) {
+			if (channel_is_sa1111_sac(dma - dma_chan))
+				sa1111_reset_sac_dma(dma - dma_chan);
+			else
+				dma->regs->ClrDCSR =
+				    DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB;
+			dma->spin_ref = 0;
+		}
+
+		/*
 		 * Let's try to start DMA on the current buffer.
 		 * If DMA is busy then we break here.
 		 */
@@ -188,8 +201,7 @@
 			 */
 			DPRINTK("IRQ: buf done\n");
 			dma->curr = buf->next;
-			if (dma->curr == NULL)
-				dma->spin_ref = -dma->spin_ref;
+			dma->spin_ref = -dma->spin_ref;
 			if (dma->head == buf)
 				dma->head = NULL;
 			if (dma->callback) {
@@ -468,7 +480,6 @@
 		int flags;
 		save_flags_cli(flags);
 		dma->stopped = 0;
-		dma->spin_ref = 0;
 		process_dma(dma);
 		restore_flags(flags);
 	}
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/dma-sa1111.c linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1111.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/dma-sa1111.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/dma-sa1111.c	Fri Mar 29 14:49:19 2002
@@ -22,6 +22,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/dma.h>
+#include <asm/hardware/sa1111.h>
 
 // #define DEBUG
 #ifdef DEBUG
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/empeg.c linux-2.4.19-pre5/arch/arm/mach-sa1100/empeg.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/empeg.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/empeg.c	Fri Mar 29 14:49:19 2002
@@ -31,7 +31,7 @@
 
 static struct map_desc empeg_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/flexanet.c linux-2.4.19-pre5/arch/arm/mach-sa1100/flexanet.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/flexanet.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/flexanet.c	Fri Mar 29 14:49:19 2002
@@ -9,8 +9,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -27,22 +25,140 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <linux/serial_core.h>
 
 #include "generic.h"
 
 
-unsigned long BCR_value         = BCR_POWERUP;
-unsigned long flexanet_GUI_type = 0x0000000F;
+unsigned long flexanet_BCR = FHH_BCR_POWERUP;
+
+EXPORT_SYMBOL(flexanet_BCR);
+
+/* physical addresses */
+#define _RCNR        0x90010004
+#define _GPLR        0x90040000
+#define _Ser4SSCR0   0x80070060
+
+/*
+ * Get the modem-control register of the UARTs
+ *
+ */
+static int flexanet_get_mctrl(struct uart_port *port)
+{
+	int            stat = 0;
+	unsigned long  bsr;
+
+	/* only DSR and CTS are implemented in UART1 & 3 */
+	if (port->membase == (void *)&Ser1UTCR0)
+	{
+		bsr = FHH_BSR;
+
+		if ((bsr & FHH_BSR_DSR1) != 0)
+			stat |= TIOCM_DSR;
+		if ((bsr & FHH_BSR_CTS1) != 0)
+			stat |= TIOCM_CTS;
+	}
+	else if (port->membase == (void *)&Ser3UTCR0)
+	{
+		bsr = FHH_BSR;
+
+		if ((bsr & FHH_BSR_DSR3) != 0)
+			stat |= TIOCM_DSR;
+		if ((bsr & FHH_BSR_CTS3) != 0)
+			stat |= TIOCM_CTS;
+	}
 
-EXPORT_SYMBOL(BCR_value);
-EXPORT_SYMBOL(flexanet_GUI_type);
+	return stat;
+}
+
+/*
+ * Set the modem-control register of the UARTs
+ *
+ */
+static void flexanet_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	unsigned long	flags;
+
+	/* only the RTS signal is implemented in UART1 & 3 */
+	if (port->membase == (void *)&Ser1UTCR0)
+	{
+		local_irq_save(flags);
+
+		if (mctrl & TIOCM_RTS)
+			flexanet_BCR |= FHH_BCR_RTS1;
+		else
+			flexanet_BCR &= ~FHH_BCR_RTS1;
+
+		FHH_BCR = flexanet_BCR;
+		local_irq_restore(flags);
+	}
+	else if (port->membase == (void *)&Ser3UTCR0)
+	{
+		local_irq_save(flags);
+
+		if (mctrl & TIOCM_RTS)
+			flexanet_BCR |= FHH_BCR_RTS3;
+		else
+			flexanet_BCR &= ~FHH_BCR_RTS3;
+
+		FHH_BCR = flexanet_BCR;
+		local_irq_restore(flags);
+	}
+}
+
+/*
+ * machine-specific serial port functions
+ *
+ * get_mctrl : set state of modem control lines
+ * set_mctrl : set the modem control lines
+ * pm        : power-management. Turn device on/off.
+ *
+ */
+static struct sa1100_port_fns	flexanet_port_fns __initdata =
+{
+	set_mctrl : flexanet_set_mctrl,
+	get_mctrl : flexanet_get_mctrl,
+	pm        : NULL,
+};
+
+
+/*
+ * Initialization and serial port mapping
+ *
+ */
+
+static int flexanet_serial_init(void)
+{
+	/* register low-level functions */
+	sa1100_register_uart_fns(&flexanet_port_fns);
+
+	/* UART port number mapping */
+	sa1100_register_uart(0, 1); /* RS232 */
+	sa1100_register_uart(1, 3); /* Radio */
+
+	/* Select UART function in Serial port 1 */
+	Ser1SDCR0 |= SDCR0_UART;
+
+	return 0;
+}
+
+
+static int __init flexanet_init(void)
+{
+	return 0;
+}
+
+__initcall(flexanet_init);
 
-static unsigned long probe_gui_board (void);
 
 static void __init
 fixup_flexanet(struct machine_desc *desc, struct param_struct *params,
 	      char **cmdline, struct meminfo *mi)
 {
+	int				status;
+	unsigned long	now;
+
+
 	/* fixed RAM size, by now (64MB) */
 	SET_BANK( 0, 0xc0000000, 64*1024*1024 );
 	mi->nr_banks = 1;
@@ -56,8 +172,11 @@
 
 static struct map_desc flexanet_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
+  { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Ethernet controller */
+  { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Instrument boards */
+  { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* External peripherals */
   LAST_DESC
 };
 
@@ -65,9 +184,27 @@
 {
 	sa1100_map_io();
 	iotable_init(flexanet_io_desc);
+	flexanet_serial_init();
 
-	sa1100_register_uart(0, 1);
-	Ser1SDCR0 |= SDCR0_UART;
+	/* wakeup source is GPIO-0 only */
+	PWER = PWER_GPIO0;
+
+	/* GPIOs set to zero during sleep */
+	PGSR = 0;
+
+	/*
+	 * stop the 3.68 MHz oscillator and float control busses
+	 * during sleep, since peripherals are powered off.
+	 */
+	PCFR = PCFR_OPDE | PCFR_FP | PCFR_FS;
+
+	/* deassert the GUI reset */
+	FLEXANET_BCR_set(FHH_BCR_GUI_NRST);
+
+	/*
+	 * Set IRQ edges
+	 */
+	set_GPIO_IRQ_edge(GPIO_GUI_IRQ, GPIO_RISING_EDGE);
 }
 
 
@@ -78,3 +215,4 @@
 	MAPIO(flexanet_map_io)
 	INITIRQ(sa1100_init_irq)
 MACHINE_END
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/freebird.c linux-2.4.19-pre5/arch/arm/mach-sa1100/freebird.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/freebird.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/freebird.c	Fri Mar 29 14:49:19 2002
@@ -37,9 +37,9 @@
 
 static struct map_desc freebird_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
-  { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0},
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
+  { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0},
    LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/frodo.c linux-2.4.19-pre5/arch/arm/mach-sa1100/frodo.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/frodo.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/frodo.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,61 @@
+
+/*
+ * linux/arch/arm/mach-sa1100/frodo.c
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * This file contains the 2d3D, Inc. SA-1110 Development Board tweaks.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * History:
+ *
+ *   2002/01/31   Initial version
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include "generic.h"
+
+static struct map_desc frodo_io_desc[] __initdata =
+{
+  /* virtual     physical    length      domain     r  w  c  b */
+   { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 },	/* flash memory */
+   { 0xf0000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 },	/* 16-bit on-board devices (including CPLDs) */
+   { 0xf1000000, 0x18000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 },	/* 32-bit daughter card */
+   LAST_DESC
+};
+
+static void __init frodo_map_io (void)
+{
+   sa1100_map_io ();
+   iotable_init (frodo_io_desc);
+
+   sa1100_register_uart (0,2);	/* UART2 (serial console) */
+   sa1100_register_uart (1,1);	/* UART1 (big kahuna flow control serial port) */
+
+   /*
+	* Set SUS bit in SDCR0 so serial port 1 acts as a UART.
+	* See Intel SA-1110 Developers Manual Section 11.9.2.1 (GPCLK/UART Select)
+	*/
+   Ser1SDCR0 |= SDCR0_SUS;
+}
+
+MACHINE_START (FRODO,"2d3D, Inc. SA-1110 Development Board")
+	BOOT_MEM (0xc0000000,0x80000000,0xf8000000)
+	BOOT_PARAMS (0xc0000100)
+	MAPIO (frodo_map_io)
+	INITIRQ (sa1100_init_irq)
+MACHINE_END
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/generic.c linux-2.4.19-pre5/arch/arm/mach-sa1100/generic.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/generic.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/generic.c	Fri Mar 29 14:49:19 2002
@@ -56,20 +56,13 @@
 /*
  * Return the current CPU clock frequency in units of 100kHz
  */
-unsigned short get_cclk_frequency(void)
+static inline unsigned short get_cclk_frequency(void)
 {
 	return cclk_frequency_100khz[PPCR & 0xf];
 }
 
-EXPORT_SYMBOL(get_cclk_frequency);
-
 #ifdef CONFIG_CPU_FREQ
-
-/*
- * Validate the speed in khz.  If we can't generate the precise
- * frequency requested, round it down (to be on the safe side).
- */
-unsigned int sa1100_validatespeed(unsigned int khz)
+unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
 {
 	int i;
 
@@ -79,35 +72,34 @@
 		if (cclk_frequency_100khz[i] <= khz)
 			break;
 
-	return cclk_frequency_100khz[i] * 100;
+	return i;
 }
 
 /*
- * Ok, set the CPU frequency.  Since we've done the validation
- * above, we can match for an exact frequency.  If we don't find
- * an exact match, we will to set the lowest frequency to be safe.
+ * Validate the speed in khz.  If we can't generate the precise
+ * frequency requested, round it down (to be on the safe side).
  */
-void sa1100_setspeed(unsigned int khz)
+unsigned int sa11x0_validatespeed(unsigned int khz)
 {
-	int i;
-
-	khz /= 100;
-
-	for (i = NR_FREQS - 1; i > 0; i--)
-		if (cclk_frequency_100khz[i] == khz)
-			break;
-//printk("setting ppcr to %d\n", i);
-	PPCR = i;
+	return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100;
 }
 
-static int __init sa1100_init_clock(void)
+static int __init sa11x0_init_clock(void)
 {
-	cpufreq_init(get_cclk_frequency() * 100);
-	cpufreq_setfunctions(sa1100_validatespeed, sa1100_setspeed);
+	cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100);
 	return 0;
 }
 
-__initcall(sa1100_init_clock);
+__initcall(sa11x0_init_clock);
+#else
+/*
+ * We still need to provide this so building without cpufreq works.
+ */ 
+unsigned int cpufreq_get(int cpu)
+{
+	return cclk_frequency_100khz[PPCR & 0xf] * 100;
+}
+EXPORT_SYMBOL(cpufreq_get);
 #endif
 
 /*
@@ -130,13 +122,13 @@
 	PMCR = PMCR_SF;
 }
 
-static int __init sa1100_set_poweroff(void)
+static int __init sa1100_init(void)
 {
 	pm_power_off = sa1100_power_off;
 	return 0;
 }
 
-__initcall(sa1100_set_poweroff);
+__initcall(sa1100_init);
 
 
 /*
@@ -149,7 +141,8 @@
  * 0xf0000000-0xf3ffffff:	miscellaneous stuff (CPLDs, etc.)
  * 0xf4000000-0xf4ffffff:	SA-1111
  * 0xf5000000-0xf5ffffff:	reserved (used by cache flushing area)
- * 0xf6000000-0xffffffff:	reserved (internal SA1100 IO defined above)
+ * 0xf6000000-0xfffeffff:	reserved (internal SA1100 IO defined above)
+ * 0xffff0000-0xffff0fff:	SA1100 exception vectors
  *
  * Below 0xe8000000 is reserved for vm allocation.
  *
@@ -159,8 +152,8 @@
 
 static struct map_desc standard_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */
-  { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */
+  { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
+  { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
   { 0xf8000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
   { 0xfa000000, 0x90000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
   { 0xfc000000, 0xa0000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/graphicsclient.c linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsclient.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/graphicsclient.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsclient.c	Fri Mar 29 14:49:19 2002
@@ -113,7 +113,6 @@
 		irq_desc[irq].mask	= ADS_mask_irq1;
 		irq_desc[irq].unmask	= ADS_unmask_irq1;
 	}
-	GPDR &= ~GPIO_GPIO0;
 	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
 	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
 }
@@ -138,7 +137,7 @@
 
 static struct map_desc graphicsclient_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */
   { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
   { 0xf1000000, 0x18000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */
   LAST_DESC
@@ -193,12 +192,8 @@
 	if (port->mapbase == _Ser1UTCR0) {
 		Ser1SDCR0 |= SDCR0_UART;
 		/* Set RTS Output */
-		GPDR |= GPIO_GC_UART0_RTS;
 		GPSR  = GPIO_GC_UART0_RTS;
 
-		/* Set CTS Input */
-		GPDR &= ~GPIO_GC_UART0_CTS;
-
 		gc_uart_ctrl_data[0].cts_prev_state = 0;
 		gc_uart_ctrl_data[0].info = info;
 		gc_uart_ctrl_data[0].port = port;
@@ -210,12 +205,8 @@
 	} else if (port->mapbase == _Ser2UTCR0) {
 		Ser2UTCR4 = Ser2HSCR0 = 0;
 		/* Set RTS Output */
-		GPDR |= GPIO_GC_UART1_RTS;
 		GPSR  = GPIO_GC_UART1_RTS;
 
-		/* Set CTS Input */
-		GPDR &= ~GPIO_GC_UART1_RTS;
-
 		gc_uart_ctrl_data[1].cts_prev_state = 0;
 		gc_uart_ctrl_data[1].info = info;
 		gc_uart_ctrl_data[1].port = port;
@@ -226,12 +217,8 @@
 							&gc_uart_ctrl_data[1]);
 	} else if (port->mapbase == _Ser3UTCR0) {
 		/* Set RTS Output */
-		GPDR |= GPIO_GC_UART2_RTS;
 		GPSR =	GPIO_GC_UART2_RTS;
 
-		/* Set CTS Input */
-		GPDR &= ~GPIO_GC_UART2_RTS;
-
 		gc_uart_ctrl_data[2].cts_prev_state = 0;
 		gc_uart_ctrl_data[2].info = info;
 		gc_uart_ctrl_data[2].port = port;
@@ -258,9 +245,9 @@
 	return 0;
 }
 
-static int graphicsclient_get_mctrl(struct uart_port *port)
+static u_int graphicsclient_get_mctrl(struct uart_port *port)
 {
-	int result = TIOCM_CD | TIOCM_DSR;
+	u_int result = TIOCM_CD | TIOCM_DSR;
 
 	if (port->mapbase == _Ser1UTCR0) {
 		if (!(GPLR & GPIO_GC_UART0_CTS))
@@ -326,6 +313,8 @@
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
 	sa1100_register_uart(2, 2);
+	GPDR |= GPIO_GC_UART0_RTS | GPIO_GC_UART1_RTS | GPIO_GC_UART2_RTS;
+	GPDR &= ~(GPIO_GC_UART0_CTS | GPIO_GC_UART1_RTS | GPIO_GC_UART2_RTS);
 }
 
 MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient")
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/graphicsmaster.c linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsmaster.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/graphicsmaster.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/graphicsmaster.c	Fri Mar 29 14:49:19 2002
@@ -43,7 +43,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	ret = sa1111_probe();
+	ret = sa1111_probe(ADS_SA1111_BASE);
 	if (ret < 0)
 		return ret;
 
@@ -174,7 +174,6 @@
 		irq_desc[irq].mask	= ADS_mask_irq1;
 		irq_desc[irq].unmask	= ADS_unmask_irq1;
 	}
-	GPDR &= ~GPIO_GPIO0;
 	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
 	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
 }
@@ -200,10 +199,10 @@
 
 static struct map_desc graphicsmaster_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
-  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD */
-  { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CAN */
-  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */
+  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
+  { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */
+  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
@@ -215,31 +214,22 @@
 		Ser1SDCR0 |= SDCR0_UART;
 		/* Set RTS Output */
 		GPSR = GPIO_GPIO15;
-		GPDR |= GPIO_GPIO15;
-		/* Set CTS Input */
-		GPDR &= ~GPIO_GPIO14;
 	}
 	else if (port->mapbase == _Ser2UTCR0) {
 		Ser2UTCR4 = Ser2HSCR0 = 0;
 		/* Set RTS Output */
 		GPSR = GPIO_GPIO17;
-		GPDR |= GPIO_GPIO17;
-		/* Set CTS Input */
-		GPDR &= ~GPIO_GPIO16;
 	}
 	else if (port->mapbase == _Ser3UTCR0) {
 	        /* Set RTS Output */
 		GPSR = GPIO_GPIO19;
-		GPDR |= GPIO_GPIO19;
-		/* Set CTS Input */
-		GPDR &= ~GPIO_GPIO18;
 	}
 	return ret;
 }
 
-static int graphicsmaster_get_mctrl(struct uart_port *port)
+static u_int graphicsmaster_get_mctrl(struct uart_port *port)
 {
-	int result = TIOCM_CD | TIOCM_DSR;
+	u_int result = TIOCM_CD | TIOCM_DSR;
 
 	if (port->mapbase == _Ser1UTCR0) {
 		if (!(GPLR & GPIO_GPIO14))
@@ -304,6 +294,10 @@
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
 	sa1100_register_uart(2, 2);
+
+	/* set GPDR now */
+	GPDR |= GPIO_GPIO15 | GPIO_GPIO17 | GPIO_GPIO19;
+       	GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO16 | GPIO_GPIO18);
 }
 
 MACHINE_START(GRAPHICSMASTER, "ADS GraphicsMaster")
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/h3600.c linux-2.4.19-pre5/arch/arm/mach-sa1100/h3600.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/h3600.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/h3600.c	Fri Mar 29 14:49:19 2002
@@ -1,8 +1,24 @@
 /*
- * linux/arch/arm/mach-sa1100/h3600.c
+ * Hardware definitions for Compaq iPAQ H3xxx Handheld Computers
+ *
+ * Copyright 2000,1 Compaq Computer Corporation.
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Jamey Hicks.
+ *
+ * History:
+ *
+ * 2001-10-??	Andrew Christian   Added support for iPAQ H3800
+ *				   and abstracted EGPIO interface.
+ *
  */
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -17,84 +33,338 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 #include <linux/serial_core.h>
+#include <asm/arch/h3600_gpio.h>
 
 #include "generic.h"
 
-
 /*
- * Bitsy has extended, write-only memory-mapped GPIO's
+ * H3600 has extended, write-only memory-mapped GPIO's
+ * H3100 has 1/2 extended, write-only GPIO and 1/2 on
+ *	 regular GPIO lines.
+ * H3800 has memory-mapped GPIO through ASIC1 & 2
  */
 
-static int h3600_egpio = EGPIO_H3600_RS232_ON;
+#define H3600_EGPIO	(*(volatile unsigned int *)H3600_EGPIO_VIRT)
+
+static unsigned int h3600_egpio;
+
+/************************* H3100 *************************/
+
+#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON	  \
+			  | GPIO_H3100_GPIO3	  \
+			  | GPIO_H3100_QMUTE	  \
+			  | GPIO_H3100_LCD_3V_ON  \
+			  | GPIO_H3100_AUD_ON	  \
+			  | GPIO_H3100_AUD_PWR_ON \
+			  | GPIO_H3100_IR_ON	  \
+			  | GPIO_H3100_IR_FSEL)
+
+static void h3100_init_egpio( void )
+{
+	GPDR |= H3100_DIRECT_EGPIO;
+	GPCR = H3100_DIRECT_EGPIO;   /* Initially all off */
+
+	/* Older bootldrs put GPIO2-9 in alternate mode on the
+	   assumption that they are used for video */
+	GAFR &= ~H3100_DIRECT_EGPIO;
+
+	h3600_egpio = EGPIO_H3600_RS232_ON;
+	H3600_EGPIO = h3600_egpio;
+}
+
+static void h3100_control_egpio( enum ipaq_egpio_type x, int setp )
+{
+	unsigned int egpio = 0;
+	long	     gpio = 0;
+	unsigned long flags;
+
+	switch (x) {
+	case IPAQ_EGPIO_LCD_ON:
+		egpio |= EGPIO_H3600_LCD_ON;
+		gpio  |= GPIO_H3100_LCD_3V_ON;
+		break;
+	case IPAQ_EGPIO_CODEC_NRESET:
+		egpio |= EGPIO_H3600_CODEC_NRESET;
+		break;
+	case IPAQ_EGPIO_AUDIO_ON:
+		gpio |= GPIO_H3100_AUD_PWR_ON
+			| GPIO_H3100_AUD_ON;
+		break;
+	case IPAQ_EGPIO_QMUTE:
+		gpio |= GPIO_H3100_QMUTE;
+		break;
+	case IPAQ_EGPIO_OPT_NVRAM_ON:
+		egpio |= EGPIO_H3600_OPT_NVRAM_ON;
+		break;
+	case IPAQ_EGPIO_OPT_ON:
+		egpio |= EGPIO_H3600_OPT_ON;
+		break;
+	case IPAQ_EGPIO_CARD_RESET:
+		egpio |= EGPIO_H3600_CARD_RESET;
+		break;
+	case IPAQ_EGPIO_OPT_RESET:
+		egpio |= EGPIO_H3600_OPT_RESET;
+		break;
+	case IPAQ_EGPIO_IR_ON:
+		gpio |= GPIO_H3100_IR_ON;
+		break;
+	case IPAQ_EGPIO_IR_FSEL:
+		gpio |= GPIO_H3100_IR_FSEL;
+		break;
+	case IPAQ_EGPIO_RS232_ON:
+		egpio |= EGPIO_H3600_RS232_ON;
+		break;
+	case IPAQ_EGPIO_VPP_ON:
+		egpio |= EGPIO_H3600_VPP_ON;
+		break;
+	}
+
+	local_irq_save(flags);
+	if ( setp ) {
+		h3600_egpio |= egpio;
+		GPSR = gpio;
+	} else {
+		h3600_egpio &= ~egpio;
+		GPCR = gpio;
+	}
+	H3600_EGPIO = h3600_egpio;
+	local_irq_restore(flags);
+
+	/*
+	if ( x != IPAQ_EGPIO_VPP_ON ) {
+		printk(__FUNCTION__ " : type=%d (%s) gpio=0x%x (0x%x) egpio=0x%x (0x%x) setp=%d\n",
+		       x, egpio_names[x], GPLR, gpio, h3600_egpio, egpio, setp );
+	}
+	*/
+}
+
+static unsigned long h3100_read_egpio( void )
+{
+	return h3600_egpio;
+}
+
+static struct ipaq_model_ops h3100_model_ops __initdata = {
+	model	     : IPAQ_H3100,
+	generic_name : "3100",
+	initialize   : h3100_init_egpio,
+	control      : h3100_control_egpio,
+	read	     : h3100_read_egpio
+};
 
-void init_h3600_egpio(void)
+
+/************************* H3600 *************************/
+
+static void h3600_init_egpio( void )
 {
-#ifdef CONFIG_IPAQ_H3100
-	int h3100_controls = (GPIO_H3100_BT_ON
-			      | GPIO_H3100_QMUTE
-			      | GPIO_H3100_LCD_3V_ON 
-			      | GPIO_H3100_AUD_ON
-			      | GPIO_H3100_AUD_PWR_ON
-			      | GPIO_H3100_IR_ON
-			      | GPIO_H3100_IR_FSEL);
-	GPDR |= h3100_controls;
-	GPCR = h3100_controls;
-	GAFR = GPIO_SSP_CLK;
-#endif
-}
-
-void clr_h3600_egpio(unsigned long x)
-{
-#ifdef CONFIG_IPAQ_H3100
-	unsigned long gpcr = 0;
-	if (x&EGPIO_H3600_QMUTE)
-		gpcr |= GPIO_H3100_QMUTE;
-	if (x&EGPIO_H3600_LCD_ON)
-		gpcr |= GPIO_H3100_LCD_3V_ON;
-	if (x&EGPIO_H3600_AUD_AMP_ON)
-		gpcr |= GPIO_H3100_AUD_ON;
-	if (x&EGPIO_H3600_AUD_PWR_ON)
-		gpcr |= GPIO_H3100_AUD_PWR_ON;
-	if (x&EGPIO_H3600_IR_ON)
-		gpcr |= GPIO_H3100_IR_ON;
-	if (x&EGPIO_H3600_IR_FSEL)
-		gpcr |= GPIO_H3100_IR_FSEL;
-	GPCR = gpcr;
-#endif
-	h3600_egpio &= ~x;
+	h3600_egpio = EGPIO_H3600_RS232_ON;
 	H3600_EGPIO = h3600_egpio;
 }
 
-void set_h3600_egpio(unsigned long x)
+static void h3600_control_egpio( enum ipaq_egpio_type x, int setp )
 {
-#ifdef CONFIG_IPAQ_H3100
-	unsigned long gpsr = 0;
-	if (x&EGPIO_H3600_QMUTE)
-		gpsr |= GPIO_H3100_QMUTE;
-	if (x&EGPIO_H3600_LCD_ON)
-		gpsr |= GPIO_H3100_LCD_3V_ON;
-	if (x&EGPIO_H3600_AUD_AMP_ON)
-		gpsr |= GPIO_H3100_AUD_ON;
-	if (x&EGPIO_H3600_AUD_PWR_ON)
-		gpsr |= GPIO_H3100_AUD_PWR_ON;
-	if (x&EGPIO_H3600_IR_ON)
-		gpsr |= GPIO_H3100_IR_ON;
-	if (x&EGPIO_H3600_IR_FSEL)
-		gpsr |= GPIO_H3100_IR_FSEL;
-	GPSR = gpsr;
-#endif
-	h3600_egpio |= x;
+	unsigned int egpio = 0;
+	unsigned long flags;
+
+	switch (x) {
+	case IPAQ_EGPIO_LCD_ON:
+		egpio |= EGPIO_H3600_LCD_ON |
+			 EGPIO_H3600_LCD_PCI |
+			 EGPIO_H3600_LCD_5V_ON |
+			 EGPIO_H3600_LVDD_ON;
+		break;
+	case IPAQ_EGPIO_CODEC_NRESET:
+		egpio |= EGPIO_H3600_CODEC_NRESET;
+		break;
+	case IPAQ_EGPIO_AUDIO_ON:
+		egpio |= EGPIO_H3600_AUD_AMP_ON |
+			EGPIO_H3600_AUD_PWR_ON;
+		break;
+	case IPAQ_EGPIO_QMUTE:
+		egpio |= EGPIO_H3600_QMUTE;
+		break;
+	case IPAQ_EGPIO_OPT_NVRAM_ON:
+		egpio |= EGPIO_H3600_OPT_NVRAM_ON;
+		break;
+	case IPAQ_EGPIO_OPT_ON:
+		egpio |= EGPIO_H3600_OPT_ON;
+		break;
+	case IPAQ_EGPIO_CARD_RESET:
+		egpio |= EGPIO_H3600_CARD_RESET;
+		break;
+	case IPAQ_EGPIO_OPT_RESET:
+		egpio |= EGPIO_H3600_OPT_RESET;
+		break;
+	case IPAQ_EGPIO_IR_ON:
+		egpio |= EGPIO_H3600_IR_ON;
+		break;
+	case IPAQ_EGPIO_IR_FSEL:
+		egpio |= EGPIO_H3600_IR_FSEL;
+		break;
+	case IPAQ_EGPIO_RS232_ON:
+		egpio |= EGPIO_H3600_RS232_ON;
+		break;
+	case IPAQ_EGPIO_VPP_ON:
+		egpio |= EGPIO_H3600_VPP_ON;
+		break;
+	}
+
+	local_irq_save(flags);
+	if ( setp )
+		h3600_egpio |= egpio;
+	else
+		h3600_egpio &= ~egpio;
 	H3600_EGPIO = h3600_egpio;
+	local_irq_restore(flags);
+}
+
+static unsigned long h3600_read_egpio( void )
+{
+	return h3600_egpio;
+}
+
+static struct ipaq_model_ops h3600_model_ops __initdata = {
+	model	     : IPAQ_H3600,
+	generic_name : "3600",
+	initialize   : h3600_init_egpio,
+	control      : h3600_control_egpio,
+	read	     : h3600_read_egpio
+};
+
+/************************* H3800 *************************/
+
+#define ASIC1_OUTPUTS	 0x7fff   /* First 15 bits are used */
+
+static unsigned int h3800_asic1_gpio;
+static unsigned int h3800_asic2_gpio;
+
+static void h3800_init_egpio(void)
+{
+	/* Set up ASIC #1 */
+	H3800_ASIC1_GPIO_Direction    = ASIC1_OUTPUTS;		  /* All outputs */
+	H3800_ASIC1_GPIO_Mask	      = ASIC1_OUTPUTS;		  /* No interrupts */
+	H3800_ASIC1_GPIO_SleepMask    = ASIC1_OUTPUTS;
+	H3800_ASIC1_GPIO_SleepDir     = ASIC1_OUTPUTS;
+	H3800_ASIC1_GPIO_SleepOut     = GPIO_H3800_ASIC1_EAR_ON_N;
+	H3800_ASIC1_GPIO_BattFaultDir = ASIC1_OUTPUTS;
+	H3800_ASIC1_GPIO_BattFaultOut = GPIO_H3800_ASIC1_EAR_ON_N;
+
+	h3800_asic1_gpio = GPIO_H3800_ASIC1_IR_ON_N   /* TODO: Check IR level */
+		| GPIO_H3800_ASIC1_RS232_ON
+		| GPIO_H3800_ASIC1_EAR_ON_N;
+
+	H3800_ASIC1_GPIO_Out = h3800_asic1_gpio;
+
+	/* Set up ASIC #2 */
+	H3800_ASIC2_GPIO_Direction = GPIO_H3800_ASIC2_PEN_IRQ
+		| GPIO_H3800_ASIC2_SD_DETECT
+		| GPIO_H3800_ASIC2_EAR_IN_N
+		| GPIO_H3800_ASIC2_USB_DETECT_N
+		| GPIO_H3800_ASIC2_SD_CON_SLT;
+
+	h3800_asic2_gpio = GPIO_H3800_ASIC2_IN_Y1_N | GPIO_H3800_ASIC2_IN_X1_N;
+	H3800_ASIC2_GPIO_Data	      = h3800_asic2_gpio;
+	H3800_ASIC2_GPIO_BattFaultOut = h3800_asic2_gpio;
+
+	/* TODO : Set sleep states & battery fault states */
+
+	/* Clear VPP Enable */
+	H3800_ASIC1_FlashWP_VPP_ON = 0;
+}
+
+static void h3800_control_egpio( enum ipaq_egpio_type x, int setp )
+{
+	unsigned int set_asic1_egpio = 0;
+	unsigned int clear_asic1_egpio = 0;
+	unsigned long flags;
+
+	switch (x) {
+	case IPAQ_EGPIO_LCD_ON:
+		set_asic1_egpio |= GPIO_H3800_ASIC1_LCD_5V_ON
+			| GPIO_H3800_ASIC1_LCD_ON
+			| GPIO_H3800_ASIC1_LCD_PCI
+			| GPIO_H3800_ASIC1_VGH_ON
+			| GPIO_H3800_ASIC1_VGL_ON;
+		break;
+	case IPAQ_EGPIO_CODEC_NRESET:
+		break;
+	case IPAQ_EGPIO_AUDIO_ON:
+		break;
+	case IPAQ_EGPIO_QMUTE:
+		break;
+	case IPAQ_EGPIO_OPT_NVRAM_ON:
+		break;
+	case IPAQ_EGPIO_OPT_ON:
+		break;
+	case IPAQ_EGPIO_CARD_RESET:
+		break;
+	case IPAQ_EGPIO_OPT_RESET:
+		break;
+	case IPAQ_EGPIO_IR_ON:
+		clear_asic1_egpio |= GPIO_H3800_ASIC1_IR_ON_N;	 /* TODO : This is backwards? */
+		break;
+	case IPAQ_EGPIO_IR_FSEL:
+		break;
+	case IPAQ_EGPIO_RS232_ON:
+		set_asic1_egpio |= GPIO_H3800_ASIC1_RS232_ON;
+		break;
+	case IPAQ_EGPIO_VPP_ON:
+		H3800_ASIC1_FlashWP_VPP_ON = setp;
+		break;
+	}
+
+	local_irq_save(flags);
+	if ( setp ) {
+		h3800_asic1_gpio |= set_asic1_egpio;
+		h3800_asic1_gpio &= ~clear_asic1_egpio;
+	}
+	else {
+		h3800_asic1_gpio &= ~set_asic1_egpio;
+		h3800_asic1_gpio |= clear_asic1_egpio;
+	}
+	H3800_ASIC1_GPIO_Out = h3800_asic1_gpio;
+	local_irq_restore(flags);
+}
+
+static unsigned long h3800_read_egpio( void )
+{
+	return h3800_asic1_gpio | (h3800_asic2_gpio << 16);
 }
 
-EXPORT_SYMBOL(clr_h3600_egpio);
-EXPORT_SYMBOL(set_h3600_egpio);
+static struct ipaq_model_ops h3800_model_ops __initdata = {
+	model	     : IPAQ_H3800,
+	generic_name : "3800",
+	initialize   : h3800_init_egpio,
+	control      : h3800_control_egpio,
+	read	     : h3800_read_egpio
+};
 
 
 /*
- * Low-level UART features.
- *
- * Note that RTS, CTS and DCD are all active low.
+ * Use command line argument to choose between ipaq handheld model numbers
+ */
+
+struct ipaq_model_ops ipaq_model_ops;
+EXPORT_SYMBOL(ipaq_model_ops);
+
+static int __init h3600_init_model_ops(void)
+{
+	if (machine_is_h3xxx()) {
+		if (machine_is_h3100()) {
+			ipaq_model_ops = h3100_model_ops;
+		} else if (machine_is_h3600()) {
+			ipaq_model_ops = h3600_model_ops;
+		} else if (machine_is_h3800()) {
+			ipaq_model_ops = h3800_model_ops;
+		}
+		init_h3600_egpio();
+	}
+	return 0;
+}
+
+__initcall(h3600_init_model_ops);
+
+/*
+ * low-level UART features
  */
 
 static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
@@ -107,9 +377,9 @@
 	}
 }
 
-static int h3600_uart_get_mctrl(struct uart_port *port)
+static u_int h3600_uart_get_mctrl(struct uart_port *port)
 {
-	int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
 
 	if (port->mapbase == _Ser3UTCR0) {
 		int gplr = GPLR;
@@ -139,18 +409,28 @@
 static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 {
 	if (port->mapbase == _Ser2UTCR0) {
-		if (state == 0) {
-			set_h3600_egpio(EGPIO_H3600_IR_ON);
-		} else {
-			clr_h3600_egpio(EGPIO_H3600_IR_ON);
-		}
+		assign_h3600_egpio( IPAQ_EGPIO_IR_ON, !state );
 	} else if (port->mapbase == _Ser3UTCR0) {
-		if (state == 0) {
-			set_h3600_egpio(EGPIO_H3600_RS232_ON);
-		} else {
-			clr_h3600_egpio(EGPIO_H3600_RS232_ON);
-		}
+		assign_h3600_egpio( IPAQ_EGPIO_RS232_ON, !state );
+	}
+}
+
+/*
+ * Enable/Disable wake up events for this serial port.
+ * Obviously, we only support this on the normal COM port.
+ */
+static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
+{
+	int err = -EINVAL;
+
+	if (port->mapbase == _Ser3UTCR0) {
+		if (enable)
+			PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */
+		else
+			PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
+		err = 0;
 	}
+	return err;
 }
 
 static int h3600_uart_open(struct uart_port *port, struct uart_info *info)
@@ -163,8 +443,6 @@
 		Ser2HSSR0 = HSSR0_EIF | HSSR0_TUR |
 			    HSSR0_RAB | HSSR0_FRE;
 	} else if (port->mapbase == _Ser3UTCR0) {
-		GPDR &= ~(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS);
-		GPDR |= GPIO_H3600_COM_RTS;
 		set_GPIO_IRQ_edge(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS,
 				  GPIO_BOTH_EDGES);
 
@@ -193,16 +471,17 @@
 	set_mctrl:	h3600_uart_set_mctrl,
 	get_mctrl:	h3600_uart_get_mctrl,
 	pm:		h3600_uart_pm,
+	set_wake:	h3600_uart_set_wake,
 	open:		h3600_uart_open,
 	close:		h3600_uart_close,
 };
 
 static struct map_desc h3600_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
-  { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
-  { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
+ /* virtual	       physical    length      domain	  r  w	c  b */
+  { 0xe8000000,        0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 	 CS#0 */
+  { H3600_EGPIO_VIRT,  0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0		 CS#5 */
+  { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2  CS#2 */
+  { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4  CS#4 */
   LAST_DESC
 };
 
@@ -214,13 +493,19 @@
 	sa1100_register_uart_fns(&h3600_port_fns);
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */
-	init_h3600_egpio();
 
 	/*
-	 * Default GPIO settings.
+	 * Default GPIO settings.  Should be set by machine
 	 */
 	GPCR = 0x0fffffff;
-	GPDR = 0x0401f3fc;
+//	GPDR = 0x0401f3fc;
+	GPDR = GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
+	       GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
+	       GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
+	       GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+	       GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+
+	init_h3600_egpio();
 
 	/*
 	 * Ensure those pins are outputs and driving low.
@@ -230,11 +515,24 @@
 
 	/* Configure suspend conditions */
 	PGSR = 0;
-	PWER = 0x1 | (1 << 31);
-	PCFR = PCFR_OPDE | PCFR_FP | PCFR_FS;
+	PWER = PWER_GPIO0 | PWER_RTC;
+	PCFR = PCFR_OPDE;
+	PSDR = 0;
 }
 
-MACHINE_START(H3600, "Compaq iPAQ")
+MACHINE_START(H3600, "Compaq iPAQ H3600")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(h3600_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
+MACHINE_START(H3100, "Compaq iPAQ H3100")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(h3600_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
+MACHINE_START(H3800, "Compaq iPAQ H3800")
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	BOOT_PARAMS(0xc0000100)
 	MAPIO(h3600_map_io)
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/huw_webpanel.c linux-2.4.19-pre5/arch/arm/mach-sa1100/huw_webpanel.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/huw_webpanel.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/huw_webpanel.c	Fri Mar 29 14:49:19 2002
@@ -2,8 +2,6 @@
  * linux/arch/arm/mach-sa1100/huw_webpanel.c
  *
  */
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -55,8 +53,8 @@
 **/
 static struct map_desc huw_webpanel_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0, neccessary for mtd */
-  { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 1, 1, 0, 0 }, /* Parameter */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0, neccessary for mtd */
+  { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 0, 1, 0, 0 }, /* Parameter */
   { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */
   LAST_DESC
 };
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/irq.c linux-2.4.19-pre5/arch/arm/mach-sa1100/irq.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/irq.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/irq.c	Fri Mar 29 14:49:19 2002
@@ -9,12 +9,11 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/ioport.h>
 #include <linux/ptrace.h>
 
 #include <asm/hardware.h>
@@ -35,8 +34,13 @@
 static int GPIO_IRQ_rising_edge;
 static int GPIO_IRQ_falling_edge;
 
-void set_GPIO_IRQ_edge( int gpio_mask, int edge )
+void set_GPIO_IRQ_edge(int gpio_mask, int edge)
 {
+	long flags;
+	int irq = 0;
+
+	gpio_mask &= 0x0fffffff;
+	local_irq_save(flags);
 	if (edge & GPIO_FALLING_EDGE)
 		GPIO_IRQ_falling_edge |= gpio_mask;
 	else
@@ -45,6 +49,17 @@
 		GPIO_IRQ_rising_edge |= gpio_mask;
 	else
 		GPIO_IRQ_rising_edge &= ~gpio_mask;
+	GPDR &= ~gpio_mask;
+	GAFR &= ~gpio_mask;
+	while (gpio_mask) {
+		if (irq == 11)
+			irq = IRQ_GPIO11;
+		if (gpio_mask & 1)
+			irq_desc[irq].valid = 1;
+		irq++;
+		gpio_mask >>= 1;
+	}
+	local_irq_restore(flags);
 }
 
 EXPORT_SYMBOL(set_GPIO_IRQ_edge);
@@ -121,7 +136,7 @@
 
 		for (i = 11; i <= 27; ++i) {
 			if (irq & (1<<i)) {
-				do_IRQ (IRQ_GPIO_11_27(i), regs);
+				do_IRQ(IRQ_GPIO11 + i - 11, regs);
 			}
 		}
 	}
@@ -175,11 +190,18 @@
 	GFER = (GFER & ~mask) | (GPIO_IRQ_falling_edge & mask);
 }
 
+static struct resource irq_resource = {
+	name:	"irqs",
+	start:	0x90050000,
+	end:	0x9005ffff,
+};
 
 void __init sa1100_init_irq(void)
 {
 	int irq;
 
+	request_resource(&iomem_resource, &irq_resource);
+
 	/* disable all IRQs */
 	ICMR = 0;
 
@@ -197,8 +219,13 @@
 	 */
 	ICCR = 1;
 
+	/*
+	 * Note: GPIO IRQs are initially invalid until at least one call
+	 * to set_GPIO_IRQ_edge() is performed.
+	 */
+
 	for (irq = 0; irq <= 10; irq++) {
-		irq_desc[irq].valid	= 1;
+		irq_desc[irq].valid	= 0;
 		irq_desc[irq].probe_ok	= 1;
 		irq_desc[irq].mask_ack	= sa1100_mask_and_ack_GPIO0_10_irq;
 		irq_desc[irq].mask	= sa1100_mask_GPIO0_10_irq;
@@ -214,7 +241,7 @@
 	}
 
 	for (irq = 32; irq <= 48; irq++) {
-		irq_desc[irq].valid	= 1;
+		irq_desc[irq].valid	= 0;
 		irq_desc[irq].probe_ok	= 1;
 		irq_desc[irq].mask_ack	= sa1100_mask_and_ack_GPIO11_27_irq;
 		irq_desc[irq].mask	= sa1100_mask_GPIO11_27_irq;
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/itsy.c linux-2.4.19-pre5/arch/arm/mach-sa1100/itsy.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/itsy.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/itsy.c	Fri Mar 29 14:49:19 2002
@@ -31,8 +31,8 @@
    likely wrong. */
 static struct map_desc itsy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/jornada720.c linux-2.4.19-pre5/arch/arm/mach-sa1100/jornada720.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/jornada720.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/jornada720.c	Fri Mar 29 14:49:19 2002
@@ -37,20 +37,17 @@
 	SKCR = JORSKCR_INIT;	/* Turn on the PLL, enable Ready and enable nOE assertion from DC */
 	mdelay(100);
 
-	SKCR = JORSKCR_RCLK;	/* turn on the RCLOCK */
-	SMCR = 0x35;	/* initialize the SMC (debug SA-1111 reset */
-	PCCR = 0;	/* initialize the S2MC (debug SA-1111 reset) */
+	SBI_SKCR = JORSKCR_RCLK;/* turn on the RCLOCK */
+	SBI_SMCR = 0x35;	/* initialize the SMC (debug SA-1111 reset */
+	PCCR = 0;		/* initialize the S2MC (debug SA-1111 reset) */
 
 	/* LDD4 is speaker, LDD3 is microphone */
 	PPSR &= ~(PPC_LDD3 | PPC_LDD4);
 	PPDR |= PPC_LDD3 | PPC_LDD4;
 
 	/* initialize extra IRQs */
-	set_GPIO_IRQ_edge(GPIO_GPIO(1), GPIO_RISING_EDGE);
-	sa1111_init_irq(SA1100_GPIO_TO_IRQ(1));	/* chained on GPIO 1 */
-
-	sa1100_register_uart(0, 3);
-	sa1100_register_uart(1, 1);
+	set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
+	sa1111_init_irq(IRQ_GPIO1);	/* chained on GPIO 1 */
 
 	return 0;
 }
@@ -68,10 +65,10 @@
 
 static struct map_desc jornada720_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson registers */
-  { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson frame buffer */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson registers */
+  { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson frame buffer */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
@@ -79,6 +76,9 @@
 {
 	sa1100_map_io();
 	iotable_init(jornada720_io_desc);
+	
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1);
 }
 
 MACHINE_START(JORNADA720, "HP Jornada 720")
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/lart.c linux-2.4.19-pre5/arch/arm/mach-sa1100/lart.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/lart.c	Sun Aug 12 17:36:24 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/lart.c	Fri Mar 29 14:49:19 2002
@@ -18,8 +18,8 @@
 
 static struct map_desc lart_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
-  { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */
+  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
+  { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */
   LAST_DESC
 };
 
@@ -31,6 +31,7 @@
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
 	sa1100_register_uart(2, 2);
+
 	GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
 	GPDR |= GPIO_UART_TXD;
 	GPDR &= ~GPIO_UART_RXD;
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-assabet.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-assabet.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-assabet.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-assabet.c	Fri Mar 29 14:49:19 2002
@@ -42,6 +42,8 @@
 
 	case led_stop:
 		led_state &= ~LED_STATE_ENABLED;
+		hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
+		ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
 		break;
 
 	case led_claim:
@@ -107,8 +109,7 @@
 	}
 
 	if  (led_state & LED_STATE_ENABLED)
-		ASSABET_BCR = BCR_value = (BCR_value & ~ASSABET_BCR_LED_MASK) |
-			hw_led_state;
+		ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
 
 	local_irq_restore(flags);
 }
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-flexanet.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-flexanet.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-flexanet.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-flexanet.c	Fri Mar 29 14:49:19 2002
@@ -35,7 +35,7 @@
 	switch (evt) {
 	case led_start:
 		/* start using LEDs and enable its hardware */
-		hw_led_bcr = BCR_LED_GREEN;
+		hw_led_bcr = FHH_BCR_LED_GREEN;
 		hw_led_gpio = GPIO_LED_RED;
 		led_state = LED_STATE_ENABLED;
 		break;
@@ -71,13 +71,13 @@
 	case led_idle_start:
 		/* turn off CPU load LED */
 		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_bcr &= ~BCR_LED_GREEN;
+			hw_led_bcr &= ~FHH_BCR_LED_GREEN;
 		break;
 
 	case led_idle_end:
 		/* turn on CPU load LED */
 		if (!(led_state & LED_STATE_CLAIMED))
-			hw_led_bcr |= BCR_LED_GREEN;
+			hw_led_bcr |= FHH_BCR_LED_GREEN;
 		break;
 #endif
 
@@ -88,12 +88,12 @@
 	/* direct LED access (must be previously claimed) */
 	case led_green_on:
 		if (led_state & LED_STATE_CLAIMED)
-			hw_led_bcr |= BCR_LED_GREEN;
+			hw_led_bcr |= FHH_BCR_LED_GREEN;
 		break;
 
 	case led_green_off:
 		if (led_state & LED_STATE_CLAIMED)
-			hw_led_bcr &= ~BCR_LED_GREEN;
+			hw_led_bcr &= ~FHH_BCR_LED_GREEN;
 		break;
 
 	case led_amber_on:
@@ -119,7 +119,7 @@
 	if  (led_state & LED_STATE_ENABLED)
 	{
 		/* update LEDs */
-		BCR = BCR_value = (BCR_value & ~BCR_LED_GREEN) | hw_led_bcr;
+		FHH_BCR = flexanet_BCR = (flexanet_BCR & ~FHH_BCR_LED_GREEN) | hw_led_bcr;
 		GPSR = hw_led_gpio;
 		GPCR = hw_led_gpio ^ GPIO_LED_RED;
 	}
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-frodo.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-frodo.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-frodo.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-frodo.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,121 @@
+
+/*
+ * linux/arch/arm/mach-sa1100/leds-frodo.c
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * This file contains the 2d3D, Inc. SA-1110 Development Board LED
+ * event handler.
+ *
+ * Frodo LEDs
+ *
+ *   - led6 - toggles state every 50 timer interrupts (Heartbeat)
+ *   - led7 - on if system is not idle (CPU load)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include "leds.h"
+
+#define led6_on() FRODO_CPLD_GENERAL |= FRODO_LED2
+#define led6_off() FRODO_CPLD_GENERAL &= ~FRODO_LED2
+#define led6_invert() do {						\
+		if ((FRODO_CPLD_GENERAL & FRODO_LED2))	\
+			led6_off ();						\
+		else									\
+			led6_on ();							\
+	} while (0)
+
+#define led7_on() FRODO_CPLD_GENERAL |= FRODO_LED1
+#define led7_off() FRODO_CPLD_GENERAL &= ~FRODO_LED1
+#define led7_invert() do {						\
+		if ((FRODO_CPLD_GENERAL & FRODO_LED1))	\
+			led7_off ();						\
+		else									\
+			led7_on ();							\
+	} while (0)
+
+static int claimed;
+
+void frodo_leds_event (led_event_t evt)
+{
+   unsigned long flags;
+
+   local_irq_save (flags);
+
+   switch (evt)
+	 {
+#ifdef CONFIG_LEDS_CPU
+		/* turn off CPU load LED */
+	  case led_idle_start:
+		if (!claimed) led7_off ();
+		break;
+
+		/* turn on CPU load LED */
+	  case led_idle_end:
+		if (!claimed) led7_on ();
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_TIMER
+		/* toggle heartbeat LED */
+	  case led_timer:
+		if (!claimed) led6_invert ();
+		break;
+#endif
+
+		/* start: turn on LEDs and set claimed to 0 */
+	  case led_start:
+		led6_on ();
+		led7_on ();
+		claimed = 0;
+		break;
+
+		/* stop: turn off LEDs */
+	  case led_stop:
+		led6_off ();
+		led7_off ();
+		break;
+
+		/* override CPU load & timer LEDs */
+	  case led_claim:
+		claimed = 1;
+		break;
+
+		/* restore CPU load & timer LEDs */
+	  case led_release:
+		claimed = 0;
+		break;
+
+		/* direct LED access (must be previously claimed) */
+
+		/* led7 */
+	  case led_green_on:
+		if (claimed) led7_on ();
+		break;
+
+	  case led_green_off:
+		if (claimed) led7_off ();
+		break;
+
+		/* led6 -- at the moment this is actually also green */
+	  case led_red_on:
+		if (claimed) led6_on ();
+		break;
+
+	  case led_red_off:
+		if (claimed) led6_off ();
+		break;
+
+	  default:
+		break;
+	}
+
+   local_irq_restore (flags);
+}
+
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-system3.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-system3.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/leds-system3.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds-system3.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-sa1100/leds-system3.c
+ *
+ * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@gmx.de>
+ *
+ * Original (leds-footbridge.c) by Russell King
+ *
+ * $Id: leds-system3.c,v 1.1.6.1 2001/12/04 15:19:26 seletz Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Log: leds-system3.c,v $
+ * Revision 1.1.6.1  2001/12/04 15:19:26  seletz
+ * - merged from linux_2_4_13_ac5_rmk2
+ *
+ * Revision 1.1.4.2  2001/11/19 17:58:53  seletz
+ * - cleanup
+ *
+ * Revision 1.1.4.1  2001/11/16 13:49:54  seletz
+ * - dummy LED support for PT Digital Board
+ *
+ * Revision 1.1.2.1  2001/10/15 16:03:39  seletz
+ * - dummy function
+ *
+ *
+ */
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include "leds.h"
+
+
+#define LED_STATE_ENABLED	1
+#define LED_STATE_CLAIMED	2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+void system3_leds_event(led_event_t evt)
+{
+	/* TODO: support LEDs */
+}
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/leds.c linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/leds.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.c	Fri Mar 29 14:49:19 2002
@@ -5,7 +5,6 @@
  * 
  * Copyright (C) 2001 Nicolas Pitre
  */
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/leds.h>
@@ -16,24 +15,30 @@
 static int __init
 sa1100_leds_init(void)
 {
+	if (machine_is_adsbitsy())
+		leds_event = adsbitsy_leds_event;
 	if (machine_is_assabet())
 		leds_event = assabet_leds_event;
+ 	if (machine_is_consus())
+ 	        leds_event = consus_leds_event;
 	if (machine_is_brutus())
 		leds_event = brutus_leds_event;
 	if (machine_is_cerf())
 		leds_event = cerf_leds_event;
 	if (machine_is_flexanet())
 		leds_event = flexanet_leds_event;
+	if (machine_is_frodo())
+		leds_event = frodo_leds_event;
 	if (machine_is_graphicsclient())
 		leds_event = graphicsclient_leds_event;
+	if (machine_is_graphicsmaster())
+		leds_event = graphicsmaster_leds_event;
 	if (machine_is_lart())
 		leds_event = lart_leds_event;
 	if (machine_is_pfs168())
 		leds_event = pfs168_leds_event;
-	if (machine_is_graphicsmaster())
-		leds_event = graphicsmaster_leds_event;
-	if (machine_is_adsbitsy())
-		leds_event = adsbitsy_leds_event;
+	if (machine_is_pt_system3())
+		leds_event = system3_leds_event;
 
 	leds_event(led_start);
 	return 0;
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/leds.h linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.h
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/leds.h	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/leds.h	Fri Mar 29 14:49:19 2002
@@ -1,4 +1,5 @@
 extern void assabet_leds_event(led_event_t evt);
+extern void consus_leds_event(led_event_t evt);
 extern void brutus_leds_event(led_event_t evt);
 extern void cerf_leds_event(led_event_t evt);
 extern void flexanet_leds_event(led_event_t evt);
@@ -7,3 +8,5 @@
 extern void pfs168_leds_event(led_event_t evt);
 extern void graphicsmaster_leds_event(led_event_t evt);
 extern void adsbitsy_leds_event(led_event_t evt);
+extern void system3_leds_event(led_event_t evt);
+extern void frodo_leds_event(led_event_t evt);
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/nanoengine.c linux-2.4.19-pre5/arch/arm/mach-sa1100/nanoengine.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/nanoengine.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/nanoengine.c	Fri Mar 29 14:49:19 2002
@@ -34,9 +34,9 @@
 
 static struct map_desc nanoengine_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
-  { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
+  { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Internal PCI Config Space */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/neponset.c linux-2.4.19-pre5/arch/arm/mach-sa1100/neponset.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/neponset.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/neponset.c	Fri Mar 29 14:49:19 2002
@@ -7,6 +7,8 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
 #include <linux/serial_core.h>
 
 #include <asm/hardware.h>
@@ -16,6 +18,7 @@
 #include <asm/arch/irq.h>
 #include <asm/mach/serial_sa1100.h>
 #include <asm/arch/assabet.h>
+#include <asm/hardware/sa1111.h>
 
 #include "sa1111.h"
 
@@ -40,10 +43,10 @@
 		if (!irr) break;
 
 		if( irr & IRR_ETHERNET )
-			do_IRQ(NEPONSET_ETHERNET_IRQ, regs);
+			do_IRQ(IRQ_NEPONSET_SMC9196, regs);
 
 		if( irr & IRR_USAR )
-			do_IRQ(NEPONSET_USAR_IRQ, regs);
+			do_IRQ(IRQ_NEPONSET_USAR, regs);
 
 		if( irr & IRR_SA1111 )
 			sa1111_IRQ_demux(irq, dev_id, regs);
@@ -58,19 +61,16 @@
 
 static void __init neponset_init_irq(void)
 {
-	int irq;
-
 	sa1111_init_irq(-1);	/* SA1111 IRQ not routed to a GPIO */
 
 	/* setup extra Neponset IRQs */
-	irq = NEPONSET_ETHERNET_IRQ;
-	irq_desc[irq].valid	= 1;
-	irq_desc[irq].probe_ok	= 1;
-	irq = NEPONSET_USAR_IRQ;
-	irq_desc[irq].valid	= 1;
-	irq_desc[irq].probe_ok	= 1;
-	set_GPIO_IRQ_edge(ASSABET_GPIO_NEP_IRQ, GPIO_RISING_EDGE);
-	setup_arm_irq(ASSABET_IRQ_GPIO_NEP_IRQ, &neponset_irq);
+	irq_desc[IRQ_NEPONSET_SMC9196].valid	= 1;
+	irq_desc[IRQ_NEPONSET_SMC9196].probe_ok	= 1;
+	irq_desc[IRQ_NEPONSET_USAR].valid	= 1;
+	irq_desc[IRQ_NEPONSET_USAR].probe_ok	= 1;
+
+	set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE);
+	setup_arm_irq(IRQ_GPIO25, &neponset_irq);
 }
 
 static int __init neponset_init(void)
@@ -102,6 +102,11 @@
 	}
 
 	/*
+	 * Disable GPIO 0/1 drivers so the buttons work on the module.
+	 */
+	NCR_0 |= NCR_GP01_OFF;
+
+	/*
 	 * Neponset has SA1111 connected to CS4.  We know that after
 	 * reset the chip will be configured for variable latency IO.
 	 */
@@ -110,7 +115,7 @@
 	/*
 	 * Probe for a SA1111.
 	 */
-	ret = sa1111_probe();
+	ret = sa1111_probe(NEPONSET_SA1111_BASE);
 	if (ret < 0)
 		return ret;
 
@@ -150,8 +155,8 @@
 
 static struct map_desc neponset_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
@@ -184,7 +189,7 @@
 	MDM_CTL_0 = mdm_ctl0;
 }
 
-static int neponset_get_mctrl(struct uart_port *port)
+static u_int neponset_get_mctrl(struct uart_port *port)
 {
 	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
 	u_int mdm_ctl1 = MDM_CTL_1;
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/omnimeter.c linux-2.4.19-pre5/arch/arm/mach-sa1100/omnimeter.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/omnimeter.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/omnimeter.c	Fri Mar 29 14:49:19 2002
@@ -30,7 +30,7 @@
 
 static struct map_desc omnimeter_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* TS */
+  { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* TS */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/pangolin.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pangolin.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/pangolin.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pangolin.c	Fri Mar 29 14:49:19 2002
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-sa1100/pangolin.c
  */
-
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
@@ -30,8 +30,8 @@
 
 static struct map_desc pangolin_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
+  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
   LAST_DESC
 };
 
@@ -43,6 +43,12 @@
 	sa1100_register_uart(0, 1);
 	sa1100_register_uart(1, 3);
 	Ser1SDCR0 |= SDCR0_UART;
+
+	/* set some GPDR bits while it's safe */
+	GPDR |= GPIO_PCMCIA_RESET;
+#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+	GPDR |= GPIO_PCMCIA_BUS_ON;
+#endif
 }
 
 MACHINE_START(PANGOLIN, "Dialogue-Pangolin")
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/pfs168.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pfs168.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/pfs168.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pfs168.c	Fri Mar 29 14:49:19 2002
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-sa1100/pfs168.c
  */
-
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
@@ -34,7 +34,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	ret = sa1111_probe();
+	ret = sa1111_probe(PFS168_SA1111_BASE);
 	if (ret < 0)
 		return ret;
 
@@ -65,8 +65,7 @@
 	 */
 	sa1110_mb_enable();
 
-	set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE);
-	sa1111_init_irq(SA1100_GPIO_TO_IRQ(25));	/* SA1111 IRQ on GPIO 25 */
+	sa1111_init_irq(IRQ_GPIO25);	/* SA1111 IRQ on GPIO 25 */
 
 	return 0;
 }
@@ -84,6 +83,8 @@
 	 */
 	set_GPIO_IRQ_edge(GPIO_GPIO(19), GPIO_RISING_EDGE);
 	set_GPIO_IRQ_edge(GPIO_GPIO(20), GPIO_RISING_EDGE);
+	set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE);
+	set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE);
 }
 
 
@@ -101,20 +102,20 @@
 
 static struct map_desc pfs168_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */
-  { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */
-  { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */
-  { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Status LED control (SYSLED) */
-  { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */
-  { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */
-  { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */
-  { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */
-  { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register A (SYSCTLA) */
-  { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register B (SYSCTLB) */
-  { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* SMC91C96 */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */
+  { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */
+  { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */
+  { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Status LED control (SYSLED) */
+  { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */
+  { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */
+  { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */
+  { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */
+  { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register A (SYSCTLA) */
+  { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register B (SYSCTLB) */
+  { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* SMC91C96 */
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/pleb.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pleb.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/pleb.c	Sun Aug 12 17:36:24 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pleb.c	Fri Mar 29 14:49:19 2002
@@ -35,8 +35,8 @@
 
 static struct map_desc pleb_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
-  { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */
+  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
+  { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/pm.c linux-2.4.19-pre5/arch/arm/mach-sa1100/pm.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/pm.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/pm.c	Fri Mar 29 14:49:19 2002
@@ -19,30 +19,27 @@
  * 			Cleaned up, pushed platform dependent stuff
  * 			in the platform specific files.
  */
-
-/*
- * Debug macros
- */
-#define DEBUG 1
-#ifdef DEBUG
-#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
-#else
-#  define DPRINTK(fmt, args...)
-#endif
-
-
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
 #include <linux/sysctl.h>
-#include <linux/acpi.h>
+#include <linux/errno.h>
 
 #include <asm/hardware.h>
 #include <asm/memory.h>
 #include <asm/system.h>
+#include <asm/leds.h>
 
 #include "sleep.h"
 
+/*
+ * Debug macros
+ */
+#undef DEBUG
+
 extern void sa1100_cpu_suspend(void);
 extern void sa1100_cpu_resume(void);
 
@@ -54,22 +51,17 @@
 
 int pm_do_suspend(void)
 {
-	int retval;
-
 	/* set up pointer to sleep parameters */
-	sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC);
+	sleep_save = kmalloc(SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC);
 	if (!sleep_save)
 		return -ENOMEM;
-	sleep_save_p = virt_to_phys(sleep_save);
 
-	retval = pm_send_all(PM_SUSPEND, (void *)2);
-	if (retval) {
-		kfree(sleep_save);
-		return retval;
-	}
+	sleep_save_p = virt_to_phys(sleep_save);
 
 	cli();
 
+	leds_event(led_stop);
+
 	/* preserve current time */
 	RCNR = xtime.tv_sec;
 
@@ -112,7 +104,9 @@
 	/* ensure not to come back here if it wasn't intended */
 	PSPR = 0;
 
-	DPRINTK("*** made it back from resume\n");
+#ifdef DEBUG
+	printk(KERN_DEBUG "*** made it back from resume\n");
+#endif
 
 	/* restore registers */
 	RESTORE(GPDR);
@@ -146,21 +140,55 @@
 	/* restore current time */
 	xtime.tv_sec = RCNR;
 
+	leds_event(led_start);
+
 	sti();
 
 	kfree (sleep_save);
 
-	retval = pm_send_all(PM_RESUME, (void *)0);
-	if (retval)
-		return retval;
+	/*
+	 * Restore the CPU frequency settings.
+	 */
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_restore();
+#endif
 
 	return 0;
 }
 
+#ifdef CONFIG_SYSCTL
+/*
+ * ARGH!  ACPI people defined CTL_ACPI in linux/acpi.h rather than
+ * linux/sysctl.h.
+ *
+ * This means our interface here won't survive long - it needs a new
+ * interface.  Quick hack to get this working - use sysctl id 9999.
+ */
+#warning ACPI broke the kernel, this interface needs to be fixed up.
+#define CTL_ACPI 9999
+#define ACPI_S1_SLP_TYP 19
+
+/*
+ * Send us to sleep.
+ */
+static int sysctl_pm_do_suspend(void)
+{
+	int retval;
+
+	retval = pm_send_all(PM_SUSPEND, (void *)3);
+
+	if (retval == 0) {
+		retval = pm_do_suspend();
+
+		pm_send_all(PM_RESUME, (void *)0);
+	}
+
+	return retval;
+}
 
 static struct ctl_table pm_table[] =
 {
-	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&pm_do_suspend},
+	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
 	{0}
 };
 
@@ -181,3 +209,4 @@
 
 __initcall(pm_init);
 
+#endif
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/sa1111-pcibuf.c linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111-pcibuf.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/sa1111-pcibuf.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111-pcibuf.c	Fri Mar 29 14:49:19 2002
@@ -13,7 +13,6 @@
  *
  *  06/13/2001 - created.
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/sa1111.c linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/sa1111.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.c	Fri Mar 29 14:49:19 2002
@@ -15,6 +15,7 @@
  * All initialization functions provided here are intended to be called
  * from machine specific code with proper arguments when required.
  */
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -22,57 +23,80 @@
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
+#include <linux/ioport.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/arch/irq.h>
 
+#include <asm/hardware/sa1111.h>
+
 #include "sa1111.h"
 
+struct resource sa1111_resource = {
+	name:	"SA1111",
+};
+
+EXPORT_SYMBOL(sa1111_resource);
+
 /*
- * SA1111  Interrupt support
+ * SA1111 interrupt support
  */
-
-void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int i;
 	unsigned long stat0, stat1;
 
-	for(;;) {
-		stat0 = INTSTATCLR0, stat1 = INTSTATCLR1;
-		if( !stat0 && !stat1 ) break;
-		if( stat0 )
-			for( i = 0; i < 32; i++ )
-				if( stat0 & (1<<i) )
-					do_IRQ( SA1111_IRQ(i), regs );
-
-		if( stat1 )
-			for( i = 32; i < 55; i++ )
-				if( stat1 & (1<<(i-32)) )
-					do_IRQ( SA1111_IRQ(i), regs );
+	while (1) {
+		int i;
+
+		stat0 = INTSTATCLR0;
+		stat1 = INTSTATCLR1;
+
+		if (stat0 == 0 && stat1 == 0)
+			break;
+
+		for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1)
+			if (stat0 & 1)
+				do_IRQ(i, regs);
+
+		for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
+			if (stat1 & 1)
+				do_IRQ(i, regs);
 	}
 }
 
-static struct irqaction sa1111_irq = {
-	name:		"SA1111",
-	handler:	sa1111_IRQ_demux,
-	flags:		SA_INTERRUPT
-};
+#define SA1111_IRQMASK_LO(x)	(1 << (x - IRQ_SA1111_START))
+#define SA1111_IRQMASK_HI(x)	(1 << (x - IRQ_SA1111_START - 32))
 
+/*
+ * A note about masking IRQs:
+ *
+ * The GPIO IRQ edge detection only functions while the IRQ itself is
+ * enabled; edges are not detected while the IRQ is disabled.
+ *
+ * This is especially important for the PCMCIA signals, where we must
+ * pick up every transition.  We therefore do not disable the IRQs
+ * while processing them.
+ *
+ * However, since we are changed to a GPIO on the host processor,
+ * all SA1111 IRQs will be disabled while we're processing any SA1111
+ * IRQ.
+ *
+ * Note also that changing INTPOL while an IRQ is enabled will itself
+ * trigger an IRQ.
+ */
 static void sa1111_mask_and_ack_lowirq(unsigned int irq)
 {
-	unsigned int mask = 1 << (irq - SA1111_IRQ(0));
+	unsigned int mask = SA1111_IRQMASK_LO(irq);
 
-	// broken hardware: interrupt events are lost if they occur
-	// while the interrupts are disabled.
 	//INTEN0 &= ~mask;
 	INTSTATCLR0 = mask;
 }
 
 static void sa1111_mask_and_ack_highirq(unsigned int irq)
 {
-	unsigned int mask = 1 << (irq - SA1111_IRQ(32));
+	unsigned int mask = SA1111_IRQMASK_HI(irq);
 
 	//INTEN1 &= ~mask;
 	INTSTATCLR1 = mask;
@@ -80,27 +104,29 @@
 
 static void sa1111_mask_lowirq(unsigned int irq)
 {
-	//INTEN0 &= ~(1 << (irq - SA1111_IRQ(0)));
+	INTEN0 &= ~SA1111_IRQMASK_LO(irq);
 }
 
 static void sa1111_mask_highirq(unsigned int irq)
 {
-	//INTEN1 &= ~(1 << (irq - SA1111_IRQ(32)));
+	INTEN1 &= ~SA1111_IRQMASK_HI(irq);
 }
 
 static void sa1111_unmask_lowirq(unsigned int irq)
 {
-	INTEN0 |= 1 << (irq - SA1111_IRQ(0));
+	INTEN0 |= SA1111_IRQMASK_LO(irq);
 }
 
 static void sa1111_unmask_highirq(unsigned int irq)
 {
-	INTEN1 |= 1 << ((irq - SA1111_IRQ(32)));
+	INTEN1 |= SA1111_IRQMASK_HI(irq);
 }
 
 void __init sa1111_init_irq(int irq_nr)
 {
-	int irq;
+	int irq, ret;
+
+	request_mem_region(_INTTEST0, 512, "irqs");
 
 	/* disable all IRQs */
 	INTEN0 = 0;
@@ -111,21 +137,21 @@
 	 * specifies that S0ReadyInt and S1ReadyInt should be '1'.
 	 */
 	INTPOL0 = 0;
-	INTPOL1 = 1 << (S0_READY_NINT - SA1111_IRQ(32)) |
-		  1 << (S1_READY_NINT - SA1111_IRQ(32));
+	INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) |
+		  SA1111_IRQMASK_HI(S1_READY_NINT);
 
 	/* clear all IRQs */
 	INTSTATCLR0 = -1;
 	INTSTATCLR1 = -1;
 
-	for (irq = SA1111_IRQ(0); irq <= SA1111_IRQ(26); irq++) {
+	for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
 		irq_desc[irq].valid	= 1;
 		irq_desc[irq].probe_ok	= 0;
 		irq_desc[irq].mask_ack	= sa1111_mask_and_ack_lowirq;
 		irq_desc[irq].mask	= sa1111_mask_lowirq;
 		irq_desc[irq].unmask	= sa1111_unmask_lowirq;
 	}
-	for (irq = SA1111_IRQ(32); irq <= SA1111_IRQ(54); irq++) {
+	for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) {
 		irq_desc[irq].valid	= 1;
 		irq_desc[irq].probe_ok	= 0;
 		irq_desc[irq].mask_ack	= sa1111_mask_and_ack_highirq;
@@ -134,28 +160,60 @@
 	}
 
 	/* Register SA1111 interrupt */
-	if (irq_nr >= 0)
-		setup_arm_irq(irq_nr, &sa1111_irq);
+	if (irq_nr < 0)
+		return;
+
+	ret = request_irq(irq_nr, sa1111_IRQ_demux, SA_INTERRUPT,
+			  "SA1111", NULL);
+	if (ret < 0)
+		printk(KERN_ERR "SA1111: unable to claim IRQ%d: %d\n",
+		       irq_nr, ret);
 }
 
-/*
- * Probe for a SA1111 chip.
+/**
+ *	sa1111_probe - probe for a single SA1111 chip.
+ *	@phys_addr: physical address of device.
+ *
+ *	Probe for a SA1111 chip.  This must be called
+ *	before any other SA1111-specific code.
+ *
+ *	Returns:
+ *	%-ENODEV	device not found.
+ *	%-EBUSY		physical address already marked in-use.
+ *	%0		successful.
  */
-
-int __init sa1111_probe(void)
+int __init sa1111_probe(unsigned long phys_addr)
 {
-	unsigned long id = SBI_SKID;
+	unsigned long id;
 	int ret = -ENODEV;
 
-	if ((id & SKID_ID_MASK) == SKID_SA1111_ID) {
-		printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: "
-			"silicon revision %lx, metal revision %lx\n",
-			(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
-		ret = 0;
-	} else {
-		printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id);
+	sa1111_resource.start = phys_addr;
+	sa1111_resource.end = phys_addr + 0x2000;
+
+	if (request_resource(&iomem_resource, &sa1111_resource)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/*
+	 * Probe for the chip.  Only touch the SBI registers.
+	 */
+	id = SBI_SKID;
+	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
+		printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
+		ret = -ENODEV;
+		goto release;
 	}
 
+	printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
+		"silicon revision %lx, metal revision %lx\n",
+		(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
+
+	return 0;
+
+ release:
+	release_resource(&sa1111_resource);
+ out:
 	return ret;
 }
 
@@ -175,6 +233,10 @@
  */
 void sa1111_wake(void)
 {
+	unsigned long flags;
+
+	local_irq_save(flags);
+
 	/*
 	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
 	 * (SA-1110 Developer's Manual, section 9.1.2.1)
@@ -210,6 +272,8 @@
 	 * Ensure all clocks are initially off.
 	 */
 	SKPCR = 0;
+
+	local_irq_restore(flags);
 }
 
 void sa1111_doze(void)
@@ -242,12 +306,17 @@
  */
 void __init sa1110_mb_disable(void)
 {
+	unsigned long flags;
+
+	local_irq_save(flags);
+	
 	PGSR &= ~GPIO_MBGNT;
 	GPCR = GPIO_MBGNT;
 	GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
 
 	GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ);
 
+	local_irq_restore(flags);
 }
 
 /*
@@ -256,10 +325,19 @@
  */
 void __init sa1110_mb_enable(void)
 {
+	unsigned long flags;
+
+	local_irq_save(flags);
+
 	PGSR &= ~GPIO_MBGNT;
 	GPCR = GPIO_MBGNT;
 	GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
 
 	GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
 	TUCR |= TUCR_MR;
+
+	local_irq_restore(flags);
 }
+
+EXPORT_SYMBOL(sa1111_wake);
+EXPORT_SYMBOL(sa1111_doze);
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/sa1111.h linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.h
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/sa1111.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sa1111.h	Fri Mar 29 14:49:19 2002
@@ -11,7 +11,7 @@
 /*
  * Probe for a SA1111 chip.
  */
-extern int sa1111_probe(void);
+extern int sa1111_probe(unsigned long phys);
 
 /*
  * Wake up a SA1111 chip.
@@ -30,5 +30,5 @@
 
 
 extern void sa1111_init_irq(int irq_nr);
-extern void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs );
+extern void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs);
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/shannon.c linux-2.4.19-pre5/arch/arm/mach-sa1100/shannon.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/shannon.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/shannon.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-sa1100/shannon.c
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include "generic.h"
+
+
+static struct map_desc shannon_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
+  LAST_DESC
+};
+
+static void __init shannon_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(shannon_io_desc);
+
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1);
+	Ser1SDCR0 |= SDCR0_SUS;
+	GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
+	GPDR |= GPIO_UART_TXD;
+	GPDR &= ~GPIO_UART_RXD;
+	PPAR |= PPAR_UPR;
+
+	set_GPIO_IRQ_edge(SHANNON_GPIO_IRQ_CODEC);
+}
+
+MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(shannon_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/sherman.c linux-2.4.19-pre5/arch/arm/mach-sa1100/sherman.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/sherman.c	Sun Aug 12 17:36:24 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/sherman.c	Fri Mar 29 14:49:19 2002
@@ -31,7 +31,7 @@
 
 static struct map_desc sherman_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash*/
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash*/
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/simpad.c linux-2.4.19-pre5/arch/arm/mach-sa1100/simpad.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/simpad.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/simpad.c	Fri Mar 29 14:49:19 2002
@@ -23,18 +23,6 @@
 
 long cs3_shadow;
 
-static int __init simpad_init(void)
-{
-	PSPR = 0xc0008000;
-	GPDR &= ~GPIO_GPIO0;
-	cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON | 
-		      ENABLE_5V | RESET_SIMCARD);
-	*(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
-	return 0;
-}
-
-__initcall(simpad_init);
-
 long get_cs3_shadow()
 {
 	return cs3_shadow;
@@ -70,8 +58,8 @@
 
 static struct map_desc simpad_io_desc[] __initdata = {
   /* virtual	physical    length	domain	   r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, 
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */  
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, 
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */  
   { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */
   LAST_DESC
 };
@@ -96,11 +84,17 @@
 	sa1100_map_io();
 	iotable_init(simpad_io_desc);
 
-#ifndef CONFIG_SERIAL_SA1100_OLD
+	PSPR = 0xc0008000;
+	GPDR &= ~GPIO_GPIO0;
+	cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON | 
+		      ENABLE_5V | RESET_SIMCARD);
+	*(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
+
 	//It is only possible to register 3 UART in serial_sa1100.c
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
-#endif
+
+	set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE);
 }
 
 #ifdef CONFIG_PROC_FS
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/system3.c linux-2.4.19-pre5/arch/arm/mach-sa1100/system3.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/system3.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/system3.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,379 @@
+/*
+ * linux/arch/arm/mach-sa1100/system3.c
+ *
+ * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
+ *
+ * $Id: system3.c,v 1.1.6.1 2001/12/04 17:28:06 seletz Exp $
+ *
+ * This file contains all PT Sytsem 3 tweaks. Based on original work from
+ * Nicolas Pitre's assabet fixes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Log: system3.c,v $
+ * Revision 1.1.6.1  2001/12/04 17:28:06  seletz
+ * - merged from previous branch
+ *
+ * Revision 1.1.4.3  2001/12/04 15:16:31  seletz
+ * - merged from linux_2_4_13_ac5_rmk2
+ *
+ * Revision 1.1.4.2  2001/11/19 17:18:57  seletz
+ * - more code cleanups
+ *
+ * Revision 1.1.4.1  2001/11/16 13:52:05  seletz
+ * - PT Digital Board Support Code
+ *
+ * Revision 1.1.2.2  2001/11/05 16:46:18  seletz
+ * - cleanups
+ *
+ * Revision 1.1.2.1  2001/10/15 16:00:43  seletz
+ * - first revision working with new board
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include <asm/arch/irq.h>
+
+#include <linux/serial_core.h>
+
+#include "generic.h"
+#include "sa1111.h"
+
+#define DEBUG 1
+
+#ifdef DEBUG
+#	define DPRINTK( x, args... )	printk( "%s: line %d: "x, __FUNCTION__, __LINE__, ## args  );
+#else
+#	define DPRINTK( x, args... )	/* nix */
+#endif
+
+/**********************************************************************
+ *  prototypes
+ */
+
+/* init funcs */
+static void __init fixup_system3(struct machine_desc *desc,
+		struct param_struct *params, char **cmdline, struct meminfo *mi);
+static void __init get_system3_scr(void);
+static int __init system3_init(void);
+static void __init system3_init_irq(void);
+static void __init system3_map_io(void);
+
+static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs );
+static int system3_get_mctrl(struct uart_port *port);
+static void system3_set_mctrl(struct uart_port *port, u_int mctrl);
+static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate);
+static int sdram_notifier(struct notifier_block *nb, unsigned long event, void *data);
+
+extern void convert_to_tag_list(struct param_struct *params, int mem_init);
+
+
+/**********************************************************************
+ *  global data
+ */
+
+/**********************************************************************
+ *  static data
+ */
+
+static struct map_desc system3_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
+  LAST_DESC
+};
+
+static struct sa1100_port_fns system3_port_fns __initdata = {
+	set_mctrl:	system3_set_mctrl,
+	get_mctrl:	system3_get_mctrl,
+	pm:		system3_uart_pm,
+};
+
+static struct irqaction system3_irq = {
+	name:		"PT Digital Board SA1111 IRQ",
+	handler:	system3_IRQ_demux,
+	flags:		SA_INTERRUPT
+};
+
+static struct notifier_block system3_clkchg_block = {
+	notifier_call:	sdram_notifier,
+};
+
+/**********************************************************************
+ *  Static functions
+ */
+
+static void __init system3_map_io(void)
+{
+	DPRINTK( "%s\n", "START" );
+	sa1100_map_io();
+	iotable_init(system3_io_desc);
+
+	sa1100_register_uart_fns(&system3_port_fns);
+	sa1100_register_uart(0, 1);	/* com port */
+	sa1100_register_uart(1, 2);
+	sa1100_register_uart(2, 3);	/* radio module */
+
+	Ser1SDCR0 |= SDCR0_SUS;
+}
+
+
+/*********************************************************************
+ * Install IRQ handler
+ */
+static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+{
+	u_char irr;
+
+	for(;;){
+		//irr = PTCPLD_REG_IRQSR & (PT_IRQ_LAN | PT_IRQ_USAR | PT_IRQ_SA1111);
+		irr = PT_IRQSR & (PT_IRQ_LAN | PT_IRQ_SA1111);
+
+		irr ^= (PT_IRQ_LAN);
+		if (!irr) break;
+
+		if( irr & PT_IRQ_LAN )
+			do_IRQ(IRQ_SYSTEM3_SMC9196, regs);
+
+#if 0
+		/* Highspeed Serial Bus not yet used */
+		if( irr & PT_IRQ_USAR )
+			do_IRQ(PT_USAR_IRQ, regs);
+#endif
+
+		if( irr & PT_IRQ_SA1111 )
+			sa1111_IRQ_demux(irq, dev_id, regs);
+	}
+}
+
+
+static void __init system3_init_irq(void)
+{
+	int irq;
+
+	DPRINTK( "%s\n", "START" );
+
+	/* SA1111 IRQ not routed to a GPIO. */
+	sa1111_init_irq(-1);
+
+	/* setup extra IRQs */
+	irq = IRQ_SYSTEM3_SMC9196;
+	irq_desc[irq].valid	= 1;
+	irq_desc[irq].probe_ok	= 1;
+
+#if 0
+	/* Highspeed Serial Bus not yet used */
+	irq = PT_USAR_IRQ;
+	irq_desc[irq].valid	= 1;
+	irq_desc[irq].probe_ok	= 1;
+#endif
+
+	/* IRQ by CPLD */
+	set_GPIO_IRQ_edge( GPIO_GPIO(25), GPIO_RISING_EDGE );
+	setup_arm_irq( IRQ_GPIO25, &system3_irq );
+}
+
+/**********************************************************************
+ * On system 3 limit cpu frequency to 206 Mhz
+ */
+static int sdram_notifier(struct notifier_block *nb, unsigned long event,
+		void *data)
+{
+	switch (event) {
+		case CPUFREQ_MINMAX:
+			cpufreq_updateminmax(data, 147500, 206000);
+			break;
+
+	}
+	return 0;
+}
+
+/**
+ *	fixup_system3 - fixup function for system 3 board
+ *	@desc:		machine description
+ *	@param:		kernel params
+ *	@cmdline:	kernel cmdline
+ *	@mi:		memory info struct
+ *
+ */
+static void __init fixup_system3(struct machine_desc *desc,
+		struct param_struct *params, char **cmdline, struct meminfo *mi)
+{
+	DPRINTK( "%s\n", "START" );
+
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+	setup_ramdisk( 1, 0, 0, 8192 );
+	setup_initrd( 0xc0800000, 8*1024*1024 );
+}
+
+
+/**
+ *	system3_uart_pm - powermgmt callback function for system 3 UART
+ *	@port: uart port structure
+ *	@state: pm state
+ *	@oldstate: old pm state
+ *
+ */
+static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
+{
+	/* TODO: switch on/off uart in powersave mode */
+}
+
+/*
+ * Note! this can be called from IRQ context.
+ * FIXME: Handle PT Digital Board CTRL regs irq-safe.
+ *
+ * NB: system3 uses COM_RTS and COM_DTR for both UART1 (com port)
+ * and UART3 (radio module).  We only handle them for UART1 here.
+ */
+static void system3_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	if (port->mapbase == _Ser1UTCR0) {
+		u_int set = 0, clear = 0;
+
+		if (mctrl & TIOCM_RTS)
+			set |= PT_CTRL2_RS1_RTS;
+		else
+			clear |= PT_CTRL2_RS1_RTS;
+
+		if (mctrl & TIOCM_DTR)
+			set |= PT_CTRL2_RS1_DTR;
+		else
+			clear |= PT_CTRL2_RS1_DTR;
+
+		PTCTRL2_clear(clear);
+		PTCTRL2_set(set);
+	}
+}
+
+static int system3_get_mctrl(struct uart_port *port)
+{
+	u_int ret = 0;
+	u_int irqsr = PT_IRQSR;
+
+	/* need 2 reads to read current value */
+	irqsr = PT_IRQSR;
+
+	/* TODO: check IRQ source register for modem/com
+	 status lines and set them correctly. */
+
+	ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+
+	return ret;
+}
+
+static int __init system3_init(void)
+{
+	int ret = 0;
+	DPRINTK( "%s\n", "START" );
+
+	if ( !machine_is_pt_system3() ) {
+		ret = -EINVAL;
+		goto DONE;
+	}
+
+	/* init control register */
+	PT_CTRL0 = PT_CTRL0_INIT;
+	PT_CTRL1 = 0x02;
+	PT_CTRL2 = 0x00;
+	DPRINTK( "CTRL[0]=0x%02x\n", PT_CTRL0 );
+	DPRINTK( "CTRL[1]=0x%02x\n", PT_CTRL1 );
+	DPRINTK( "CTRL[2]=0x%02x\n", PT_CTRL2 );
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state.
+	 */
+	sa1110_mb_disable();
+
+	/*
+	 * Probe for a SA1111.
+	 */
+	ret = sa1111_probe(PT_SA1111_BASE);
+	if (ret < 0) {
+		printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" );
+		goto DONE;
+	}
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
+	SKPCR |= SKPCR_DCLKEN;
+
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	system3_init_irq();
+
+#if defined( CONFIG_CPU_FREQ )
+	ret = cpufreq_register_notifier(&system3_clkchg_block);
+	if ( ret != 0 ) {
+		printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" );
+		goto DONE;
+	}
+#endif
+
+	ret = 0;
+DONE:
+	DPRINTK( "ret=%d\n", ret );
+	return ret;
+}
+
+/**********************************************************************
+ *  Exported Functions
+ */
+
+/**********************************************************************
+ *  kernel magic macros
+ */
+__initcall(system3_init);
+
+MACHINE_START(PT_SYSTEM3, "PT System 3")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_system3)
+	MAPIO(system3_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/victor.c linux-2.4.19-pre5/arch/arm/mach-sa1100/victor.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/victor.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/victor.c	Fri Mar 29 14:49:19 2002
@@ -60,7 +60,7 @@
 
 static struct map_desc victor_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+  { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/xp860.c linux-2.4.19-pre5/arch/arm/mach-sa1100/xp860.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/xp860.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/xp860.c	Fri Mar 29 14:49:19 2002
@@ -21,6 +21,7 @@
 
 static void xp860_power_off(void)
 {
+	cli();
 	GPDR |= GPIO_GPIO20;
 	GPSR = GPIO_GPIO20;
 	mdelay(1000);
@@ -40,7 +41,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	ret = sa1111_probe();
+	ret = sa1111_probe(0x40000000);
 	if (ret < 0)
 		return ret;
 
@@ -65,9 +66,9 @@
 
 static struct map_desc xp860_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */
-  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */
-  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCSI */
+  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN */
+  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.4.19-pre4/arch/arm/mach-sa1100/yopy.c linux-2.4.19-pre5/arch/arm/mach-sa1100/yopy.c
--- linux-2.4.19-pre4/arch/arm/mach-sa1100/yopy.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/mach-sa1100/yopy.c	Fri Mar 29 14:49:19 2002
@@ -1,8 +1,6 @@
 /*
  * linux/arch/arm/mach-sa1100/yopy.c
  */
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -52,14 +50,16 @@
 
 static int __init yopy_hw_init(void)
 {
-	YOPY_EGPIO = yopy_egpio;
+	if (machine_is_yopy()) {
+		YOPY_EGPIO = yopy_egpio;
 
-	/* Enable Output */
-	PPDR |= PPC_L_BIAS;
-	PSDR &= ~PPC_L_BIAS;
-	PPSR |= PPC_L_BIAS;
+		/* Enable Output */
+		PPDR |= PPC_L_BIAS;
+		PSDR &= ~PPC_L_BIAS;
+		PPSR |= PPC_L_BIAS;
 
-	YOPY_EGPIO = yopy_egpio;
+		YOPY_EGPIO = yopy_egpio;
+	}
 
 	return 0;
 }
@@ -69,9 +69,9 @@
 
 static struct map_desc yopy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 0 */
-  { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 1 */
-  { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD */
+  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 0 */
+  { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 1 */
+  { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */
   { 0xf1000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO */
   LAST_DESC
 };
@@ -82,6 +82,8 @@
 	iotable_init(yopy_io_desc);
 
 	sa1100_register_uart(0, 3);
+
+	set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE);
 }
 
 
diff -urN linux-2.4.19-pre4/arch/arm/mm/Makefile linux-2.4.19-pre5/arch/arm/mm/Makefile
--- linux-2.4.19-pre4/arch/arm/mm/Makefile	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre5/arch/arm/mm/Makefile	Fri Mar 29 14:49:19 2002
@@ -13,19 +13,20 @@
 
 # Object file lists.
 
-obj-y		:= init.o
+obj-y		:= init.o extable.o fault-common.o
 obj-m		:=
 obj-n		:=
 obj-		:=
 export-objs	:= proc-syms.o discontig.o
 
-cpu32-y		:= consistent.o fault-armv.o ioremap.o mm-armv.o
-cpu32-$(CONFIG_MODULES) += proc-syms.o
+ifeq ($(CONFIG_CPU_32),y)
+obj-y		+= consistent.o fault-armv.o ioremap.o mm-armv.o
+obj-$(CONFIG_MODULES) += proc-syms.o
+endif
 
-obj-y		+= extable.o fault-common.o
 obj-$(CONFIG_CPU_26) += fault-armo.o mm-armo.o small_page.o
-obj-$(CONFIG_CPU_32) += $(cpu32-y)
 
+obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
 obj-$(CONFIG_DISCONTIGMEM) += discontig.o
 
 # Select the processor-specific files
@@ -34,6 +35,7 @@
 p-$(CONFIG_CPU_ARM710)	+= proc-arm6,7.o
 p-$(CONFIG_CPU_ARM720T)	+= proc-arm720.o
 p-$(CONFIG_CPU_ARM920T)	+= proc-arm920.o
+p-$(CONFIG_CPU_ARM922T)	+= proc-arm922.o
 p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o
 p-$(CONFIG_CPU_ARM1020)	+= proc-arm1020.o
 p-$(CONFIG_CPU_SA110)	+= proc-sa110.o
diff -urN linux-2.4.19-pre4/arch/arm/mm/alignment.c linux-2.4.19-pre5/arch/arm/mm/alignment.c
--- linux-2.4.19-pre4/arch/arm/mm/alignment.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mm/alignment.c	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,609 @@
+/*
+ *  linux/arch/arm/mm/alignment.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Modifications for ARM processor (c) 1995-2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/compiler.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/unaligned.h>
+
+extern void
+do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
+	    int error_code, struct pt_regs *regs);
+
+/*
+ * 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
+ *
+ * Speed optimisations and better fault handling by Russell King.
+ *
+ * *** NOTE ***
+ * This code is not portable to processors with late data abort handling.
+ */
+#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 LDST_P_EQ_U(i)	((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
+
+#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 ai_usermode;
+
+#ifdef CONFIG_PROC_FS
+static const char *usermode_action[] = {
+	"ignored",
+	"warn",
+	"fixup",
+	"fixup+warn",
+	"signal",
+	"signal+warn"
+};
+
+static int
+proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
+		    void *data)
+{
+	char *p = page;
+	int len;
+
+	p += sprintf(p, "User:\t\t%lu\n", ai_user);
+	p += sprintf(p, "System:\t\t%lu\n", ai_sys);
+	p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
+	p += sprintf(p, "Half:\t\t%lu\n", ai_half);
+	p += sprintf(p, "Word:\t\t%lu\n", ai_word);
+	p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
+	p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
+			usermode_action[ai_usermode]);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static int proc_alignment_write(struct file *file, const char *buffer,
+			       unsigned long count, void *data)
+{
+	int mode;
+
+	if (count > 0) {
+		if (get_user(mode, buffer))
+			return -EFAULT;
+		if (mode >= '0' && mode <= '5')
+			   ai_usermode = mode - '0';
+	}
+	return count;
+}
+
+/*
+ * This needs to be done after sysctl_init, otherwise sys/ will be
+ * overwritten.  Actually, this shouldn't be in sys/ at all since
+ * it isn't a sysctl, and it doesn't contain sysctl information.
+ * We now locate it in /proc/cpu/alignment instead.
+ */
+static int __init alignment_init(void)
+{
+	struct proc_dir_entry *res;
+
+	res = proc_mkdir("cpu", NULL);
+	if (!res)
+		return -ENOMEM;
+
+	res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
+	if (!res)
+		return -ENOMEM;
+
+	res->read_proc = proc_alignment_read;
+	res->write_proc = proc_alignment_write;
+
+	return 0;
+}
+
+__initcall(alignment_init);
+#endif /* CONFIG_PROC_FS */
+
+union offset_union {
+	unsigned long un;
+	  signed long sn;
+};
+
+#define TYPE_ERROR	0
+#define TYPE_FAULT	1
+#define TYPE_LDST	2
+#define TYPE_DONE	3
+
+#define __get8_unaligned_check(ins,val,addr,err)	\
+	__asm__(					\
+	"1:	"ins"	%1, [%2], #1\n"			\
+	"2:\n"						\
+	"	.section .fixup,\"ax\"\n"		\
+	"	.align	2\n"				\
+	"3:	mov	%0, #1\n"			\
+	"	b	2b\n"				\
+	"	.previous\n"				\
+	"	.section __ex_table,\"a\"\n"		\
+	"	.align	3\n"				\
+	"	.long	1b, 3b\n"			\
+	"	.previous\n"				\
+	: "=r" (err), "=&r" (val), "=r" (addr)		\
+	: "0" (err), "2" (addr))
+
+#define __get16_unaligned_check(ins,val,addr)			\
+	do {							\
+		unsigned int err = 0, v, a = addr;		\
+		__get8_unaligned_check(ins,val,a,err);		\
+		__get8_unaligned_check(ins,v,a,err);		\
+		val |= v << 8;					\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define get16_unaligned_check(val,addr) \
+	__get16_unaligned_check("ldrb",val,addr)
+
+#define get16t_unaligned_check(val,addr) \
+	__get16_unaligned_check("ldrbt",val,addr)
+
+#define __get32_unaligned_check(ins,val,addr)			\
+	do {							\
+		unsigned int err = 0, v, a = addr;		\
+		__get8_unaligned_check(ins,val,a,err);		\
+		__get8_unaligned_check(ins,v,a,err);		\
+		val |= v << 8;					\
+		__get8_unaligned_check(ins,v,a,err);		\
+		val |= v << 16;					\
+		__get8_unaligned_check(ins,v,a,err);		\
+		val |= v << 24;					\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define get32_unaligned_check(val,addr) \
+	__get32_unaligned_check("ldrb",val,addr)
+
+#define get32t_unaligned_check(val,addr) \
+	__get32_unaligned_check("ldrbt",val,addr)
+
+#define __put16_unaligned_check(ins,val,addr)			\
+	do {							\
+		unsigned int err = 0, v = val, a = addr;	\
+		__asm__(					\
+		"1:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"2:	"ins"	%1, [%2]\n"			\
+		"3:\n"						\
+		"	.section .fixup,\"ax\"\n"		\
+		"	.align	2\n"				\
+		"4:	mov	%0, #1\n"			\
+		"	b	3b\n"				\
+		"	.previous\n"				\
+		"	.section __ex_table,\"a\"\n"		\
+		"	.align	3\n"				\
+		"	.long	1b, 4b\n"			\
+		"	.long	2b, 4b\n"			\
+		"	.previous\n"				\
+		: "=r" (err), "=&r" (v), "=&r" (a)		\
+		: "0" (err), "1" (v), "2" (a));			\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define put16_unaligned_check(val,addr)  \
+	__put16_unaligned_check("strb",val,addr)
+
+#define put16t_unaligned_check(val,addr) \
+	__put16_unaligned_check("strbt",val,addr)
+
+#define __put32_unaligned_check(ins,val,addr)			\
+	do {							\
+		unsigned int err = 0, v = val, a = addr;	\
+		__asm__(					\
+		"1:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"2:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"3:	"ins"	%1, [%2], #1\n"			\
+		"	mov	%1, %1, lsr #8\n"		\
+		"4:	"ins"	%1, [%2]\n"			\
+		"5:\n"						\
+		"	.section .fixup,\"ax\"\n"		\
+		"	.align	2\n"				\
+		"6:	mov	%0, #1\n"			\
+		"	b	5b\n"				\
+		"	.previous\n"				\
+		"	.section __ex_table,\"a\"\n"		\
+		"	.align	3\n"				\
+		"	.long	1b, 6b\n"			\
+		"	.long	2b, 6b\n"			\
+		"	.long	3b, 6b\n"			\
+		"	.long	4b, 6b\n"			\
+		"	.previous\n"				\
+		: "=r" (err), "=&r" (v), "=&r" (a)		\
+		: "0" (err), "1" (v), "2" (a));			\
+		if (err)					\
+			goto fault;				\
+	} while (0)
+
+#define put32_unaligned_check(val,addr)	 \
+	__put32_unaligned_check("strb", val, addr)
+
+#define put32t_unaligned_check(val,addr) \
+	__put32_unaligned_check("strbt", val, addr)
+
+static void
+do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
+{
+	if (!LDST_U_BIT(instr))
+		offset.un = -offset.un;
+
+	if (!LDST_P_BIT(instr))
+		addr += offset.un;
+
+	if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
+		regs->uregs[RN_BITS(instr)] = addr;
+}
+
+static int
+do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
+{
+	unsigned int rd = RD_BITS(instr);
+
+	if ((instr & 0x01f00ff0) == 0x01000090)
+		goto swp;
+
+	if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
+		goto bad;
+
+	ai_half += 1;
+
+	if (user_mode(regs))
+		goto user;
+
+	if (LDST_L_BIT(instr)) {
+		unsigned long val;
+		get16_unaligned_check(val, addr);
+
+		/* signed half-word? */
+		if (instr & 0x40)
+			val = (signed long)((signed short) val);
+
+		regs->uregs[rd] = val;
+	} else
+		put16_unaligned_check(regs->uregs[rd], addr);
+
+	return TYPE_LDST;
+
+ user:
+ 	if (LDST_L_BIT(instr)) {
+ 		unsigned long val;
+ 		get16t_unaligned_check(val, addr);
+
+ 		/* signed half-word? */
+ 		if (instr & 0x40)
+ 			val = (signed long)((signed short) val);
+
+ 		regs->uregs[rd] = val;
+ 	} else
+ 		put16t_unaligned_check(regs->uregs[rd], addr);
+
+ 	return TYPE_LDST;
+
+ swp:
+	printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
+ bad:
+	return TYPE_ERROR;
+
+ fault:
+	return TYPE_FAULT;
+}
+
+static int
+do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs)
+{
+	unsigned int rd = RD_BITS(instr);
+
+	ai_word += 1;
+
+	if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs))
+		goto trans;
+
+	if (LDST_L_BIT(instr)) {
+		unsigned int val;
+		get32_unaligned_check(val, addr);
+		regs->uregs[rd] = val;
+	} else
+		put32_unaligned_check(regs->uregs[rd], addr);
+	return TYPE_LDST;
+
+ trans:
+	if (LDST_L_BIT(instr)) {
+		unsigned int val;
+		get32t_unaligned_check(val, addr);
+		regs->uregs[rd] = val;
+	} else
+		put32t_unaligned_check(regs->uregs[rd], addr);
+	return TYPE_LDST;
+
+ fault:
+	return TYPE_FAULT;
+}
+
+/*
+ * LDM/STM alignment handler.
+ *
+ * There are 4 variants of this instruction:
+ *
+ * B = rn pointer before instruction, A = rn pointer after instruction
+ *              ------ increasing address ----->
+ *	        |    | r0 | r1 | ... | rx |    |
+ * PU = 01             B                    A
+ * PU = 11        B                    A
+ * PU = 00        A                    B
+ * PU = 10             A                    B
+ */
+static int
+do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
+{
+	unsigned int rd, rn, correction, nr_regs, regbits;
+	unsigned long eaddr, newaddr;
+
+	if (LDM_S_BIT(instr))
+		goto bad;
+
+	correction = 4; /* processor implementation defined */
+	regs->ARM_pc += correction;
+
+	ai_multi += 1;
+
+	/* count the number of registers in the mask to be transferred */
+	nr_regs = hweight16(REGMASK_BITS(instr)) * 4;
+
+	rn = RN_BITS(instr);
+	newaddr = eaddr = regs->uregs[rn];
+
+	if (!LDST_U_BIT(instr))
+		nr_regs = -nr_regs;
+	newaddr += nr_regs;
+	if (!LDST_U_BIT(instr))
+		eaddr = newaddr;
+
+	if (LDST_P_EQ_U(instr))	/* U = P */
+		eaddr += 4;
+
+	/* 
+	 * For alignment faults on the ARM922T the MMU  makes 
+	 * the FSR (and hence addr) equal to the updated base address
+	 * of the multiple access rather than the restored value.
+	 * Switch this messsage off if we've got a ARM922, otherwise
+	 * [ls]dm alignment faults are noisy!
+	 */
+#if !(defined CONFIG_CPU_ARM922T)  
+	/*
+	 * This is a "hint" - we already have eaddr worked out by the
+	 * processor for us.
+	 */
+	if (addr != eaddr) {
+		printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
+			"addr = %08lx, eaddr = %08lx\n",
+			 instruction_pointer(regs), instr, addr, eaddr);
+		show_regs(regs);
+	}
+#endif
+
+	if (user_mode(regs)) {
+		for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
+		     regbits >>= 1, rd += 1)
+			if (regbits & 1) {
+				if (LDST_L_BIT(instr)) {
+					unsigned int val;
+					get32t_unaligned_check(val, eaddr);
+					regs->uregs[rd] = val;
+				} else
+					put32t_unaligned_check(regs->uregs[rd], eaddr);
+				eaddr += 4;
+			}
+	} else {
+		for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
+		     regbits >>= 1, rd += 1)
+			if (regbits & 1) {
+				if (LDST_L_BIT(instr)) {
+					unsigned int val;
+					get32_unaligned_check(val, eaddr);
+					regs->uregs[rd] = val;
+				} else
+					put32_unaligned_check(regs->uregs[rd], eaddr);
+				eaddr += 4;
+			}
+	}
+
+	if (LDST_W_BIT(instr))
+		regs->uregs[rn] = newaddr;
+	if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
+		regs->ARM_pc -= correction;
+	return TYPE_DONE;
+
+fault:
+	regs->ARM_pc -= correction;
+	return TYPE_FAULT;
+
+bad:
+	printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
+	return TYPE_ERROR;
+}
+
+int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
+{
+	union offset_union offset;
+	unsigned long instr, instrptr;
+	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
+	unsigned int type;
+
+	instrptr = instruction_pointer(regs);
+	instr = *(unsigned long *)instrptr;
+
+	if (user_mode(regs))
+		goto user;
+
+	ai_sys += 1;
+
+ fixup:
+
+	regs->ARM_pc += 4;
+
+	switch (CODING_BITS(instr)) {
+	case 0x00000000:	/* ldrh or strh */
+		if (LDSTH_I_BIT(instr))
+			offset.un = (instr & 0xf00) >> 4 | (instr & 15);
+		else
+			offset.un = regs->uregs[RM_BITS(instr)];
+		handler = do_alignment_ldrhstrh;
+		break;
+
+	case 0x04000000:	/* ldr or str immediate */
+		offset.un = OFFSET_BITS(instr);
+		handler = do_alignment_ldrstr;
+		break;
+
+	case 0x06000000:	/* ldr or str register */
+		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;
+			}
+		}
+		handler = do_alignment_ldrstr;
+		break;
+
+	case 0x08000000:	/* ldm or stm */
+		handler = do_alignment_ldmstm;
+		break;
+
+	default:
+		goto bad;
+	}
+
+	type = handler(addr, instr, regs);
+
+	if (type == TYPE_ERROR || type == TYPE_FAULT)
+		goto bad_or_fault;
+
+	if (type == TYPE_LDST)
+		do_alignment_finish_ldst(addr, instr, regs, offset);
+
+	return 0;
+
+ bad_or_fault:
+	if (type == TYPE_ERROR)
+		goto bad;
+	regs->ARM_pc -= 4;
+	/*
+	 * We got a fault - fix it up, or die.
+	 */
+	do_bad_area(current, current->mm, addr, error_code, regs);
+	return 0;
+
+ bad:
+	/*
+	 * Oops, we didn't handle the instruction.
+	 */
+	printk(KERN_ERR "Alignment trap: not handling instruction "
+		"%08lx at [<%08lx>]\n", instr, instrptr);
+	ai_skipped += 1;
+	return 1;
+
+ user:
+	ai_user += 1;
+
+	if (ai_usermode & 1)
+		printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx "
+		       "Address=0x%08lx Code 0x%02x\n", current->comm,
+			current->pid, instrptr, instr, addr, error_code);
+
+	if (ai_usermode & 2)
+		goto fixup;
+
+	if (ai_usermode & 4)
+		force_sig(SIGBUS, current);
+	else
+		set_cr(cr_no_alignment);
+
+	return 0;
+}
diff -urN linux-2.4.19-pre4/arch/arm/mm/fault-armv.c linux-2.4.19-pre5/arch/arm/mm/fault-armv.c
--- linux-2.4.19-pre4/arch/arm/mm/fault-armv.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mm/fault-armv.c	Fri Mar 29 14:49:19 2002
@@ -27,7 +27,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/unaligned.h>
 
 extern void die_if_kernel(const char *str, struct pt_regs *regs, int err);
 extern void show_pte(struct mm_struct *mm, unsigned long addr);
@@ -40,499 +39,15 @@
 			struct pt_regs *regs);
 
 #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
- *
- * Speed optimisations and better fault handling by Russell King.
- *
- * *** NOTE ***
- * This code is not portable to processors with late data abort handling.
- */
-#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 LDST_P_EQ_U(i)	((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
-
-#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;
-
-#ifdef CONFIG_SYSCTL
-static int proc_alignment_read(char *page, char **start, off_t off,
-			       int count, int *eof, void *data)
-{
-	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;
-}
-
-/*
- * This needs to be done after sysctl_init, otherwise sys/
- * will be overwritten.
- */
-static int __init alignment_init(void)
-{
-	create_proc_read_entry("sys/debug/alignment", 0, NULL,
-				proc_alignment_read, NULL);
-	return 0;
-}
-
-__initcall(alignment_init);
-#endif /* CONFIG_SYSCTL */
-
-union offset_union {
-	unsigned long un;
-	  signed long sn;
-};
-
-#define TYPE_ERROR	0
-#define TYPE_FAULT	1
-#define TYPE_LDST	2
-#define TYPE_DONE	3
-
-#define get8_unaligned_check(val,addr,err)		\
-	__asm__(					\
-	"1:	ldrb	%1, [%2], #1\n"			\
-	"2:\n"						\
-	"	.section .fixup,\"ax\"\n"		\
-	"	.align	2\n"				\
-	"3:	mov	%0, #1\n"			\
-	"	b	2b\n"				\
-	"	.previous\n"				\
-	"	.section __ex_table,\"a\"\n"		\
-	"	.align	3\n"				\
-	"	.long	1b, 3b\n"			\
-	"	.previous\n"				\
-	: "=r" (err), "=&r" (val), "=r" (addr)		\
-	: "0" (err), "2" (addr))
-
-#define get8t_unaligned_check(val,addr,err)		\
-	__asm__(					\
-	"1:	ldrbt	%1, [%2], #1\n"			\
-	"2:\n"						\
-	"	.section .fixup,\"ax\"\n"		\
-	"	.align	2\n"				\
-	"3:	mov	%0, #1\n"			\
-	"	b	2b\n"				\
-	"	.previous\n"				\
-	"	.section __ex_table,\"a\"\n"		\
-	"	.align	3\n"				\
-	"	.long	1b, 3b\n"			\
-	"	.previous\n"				\
-	: "=r" (err), "=&r" (val), "=r" (addr)		\
-	: "0" (err), "2" (addr))
-
-#define get16_unaligned_check(val,addr)				\
-	do {							\
-		unsigned int err = 0, v, a = addr;		\
-		get8_unaligned_check(val,a,err);		\
-		get8_unaligned_check(v,a,err);			\
-		val |= v << 8;					\
-		if (err)					\
-			goto fault;				\
-	} while (0)
-
-#define put16_unaligned_check(val,addr)				\
-	do {							\
-		unsigned int err = 0, v = val, a = addr;	\
-		__asm__(					\
-		"1:	strb	%1, [%2], #1\n"			\
-		"	mov	%1, %1, lsr #8\n"		\
-		"2:	strb	%1, [%2]\n"			\
-		"3:\n"						\
-		"	.section .fixup,\"ax\"\n"		\
-		"	.align	2\n"				\
-		"4:	mov	%0, #1\n"			\
-		"	b	3b\n"				\
-		"	.previous\n"				\
-		"	.section __ex_table,\"a\"\n"		\
-		"	.align	3\n"				\
-		"	.long	1b, 4b\n"			\
-		"	.long	2b, 4b\n"			\
-		"	.previous\n"				\
-		: "=r" (err), "=&r" (v), "=&r" (a)		\
-		: "0" (err), "1" (v), "2" (a));			\
-		if (err)					\
-			goto fault;				\
-	} while (0)
-
-#define __put32_unaligned_check(ins,val,addr)			\
-	do {							\
-		unsigned int err = 0, v = val, a = addr;	\
-		__asm__(					\
-		"1:	"ins"	%1, [%2], #1\n"			\
-		"	mov	%1, %1, lsr #8\n"		\
-		"2:	"ins"	%1, [%2], #1\n"			\
-		"	mov	%1, %1, lsr #8\n"		\
-		"3:	"ins"	%1, [%2], #1\n"			\
-		"	mov	%1, %1, lsr #8\n"		\
-		"4:	"ins"	%1, [%2]\n"			\
-		"5:\n"						\
-		"	.section .fixup,\"ax\"\n"		\
-		"	.align	2\n"				\
-		"6:	mov	%0, #1\n"			\
-		"	b	5b\n"				\
-		"	.previous\n"				\
-		"	.section __ex_table,\"a\"\n"		\
-		"	.align	3\n"				\
-		"	.long	1b, 6b\n"			\
-		"	.long	2b, 6b\n"			\
-		"	.long	3b, 6b\n"			\
-		"	.long	4b, 6b\n"			\
-		"	.previous\n"				\
-		: "=r" (err), "=&r" (v), "=&r" (a)		\
-		: "0" (err), "1" (v), "2" (a));			\
-		if (err)					\
-			goto fault;				\
-	} while (0)
-
-#define get32_unaligned_check(val,addr)				\
-	do {							\
-		unsigned int err = 0, v, a = addr;		\
-		get8_unaligned_check(val,a,err);		\
-		get8_unaligned_check(v,a,err);			\
-		val |= v << 8;					\
-		get8_unaligned_check(v,a,err);			\
-		val |= v << 16;					\
-		get8_unaligned_check(v,a,err);			\
-		val |= v << 24;					\
-		if (err)					\
-			goto fault;				\
-	} while (0)
-
-#define put32_unaligned_check(val,addr)	 \
-	__put32_unaligned_check("strb", val, addr)
-
-#define get32t_unaligned_check(val,addr)			\
-	do {							\
-		unsigned int err = 0, v, a = addr;		\
-		get8t_unaligned_check(val,a,err);		\
-		get8t_unaligned_check(v,a,err);			\
-		val |= v << 8;					\
-		get8t_unaligned_check(v,a,err);			\
-		val |= v << 16;					\
-		get8t_unaligned_check(v,a,err);			\
-		val |= v << 24;					\
-		if (err)					\
-			goto fault;				\
-	} while (0)
-
-#define put32t_unaligned_check(val,addr) \
-	__put32_unaligned_check("strbt", val, addr)
-
-static void
-do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
-{
-	if (!LDST_U_BIT(instr))
-		offset.un = -offset.un;
-
-	if (!LDST_P_BIT(instr))
-		addr += offset.un;
-
-	if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
-		regs->uregs[RN_BITS(instr)] = addr;
-}
-
-static int
-do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
-{
-	unsigned int rd = RD_BITS(instr);
-
-	if ((instr & 0x01f00ff0) == 0x01000090)
-		goto swp;
-
-	if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
-		goto bad;
-
-	ai_half += 1;
-
-	if (LDST_L_BIT(instr)) {
-		unsigned long val;
-		get16_unaligned_check(val, addr);
-
-		/* signed half-word? */
-		if (instr & 0x40)
-			val = (signed long)((signed short) val);
-
-		regs->uregs[rd] = val;
-	} else
-		put16_unaligned_check(regs->uregs[rd], addr);
-
-	return TYPE_LDST;
-
-swp:
-	printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
-bad:
-	return TYPE_ERROR;
-
-fault:
-	return TYPE_FAULT;
-}
-
-static int
-do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs)
-{
-	unsigned int rd = RD_BITS(instr);
-
-	ai_word += 1;
-
-	if (!LDST_P_BIT(instr) && LDST_W_BIT(instr))
-		goto trans;
-
-	if (LDST_L_BIT(instr))
-		get32_unaligned_check(regs->uregs[rd], addr);
-	else
-		put32_unaligned_check(regs->uregs[rd], addr);
-	return TYPE_LDST;
-
-trans:
-	if (LDST_L_BIT(instr))
-		get32t_unaligned_check(regs->uregs[rd], addr);
-	else
-		put32t_unaligned_check(regs->uregs[rd], addr);
-	return TYPE_LDST;
-
-fault:
-	return TYPE_FAULT;
-}
-
-/*
- * LDM/STM alignment handler.
- *
- * There are 4 variants of this instruction:
- *
- * B = rn pointer before instruction, A = rn pointer after instruction
- *              ------ increasing address ----->
- *	        |    | r0 | r1 | ... | rx |    |
- * PU = 01             B                    A
- * PU = 11        B                    A
- * PU = 00        A                    B
- * PU = 10             A                    B
- */
-static int
-do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
-{
-	unsigned int rd, rn, correction, nr_regs, regbits;
-	unsigned long eaddr, newaddr;
-
-	if (LDM_S_BIT(instr))
-		goto bad;
-
-	correction = 4; /* processor implementation defined */
-	regs->ARM_pc += correction;
-
-	ai_multi += 1;
-
-	/* count the number of registers in the mask to be transferred */
-	nr_regs = hweight16(REGMASK_BITS(instr)) * 4;
-
-	rn = RN_BITS(instr);
-	newaddr = eaddr = regs->uregs[rn];
-
-	if (!LDST_U_BIT(instr))
-		nr_regs = -nr_regs;
-	newaddr += nr_regs;
-	if (!LDST_U_BIT(instr))
-		eaddr = newaddr;
-
-	if (LDST_P_EQ_U(instr))	/* U = P */
-		eaddr += 4;
-
-	/*
-	 * This is a "hint" - we already have eaddr worked out by the
-	 * processor for us.
-	 */
-	if (addr != eaddr) {
-		printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
-			"addr = %08lx, eaddr = %08lx\n",
-			 instruction_pointer(regs), instr, addr, eaddr);
-		show_regs(regs);
-	}
-
-	for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
-		if (regbits & 1) {
-			if (LDST_L_BIT(instr))
-				get32_unaligned_check(regs->uregs[rd], eaddr);
-			else
-				put32_unaligned_check(regs->uregs[rd], eaddr);
-			eaddr += 4;
-		}
-
-	if (LDST_W_BIT(instr))
-		regs->uregs[rn] = newaddr;
-	if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
-		regs->ARM_pc -= correction;
-	return TYPE_DONE;
-
-fault:
-	regs->ARM_pc -= correction;
-	return TYPE_FAULT;
-
-bad:
-	printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
-	return TYPE_ERROR;
-}
-
-static int
-do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
-{
-	union offset_union offset;
-	unsigned long instr, instrptr;
-	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
-	unsigned int type;
-
-	if (user_mode(regs))
-		goto user;
-
-	ai_sys += 1;
-
-	instrptr = instruction_pointer(regs);
-	instr = *(unsigned long *)instrptr;
-
-	regs->ARM_pc += 4;
-
-	switch (CODING_BITS(instr)) {
-	case 0x00000000:	/* ldrh or strh */
-		if (LDSTH_I_BIT(instr))
-			offset.un = (instr & 0xf00) >> 4 | (instr & 15);
-		else
-			offset.un = regs->uregs[RM_BITS(instr)];
-		handler = do_alignment_ldrhstrh;
-		break;
-
-	case 0x04000000:	/* ldr or str immediate */
-		offset.un = OFFSET_BITS(instr);
-		handler = do_alignment_ldrstr;
-		break;
-
-	case 0x06000000:	/* ldr or str register */
-		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;
-			}
-		}
-		handler = do_alignment_ldrstr;
-		break;
-
-	case 0x08000000:	/* ldm or stm */
-		handler = do_alignment_ldmstm;
-		break;
-
-	default:
-		goto bad;
-	}
-
-	type = handler(addr, instr, regs);
-
-	if (type == TYPE_ERROR || type == TYPE_FAULT)
-		goto bad_or_fault;
-
-	if (type == TYPE_LDST)
-		do_alignment_finish_ldst(addr, instr, regs, offset);
-
-	return 0;
-
-bad_or_fault:
-	if (type == TYPE_ERROR)
-		goto bad;
-	regs->ARM_pc -= 4;
-	/*
-	 * We got a fault - fix it up, or die.
-	 */
-	do_bad_area(current, current->mm, addr, error_code, regs);
-	return 0;
-
-bad:
-	/*
-	 * Oops, we didn't handle the instruction.
-	 */
-	printk(KERN_ERR "Alignment trap: not handling instruction "
-		"%08lx at [<%08lx>]\n", instr, instrptr);
-	ai_skipped += 1;
-	return 1;
-
-user:
-	set_cr(cr_no_alignment);
-	ai_user += 1;
-	return 0;
-}
-
+extern int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs);
 #else
-
-#define do_alignment NULL
-
+#define do_alignment do_bad
 #endif
 
+
 /*
- * Some section permission faults need to be handled gracefully, for
- * instance, when they happen due to a __{get,put}_user during an oops).
+ * Some section permission faults need to be handled gracefully.
+ * They can happen due to a __{get,put}_user during an oops.
  */
 static int
 do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
@@ -557,73 +72,54 @@
 	return 1;
 }
 
+/*
+ * This abort handler always returns "fault".
+ */
+static int
+do_bad(unsigned long addr, int error_code, struct pt_regs *regs)
+{
+	return 1;
+}
+
 static const struct fsr_info {
 	int	(*fn)(unsigned long addr, int error_code, struct pt_regs *regs);
 	int	sig;
-	char	*name;
+	const char *name;
 } fsr_info[] = {
-	{ NULL,			SIGSEGV, "vector exception"		   },
+	{ do_bad,		SIGSEGV, "vector exception"		   },
 	{ do_alignment,		SIGILL,	 "alignment exception"		   },
-	{ NULL,			SIGKILL, "terminal exception"		   },
+	{ do_bad,		SIGKILL, "terminal exception"		   },
 	{ do_alignment,		SIGILL,	 "alignment exception"		   },
 	{ do_external_fault,	SIGBUS,	 "external abort on linefetch"	   },
 	{ do_translation_fault,	SIGSEGV, "section translation fault"	   },
 	{ do_external_fault,	SIGBUS,	 "external abort on linefetch"	   },
 	{ do_page_fault,	SIGSEGV, "page translation fault"	   },
 	{ do_external_fault,	SIGBUS,	 "external abort on non-linefetch" },
-	{ NULL,			SIGSEGV, "section domain fault"		   },
+	{ do_bad,		SIGSEGV, "section domain fault"		   },
 	{ do_external_fault,	SIGBUS,	 "external abort on non-linefetch" },
-	{ NULL,			SIGSEGV, "page domain fault"		   },
-	{ NULL,			SIGBUS,	 "external abort on translation"   },
+	{ do_bad,		SIGSEGV, "page domain fault"		   },
+	{ do_bad,		SIGBUS,	 "external abort on translation"   },
 	{ do_sect_fault,	SIGSEGV, "section permission fault"	   },
-	{ NULL,			SIGBUS,	 "external abort on translation"   },
+	{ do_bad,		SIGBUS,	 "external abort on translation"   },
 	{ do_page_fault,	SIGSEGV, "page permission fault"	   }
 };
 
 /*
- * Currently dropped down to debug level
+ * Dispatch a data abort to the relevant handler.
  */
 asmlinkage void
 do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr)
 {
 	const struct fsr_info *inf = fsr_info + (fsr & 15);
 
-#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS)
-	if (addr == regs->ARM_pc)
-		goto sa1_weirdness;
-#endif
-
-	if (!inf->fn)
-		goto bad;
-
 	if (!inf->fn(addr, error_code, regs))
 		return;
-bad:
-	printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n",
+
+	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
 		inf->name, fsr, addr);
-	show_pte(current->mm, addr);
 	force_sig(inf->sig, current);
+	show_pte(current->mm, addr);
 	die_if_kernel("Oops", regs, 0);
-	return;
-
-#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS)
-sa1_weirdness:
-	if (user_mode(regs)) {
-		static int first = 1;
-		if (first) {
-			printk(KERN_DEBUG "Fixing up bad data abort at %08lx\n", addr);
-#ifdef CONFIG_DEBUG_ERRORS
-			show_pte(current->mm, addr);
-#endif
-		}
-		first = 0;
-		return;
-	}
-
-	if (!inf->fn || inf->fn(addr, error_code, regs))
-		goto bad;
-	return;
-#endif
 }
 
 asmlinkage void
@@ -680,38 +176,13 @@
 	return;
 }
 
-/*
- * Take care of architecture specific things when placing a new PTE into
- * a page table, or changing an existing PTE.  Basically, there are two
- * things that we need to take care of:
- *
- *  1. If PG_dcache_dirty is set for the page, we need to ensure
- *     that any cache entries for the kernels virtual memory
- *     range are written back to the page.
- *  2. If we have multiple shared mappings of the same space in
- *     an object, we need to deal with the cache aliasing issues.
- *
- * Note that the page_table_lock will be held.
- */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+static void
+make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page)
 {
-	struct page *page = pte_page(pte);
 	struct vm_area_struct *mpnt;
-	struct mm_struct *mm;
-	unsigned long pgoff;
-	int aliases;
-
-	if (!VALID_PAGE(page) || !page->mapping)
-		return;
-
-	if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
-		unsigned long kvirt = (unsigned long)page_address(page);
-		cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
-	}
-
-	mm = vma->vm_mm;
-	pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
-	aliases = 0;
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+	int aliases = 0;
 
 	/*
 	 * If we have any shared mappings that are in the same mm
@@ -727,7 +198,7 @@
 		 * Note that we intentionally don't mask out the VMA
 		 * that we are fixing up.
 		 */
-		if (mpnt->vm_mm != mm && mpnt != vma)
+		if (mpnt->vm_mm != mm || mpnt == vma)
 			continue;
 
 		/*
@@ -749,3 +220,30 @@
 	if (aliases)
 		adjust_pte(vma, addr);
 }
+
+/*
+ * Take care of architecture specific things when placing a new PTE into
+ * a page table, or changing an existing PTE.  Basically, there are two
+ * things that we need to take care of:
+ *
+ *  1. If PG_dcache_dirty is set for the page, we need to ensure
+ *     that any cache entries for the kernels virtual memory
+ *     range are written back to the page.
+ *  2. If we have multiple shared mappings of the same space in
+ *     an object, we need to deal with the cache aliasing issues.
+ *
+ * Note that the page_table_lock will be held.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+	struct page *page = pte_page(pte);
+
+	if (VALID_PAGE(page) && page->mapping) {
+		if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
+			unsigned long kvirt = (unsigned long)page_address(page);
+			cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
+		}
+
+		make_coherent(vma, addr, page);
+	}
+}
diff -urN linux-2.4.19-pre4/arch/arm/mm/fault-common.c linux-2.4.19-pre5/arch/arm/mm/fault-common.c
--- linux-2.4.19-pre4/arch/arm/mm/fault-common.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mm/fault-common.c	Fri Mar 29 14:49:19 2002
@@ -141,6 +141,7 @@
 	printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, "
 	       "lr=0x%08lx (bad address=0x%08lx, code %d)\n",
 	       tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code);
+	show_regs(regs);
 #endif
 
 	tsk->thread.address = addr;
diff -urN linux-2.4.19-pre4/arch/arm/mm/mm-armv.c linux-2.4.19-pre5/arch/arm/mm/mm-armv.c
--- linux-2.4.19-pre4/arch/arm/mm/mm-armv.c	Wed Jun 27 14:12:04 2001
+++ linux-2.4.19-pre5/arch/arm/mm/mm-armv.c	Fri Mar 29 14:49:19 2002
@@ -14,10 +14,10 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 
+#include <asm/hardware.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/page.h>
-#include <asm/io.h>
 #include <asm/setup.h>
 
 #include <asm/mach/map.h>
@@ -225,6 +225,19 @@
 	int prot_sect, prot_pte;
 	long off;
 
+	if (md->prot_read && md->prot_write &&
+	    !md->cacheable && !md->bufferable) {
+		printk(KERN_WARNING "Security risk: creating user "
+		       "accessible mapping for 0x%08lx at 0x%08lx\n",
+		       md->physical, md->virtual);
+	}
+
+	if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) {
+		printk(KERN_WARNING "MM: not creating mapping for "
+		       "0x%08lx at 0x%08lx in user region\n",
+		       md->physical, md->virtual);
+	}
+
 	prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
 		   (md->prot_read  ? L_PTE_USER       : 0) |
 		   (md->prot_write ? L_PTE_WRITE      : 0) |
diff -urN linux-2.4.19-pre4/arch/arm/mm/proc-arm1020.S linux-2.4.19-pre5/arch/arm/mm/proc-arm1020.S
--- linux-2.4.19-pre4/arch/arm/mm/proc-arm1020.S	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre5/arch/arm/mm/proc-arm1020.S	Fri Mar 29 14:49:19 2002
@@ -56,22 +56,27 @@
  * cpu_arm1020_data_abort()
  *
  * obtain information about current aborted instruction
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
  *
- * r0 = address of aborted instruction
+ *  r2 = address of aborted instruction
+ *  r3 = cpsr
  *
  * Returns:
  *  r0 = address of abort
  *  r1 != 0 if writing
  *  r3 = FSR
+ *  r4 = corrupted
  */
 	.align	5
 ENTRY(cpu_arm1020_data_abort)
-	ldr	r1, [r0]			@ read aborted instruction
+	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	ldr	r1, [r2]			@ read aborted instruction
+	and	r3, r3, #255
 	tst	r1, r1, lsr #21 		@ C = bit 20
-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
 	sbc	r1, r1, r1			@ r1 = C - 1
-	and	r3, r3, #255
 	mov	pc, lr
 
 /*
diff -urN linux-2.4.19-pre4/arch/arm/mm/proc-arm720.S linux-2.4.19-pre5/arch/arm/mm/proc-arm720.S
--- linux-2.4.19-pre4/arch/arm/mm/proc-arm720.S	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/mm/proc-arm720.S	Fri Mar 29 14:49:19 2002
@@ -111,6 +111,9 @@
  *         : r3 = saved SPSR
  *
  * Purpose : obtain information about current aborted instruction
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
  *
  * Returns : r0 = address of abort
  *	   : r1 != 0 if writing
diff -urN linux-2.4.19-pre4/arch/arm/mm/proc-arm920.S linux-2.4.19-pre5/arch/arm/mm/proc-arm920.S
--- linux-2.4.19-pre4/arch/arm/mm/proc-arm920.S	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mm/proc-arm920.S	Fri Mar 29 14:49:19 2002
@@ -56,22 +56,27 @@
  * cpu_arm920_data_abort()
  *
  * obtain information about current aborted instruction
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
  *
- * r0 = address of aborted instruction
+ *  r2 = address of aborted instruction
+ *  r3 = cpsr
  *
  * Returns:
  *  r0 = address of abort
  *  r1 != 0 if writing
  *  r3 = FSR
+ *  r4 = corrupted
  */
 	.align	5
 ENTRY(cpu_arm920_data_abort)
-	ldr	r1, [r0]			@ read aborted instruction
+	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	ldr	r1, [r2]			@ read aborted instruction
+	and	r3, r3, #255
 	tst	r1, r1, lsr #21			@ C = bit 20
-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
 	sbc	r1, r1, r1			@ r1 = C - 1
-	and	r3, r3, #255
 	mov	pc, lr
 	
 /*
diff -urN linux-2.4.19-pre4/arch/arm/mm/proc-arm922.S linux-2.4.19-pre5/arch/arm/mm/proc-arm922.S
--- linux-2.4.19-pre4/arch/arm/mm/proc-arm922.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/arm/mm/proc-arm922.S	Fri Mar 29 14:49:19 2002
@@ -0,0 +1,657 @@
+/*
+ *  linux/arch/arm/mm/arm922.S: MMU functions for ARM922
+ *
+ *  Copyright (C) 1999,2000 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2001 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * These are the low level assembler for performing cache and TLB
+ * functions on the arm922.
+ */
+#include <linux/linkage.h>
+#include <linux/config.h>
+#include <asm/assembler.h>
+#include <asm/constants.h>
+#include <asm/procinfo.h>
+#include <asm/hardware.h>
+
+/*
+ * This is the maximum size of an area which will be invalidated
+ * using the single invalidate entry instructions.  Anything larger
+ * than this, and we go for the whole cache.
+ *
+ * This value should be chosen such that we choose the cheapest
+ * alternative.
+ */
+#define MAX_AREA_SIZE	8192
+
+/*
+ * the cache line size of the I and D cache
+ */
+#define DCACHELINESIZE	32
+#define ICACHELINESIZE	32
+
+/*
+ * and the page size
+ */
+#define PAGESIZE	4096
+
+	.text
+
+/*
+ * cpu_arm922_data_abort()
+ *
+ * obtain information about current aborted instruction
+ *
+ * r0 = address of aborted instruction
+ *
+ * Returns:
+ *  r0 = address of abort
+ *  r1 != 0 if writing
+ *  r3 = FSR
+ */
+	.align	5
+ENTRY(cpu_arm922_data_abort)
+	ldr	r1, [r0]			@ read aborted instruction
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	tst	r1, r1, lsr #21			@ C = bit 20
+	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
+	sbc	r1, r1, r1			@ r1 = C - 1
+	and	r3, r3, #255
+	mov	pc, lr
+	
+/*
+ * cpu_arm922_check_bugs()
+ */
+ENTRY(cpu_arm922_check_bugs)
+	mrs	ip, cpsr
+	bic	ip, ip, #F_BIT
+	msr	cpsr, ip
+	mov	pc, lr
+
+/*
+ * cpu_arm922_proc_init()
+ */
+ENTRY(cpu_arm922_proc_init)
+	mov	pc, lr
+
+/*
+ * cpu_arm922_proc_fin()
+ */
+ENTRY(cpu_arm922_proc_fin)
+	stmfd	sp!, {lr}
+	mov	ip, #F_BIT | I_BIT | SVC_MODE
+	msr	cpsr_c, ip
+	bl	cpu_arm922_cache_clean_invalidate_all
+	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
+	bic	r0, r0, #0x1000			@ ...i............
+	bic	r0, r0, #0x000e			@ ............wca.
+	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
+	ldmfd	sp!, {pc}
+
+/*
+ * cpu_arm922_reset(loc)
+ *
+ * Perform a soft reset of the system.  Put the CPU into the
+ * same state as it would be if it had been reset, and branch
+ * to what would be the reset vector.
+ *
+ * loc: location to jump to for soft reset
+ */
+	.align	5
+ENTRY(cpu_arm922_reset)
+	mov	ip, #0
+	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
+	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
+	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
+	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
+	bic	ip, ip, #0x000f			@ ............wcam
+	bic	ip, ip, #0x1100			@ ...i...s........
+	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
+	mov	pc, r0
+
+/*
+ * cpu_arm922_do_idle()
+ */
+	.align	5
+ENTRY(cpu_arm922_do_idle)
+#if defined(CONFIG_CPU_ARM922_CPU_IDLE)
+	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
+#endif
+	mov	pc, lr
+
+/* ================================= CACHE ================================ */
+
+
+/*
+ * cpu_arm922_cache_clean_invalidate_all()
+ *
+ * clean and invalidate all cache lines
+ *
+ * Note:
+ *  1. we should preserve r0 at all times
+ */
+	.align	5
+ENTRY(cpu_arm922_cache_clean_invalidate_all)
+	mov	r2, #1
+cpu_arm922_cache_clean_invalidate_all_r2:
+	mov	ip, #0
+#ifdef CONFIG_CPU_ARM922_WRITETHROUGH
+	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
+#else
+/*
+ * 'Clean & Invalidate whole DCache'
+ * Re-written to use Index Ops.
+ * Uses registers r1, r3 and ip
+ */
+	mov	r1, #3 << 5			@ 4 segments
+1:	orr	r3, r1, #63 << 26		@ 64 entries
+2:	mcr	p15, 0, r3, c7, c14, 2		@ clean & invalidate D index
+	subs	r3, r3, #1 << 26
+	bcs	2b				@ entries 63 to 0
+	subs	r1, r1, #1 << 5
+	bcs	1b				@ segments 7 to 0
+#endif
+	teq	r2, #0
+	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
+	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+/*
+ * cpu_arm922_cache_clean_invalidate_range(start, end, flags)
+ *
+ * clean and invalidate all cache lines associated with this area of memory
+ *
+ * start: Area start address
+ * end:   Area end address
+ * flags: nonzero for I cache as well
+ */
+		.align	5
+ENTRY(cpu_arm922_cache_clean_invalidate_range)
+	bic	r0, r0, #DCACHELINESIZE - 1	@ && added by PGM
+	bic	r1, r1, #DCACHELINESIZE - 1     @ && added by DHM
+	sub	r3, r1, r0
+	cmp	r3, #MAX_AREA_SIZE
+	bgt	cpu_arm922_cache_clean_invalidate_all_r2
+1:	teq	r2, #0
+#ifdef CONFIG_CPU_ARM922_WRITETHROUGH
+	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
+	add	r0, r0, #DCACHELINESIZE
+	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
+	add	r0, r0, #DCACHELINESIZE
+#else
+	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
+	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
+	add	r0, r0, #DCACHELINESIZE
+	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
+	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
+	add	r0, r0, #DCACHELINESIZE
+#endif
+	cmp	r0, r1
+	blt	1b
+
+	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+/*
+ * cpu_arm922_flush_ram_page(page)
+ *
+ * clean and invalidate all cache lines associated with this area of memory
+ *
+ * page: page to clean and invalidate
+ */
+	.align	5
+ENTRY(cpu_arm922_flush_ram_page)
+	mov	r1, #PAGESIZE
+#ifdef CONFIG_CPU_ARM922_WRITETHROUGH
+1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+	add	r0, r0, #DCACHELINESIZE
+	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+	add	r0, r0, #DCACHELINESIZE
+#else
+1:	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
+	add	r0, r0, #DCACHELINESIZE
+	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
+	add	r0, r0, #DCACHELINESIZE
+#endif
+	subs	r1, r1, #2 * DCACHELINESIZE
+	bne	1b
+	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+/* ================================ D-CACHE =============================== */
+
+/*
+ * cpu_arm922_dcache_invalidate_range(start, end)
+ *
+ * throw away all D-cached data in specified region without an obligation
+ * to write them back.  Note however that we must clean the D-cached entries
+ * around the boundaries if the start and/or end address are not cache
+ * aligned.
+ *
+ * start: virtual start address
+ * end:   virtual end address
+ */
+	.align	5
+ENTRY(cpu_arm922_dcache_invalidate_range)
+#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
+	tst	r0, #DCACHELINESIZE - 1
+	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
+	tst	r1, #DCACHELINESIZE - 1
+	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
+#endif		@ clean D entry
+	bic	r0, r0, #DCACHELINESIZE - 1
+	bic	r1, r1, #DCACHELINESIZE - 1
+1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+	add	r0, r0, #DCACHELINESIZE
+	cmp	r0, r1
+	blt	1b
+	mov	pc, lr
+
+/*
+ * cpu_arm922_dcache_clean_range(start, end)
+ *
+ * For the specified virtual address range, ensure that all caches contain
+ * clean data, such that peripheral accesses to the physical RAM fetch
+ * correct data.
+ *
+ * start: virtual start address
+ * end:   virtual end address
+ */
+	.align	5
+ENTRY(cpu_arm922_dcache_clean_range)
+#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
+	bic	r0, r0, #DCACHELINESIZE - 1
+	sub	r1, r1, r0
+	cmp	r1, #MAX_AREA_SIZE
+	mov	r2, #0
+	bgt	cpu_arm922_cache_clean_invalidate_all_r2
+
+	bic	r1, r1, #DCACHELINESIZE -1
+	add	r1, r1, #DCACHELINESIZE
+
+1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	add	r0, r0, #DCACHELINESIZE
+	subs	r1, r1, #DCACHELINESIZE
+	bpl	1b
+#endif
+	mcr	p15, 0, r2, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+/*
+ * cpu_arm922_dcache_clean_page(page)
+ *
+ * Cleans a single page of dcache so that if we have any future aliased
+ * mappings, they will be consistent at the time that they are created.
+ *
+ * page: virtual address of page to clean from dcache
+ *
+ * Note:
+ *  1. we don't need to flush the write buffer in this case.
+ *  2. we don't invalidate the entries since when we write the page
+ *     out to disk, the entries may get reloaded into the cache.
+ */
+	.align	5
+ENTRY(cpu_arm922_dcache_clean_page)
+#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
+	mov	r1, #PAGESIZE
+1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	add	r0, r0, #DCACHELINESIZE
+	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	add	r0, r0, #DCACHELINESIZE
+	subs	r1, r1, #2 * DCACHELINESIZE
+	bne	1b
+#endif
+	mov	pc, lr
+
+/*
+ * cpu_arm922_dcache_clean_entry(addr)
+ *
+ * Clean the specified entry of any caches such that the MMU
+ * translation fetches will obtain correct data.
+ *
+ * addr: cache-unaligned virtual address
+ */
+	.align	5
+ENTRY(cpu_arm922_dcache_clean_entry)
+#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
+	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+#endif
+	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+/* ================================ I-CACHE =============================== */
+
+/*
+ * cpu_arm922_icache_invalidate_range(start, end)
+ *
+ * invalidate a range of virtual addresses from the Icache
+ *
+ * This is a little misleading, it is not intended to clean out
+ * the i-cache but to make sure that any data written to the
+ * range is made consistant.  This means that when we execute code
+ * in that region, everything works as we expect.
+ *
+ * This generally means writing back data in the Dcache and
+ * write buffer and flushing the Icache over that region
+ *
+ * start: virtual start address
+ * end:   virtual end address
+ *
+ * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to
+ * loop twice, once for i-cache, once for d-cache)
+ */
+	.align	5
+ENTRY(cpu_arm922_icache_invalidate_range)
+	bic	r0, r0, #ICACHELINESIZE - 1	@ Safety check
+	sub	r1, r1, r0
+	cmp	r1, #MAX_AREA_SIZE
+	bgt	cpu_arm922_cache_clean_invalidate_all_r2
+
+	bic	r1, r1, #ICACHELINESIZE - 1
+	add	r1, r1, #ICACHELINESIZE
+
+1:	mcr	p15, 0, r0, c7, c5, 1		@ Clean I entry
+	mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
+	add	r0, r0, #ICACHELINESIZE
+	subs	r1, r1, #ICACHELINESIZE
+	bne	1b
+
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+ENTRY(cpu_arm922_icache_invalidate_page)
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+
+/* ================================== TLB ================================= */
+
+/*
+ * cpu_arm922_tlb_invalidate_all()
+ *
+ * Invalidate all TLB entries
+ */
+	.align	5
+ENTRY(cpu_arm922_tlb_invalidate_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D TLBs
+	mov	pc, lr
+
+/*
+ * cpu_arm922_tlb_invalidate_range(start, end)
+ *
+ * invalidate TLB entries covering the specified range
+ *
+ * start: range start address
+ * end:   range end address
+ */
+	.align	5
+ENTRY(cpu_arm922_tlb_invalidate_range)
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+
+	mov	r3, #PAGESIZE
+	sub	r3, r3, #1
+	bic 	r0, r0, r3
+	bic	r1, r1, r3
+
+1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+	add	r0, r0, #PAGESIZE
+	cmp	r0, r1
+	blt	1b
+	mov	pc, lr
+
+/*
+ * cpu_arm922_tlb_invalidate_page(page, flags)
+ *
+ * invalidate the TLB entries for the specified page.
+ *
+ * page:  page to invalidate
+ * flags: non-zero if we include the I TLB
+ */
+	.align	5
+ENTRY(cpu_arm922_tlb_invalidate_page)
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+	teq	r1, #0
+	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+	mov	pc, lr
+
+/* =============================== PageTable ============================== */
+
+/*
+ * cpu_arm922_set_pgd(pgd)
+ *
+ * Set the translation base pointer to be as described by pgd.
+ *
+ * pgd: new page tables
+ */
+	.align	5
+ENTRY(cpu_arm922_set_pgd)
+	mov	ip, #0
+#ifdef CONFIG_CPU_ARM922_WRITETHROUGH
+	/* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */
+	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
+#else
+@ && 'Clean & Invalidate whole DCache'
+@ && Re-written to use Index Ops.
+@ && Uses registers r1, r3 and ip
+
+	mov	r1, #3 << 5			@ 4 segments
+1:	orr	r3, r1, #63 << 26		@ 64 entries
+2:	mcr	p15, 0, r3, c7, c14, 2		@ clean & invalidate D index
+	subs	r3, r3, #1 << 26
+	bcs	2b				@ entries 63 to 0
+	subs	r1, r1, #1 << 5
+	bcs	1b				@ segments 7 to 0
+#endif
+	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
+	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
+	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
+	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
+	mov	pc, lr
+
+/*
+ * cpu_arm922_set_pmd(pmdp, pmd)
+ *
+ * Set a level 1 translation table entry, and clean it out of
+ * any caches such that the MMUs can load it correctly.
+ *
+ * pmdp: pointer to PMD entry
+ * pmd:  PMD value to store
+ */
+	.align	5
+ENTRY(cpu_arm922_set_pmd)
+#ifdef CONFIG_CPU_ARM922_WRITETHROUGH
+	eor	r2, r1, #0x0a			@ C & Section
+	tst	r2, #0x0b
+	biceq	r1, r1, #4			@ clear bufferable bit
+#endif
+	str	r1, [r0]
+	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+/*
+ * cpu_arm922_set_pte(ptep, pte)
+ *
+ * Set a PTE and flush it out
+ */
+	.align	5
+ENTRY(cpu_arm922_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
+
+#ifdef CONFIG_CPU_ARM922_WRITETHROUGH
+	eor	r3, r2, #0x0a			@ C & small page?
+	tst	r3, #0x0b
+	biceq	r2, r2, #4
+#endif
+	str	r2, [r0]			@ hardware version
+	mov	r0, r0
+	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+	mov	pc, lr
+
+
+cpu_manu_name:
+	.asciz	"ARM/ALTERA"
+ENTRY(cpu_arm922_name)
+	.ascii	"Arm922T"
+#if defined(CONFIG_CPU_ARM922_CPU_IDLE)
+	.ascii	"s"
+#endif
+#if defined(CONFIG_CPU_ARM922_I_CACHE_ON)
+	.ascii	"i"
+#endif
+#if defined(CONFIG_CPU_ARM922_D_CACHE_ON)
+	.ascii	"d"
+#if defined(CONFIG_CPU_ARM922_WRITETHROUGH)
+	.ascii	"(wt)"
+#else
+	.ascii	"(wb)"
+#endif
+#endif
+	.ascii	"\0"
+	.align
+
+	.section ".text.init", #alloc, #execinstr
+
+__arm922_setup:
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
+	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
+	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
+	mcr	p15, 0, r4, c2, c0		@ load page table pointer
+	mov	r0, #0x1f			@ Domains 0, 1 = client
+	mcr	p15, 0, r0, c3, c0		@ load domain access register
+	mrc	p15, 0, r0, c1, c0		@ get control register v4
+/*
+ * Clear out 'unwanted' bits (then put them in if we need them)
+ */
+						@   VI ZFRS BLDP WCAM
+	bic	r0, r0, #0x0e00
+	bic	r0, r0, #0x0002
+	bic	r0, r0, #0x000c
+	bic	r0, r0, #0x1000			@ ...0 000. .... 000.
+/*
+ * Turn on what we want
+ */
+	orr	r0, r0, #0x0031
+	orr	r0, r0, #0x2100			@ ..1. ...1 ..11 ...1
+
+#ifdef CONFIG_CPU_ARM922_D_CACHE_ON
+	orr	r0, r0, #0x0004			@ .... .... .... .1..
+#endif
+#ifdef CONFIG_CPU_ARM922_I_CACHE_ON
+	orr	r0, r0, #0x1000			@ ...1 .... .... ....
+#endif
+	mov	pc, lr
+
+	.text
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ *	     come through these
+ */
+	.type	arm922_processor_functions, #object
+arm922_processor_functions:
+	.word	cpu_arm922_data_abort
+	.word	cpu_arm922_check_bugs
+	.word	cpu_arm922_proc_init
+	.word	cpu_arm922_proc_fin
+	.word	cpu_arm922_reset
+	.word   cpu_arm922_do_idle
+
+	/* cache */
+	.word	cpu_arm922_cache_clean_invalidate_all
+	.word	cpu_arm922_cache_clean_invalidate_range
+	.word	cpu_arm922_flush_ram_page
+
+	/* dcache */
+	.word	cpu_arm922_dcache_invalidate_range
+	.word	cpu_arm922_dcache_clean_range
+	.word	cpu_arm922_dcache_clean_page
+	.word	cpu_arm922_dcache_clean_entry
+
+	/* icache */
+	.word	cpu_arm922_icache_invalidate_range
+	.word	cpu_arm922_icache_invalidate_page
+
+	/* tlb */
+	.word	cpu_arm922_tlb_invalidate_all
+	.word	cpu_arm922_tlb_invalidate_range
+	.word	cpu_arm922_tlb_invalidate_page
+
+	/* pgtable */
+	.word	cpu_arm922_set_pgd
+	.word	cpu_arm922_set_pmd
+	.word	cpu_arm922_set_pte
+	.size	arm922_processor_functions, . - arm922_processor_functions
+
+	.type	cpu_arm922_info, #object
+cpu_arm922_info:
+	.long	cpu_manu_name
+	.long	cpu_arm922_name
+	.size	cpu_arm922_info, . - cpu_arm922_info
+
+	.type	cpu_arch_name, #object
+cpu_arch_name:
+	.asciz	"armv4"
+	.size	cpu_arch_name, . - cpu_arch_name
+
+	.type	cpu_elf_name, #object
+cpu_elf_name:
+	.asciz	"v4"
+	.size	cpu_elf_name, . - cpu_elf_name
+	.align
+
+	.section ".proc.info", #alloc, #execinstr
+
+	.type	__arm922_proc_info,#object
+__arm922_proc_info:
+	.long	0x41009220
+	.long	0xff00fff0
+	.long	0x00000c1e			@ mmuflags
+	b	__arm922_setup
+	.long	cpu_arch_name
+	.long	cpu_elf_name
+	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+	.long	cpu_arm922_info
+	.long	arm922_processor_functions
+	.size	__arm922_proc_info, . - __arm922_proc_info
diff -urN linux-2.4.19-pre4/arch/arm/mm/proc-arm926.S linux-2.4.19-pre5/arch/arm/mm/proc-arm926.S
--- linux-2.4.19-pre4/arch/arm/mm/proc-arm926.S	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre5/arch/arm/mm/proc-arm926.S	Fri Mar 29 14:49:19 2002
@@ -56,35 +56,39 @@
  * cpu_arm926_data_abort()
  *
  * obtain information about current aborted instruction
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
  *
  * Inputs:
- *  r0 = address of abort 
- *  r1 = cpsr of abort 
+ *  r2 = address of abort 
+ *  r3 = cpsr of abort
  *
  * Returns:
  *  r0 = address of abort
  *  r1 != 0 if writing
  *  r3 = FSR
+ *  r4 = corrupted
  */
 	.align	5
 ENTRY(cpu_arm926_data_abort)
-	tst	r1, #1<<24			@ Check for Jbit (NE -> found)
-	movne	r1, #-1 			@ Mark as writing
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	mrc	p15, 0, r4, c5, c0, 0		@ get FSR
+
+	tst	r3, #1<<24			@ Check for Jbit (NE -> found)
+	movne	r3, #-1 			@ Mark as writing
 	bne	2f
 
-	tst	r1, #1<<5			@ Check for Thumb-bit (NE -> found)
-	ldrneh	r1, [r0]			@ Read aborted Thumb instruction        
+	tst	r3, #1<<5			@ Check for Thumb-bit (NE -> found)
+	ldrneh	r1, [r2]			@ Read aborted Thumb instruction        
 	tstne	r1, r1, lsr #12 		@ C = bit 11
 
-	ldreq	r1, [r0]			@ Read aborted ARM instruction
+	ldreq	r1, [r2]			@ Read aborted ARM instruction
 	tsteq	r1, r1, lsr #21 		@ C = bit 20
 
 	sbc	r1, r1, r1			@ r1 = C - 1
 2:
-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
-	and	r3, r3, #255
-	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-
+	and	r3, r4, #255
 	mov	pc, lr
 
 /*
@@ -193,10 +197,9 @@
 	.align	5
 ENTRY(cpu_arm926_cache_clean_invalidate_range)
 	bic	r0, r0, #DCACHELINESIZE - 1	@ && added by PGM
-	bic	r1, r1, #DCACHELINESIZE - 1	@ && added by DHM
 	sub	r3, r1, r0
 	cmp	r3, #MAX_AREA_SIZE
-	bgt	cpu_arm926_cache_clean_invalidate_all_r2
+	bhi	cpu_arm926_cache_clean_invalidate_all_r2
 
 1:	teq	r2, #0
 #ifdef CONFIG_CPU_ARM926_WRITETHROUGH
@@ -216,7 +219,7 @@
 #endif
         
 	cmp	r0, r1
-	blt	1b
+	blo	1b
 
 	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
 
@@ -267,14 +270,13 @@
 	tst	r0, #DCACHELINESIZE - 1
 	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
 	tst	r1, #DCACHELINESIZE - 1
-	mcrne	p15, 0, r1, c7, c10, 1
-#endif		@ clean D entry
+	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
+#endif
 	bic	r0, r0, #DCACHELINESIZE - 1
-	bic	r1, r1, #DCACHELINESIZE - 1
 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
 	add	r0, r0, #DCACHELINESIZE
 	cmp	r0, r1
-	blt	1b
+	blo	1b
 	mov	pc, lr
 
 /*
@@ -291,18 +293,15 @@
 ENTRY(cpu_arm926_dcache_clean_range)
 #ifndef CONFIG_CPU_ARM926_WRITETHROUGH
 	bic	r0, r0, #DCACHELINESIZE - 1
-	sub	r1, r1, r0
-	cmp	r1, #MAX_AREA_SIZE
+	sub	r3, r1, r0
+	cmp	r3, #MAX_AREA_SIZE
 	mov	r2, #0
-	bgt	cpu_arm926_cache_clean_invalidate_all_r2
-
-	bic	r1, r1, #DCACHELINESIZE -1
-	add	r1, r1, #DCACHELINESIZE
+	bhi	cpu_arm926_cache_clean_invalidate_all_r2
 
 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 	add	r0, r0, #DCACHELINESIZE
-	subs	r1, r1, #DCACHELINESIZE
-	bpl	1b
+	cmp	r0, r1
+	blo	1b
 #endif
 	mcr	p15, 0, r2, c7, c10, 4		@ drain WB
 	mov	pc, lr
@@ -354,7 +353,12 @@
 /*
  * cpu_arm926_icache_invalidate_range(start, end)
  *
- * invalidate a range of virtual addresses from the Icache
+ * This *is not* just icache.  It is to make data written to memory
+ * consistent such that instructions fetched from the region are what
+ * we expect.
+ *
+ * This is typically used after we have copied a module into kernel space,
+ * and we're about to start executing code from that module.
  *
  * start: virtual start address
  * end:   virtual end address
@@ -362,17 +366,14 @@
 	.align	5
 ENTRY(cpu_arm926_icache_invalidate_range)
 	bic	r0, r0, #DCACHELINESIZE - 1	@ Safety check
-	sub	r1, r1, r0
-	cmp	r1, #MAX_AREA_SIZE
-	bgt	cpu_arm926_cache_clean_invalidate_all_r2
-
-	bic	r1, r1, #DCACHELINESIZE - 1
-	add	r1, r1, #DCACHELINESIZE
+	sub	r3, r1, r0
+	cmp	r3, #MAX_AREA_SIZE
+	bhi	cpu_arm926_cache_clean_invalidate_all_r2
 
 1:	mcr	p15, 0, r0, c7, c5, 1		@ clean I entries
 	add	r0, r0, #DCACHELINESIZE
-	subs	r1, r1, #DCACHELINESIZE
-	bne	1b
+	cmp	r0, r1
+	blo	1b
 
 	mov	r0, #0
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
@@ -410,16 +411,14 @@
 	mov	r3, #0
 	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
 
-	mov	r3, #PAGESIZE
-	sub	r3, r3, #1
-	bic	r0, r0, r3
-	bic	r1, r1, r3
+	bic	r0, r0, #(PAGESIZE - 1) & 0x00ff
+	bic	r0, r0, #(PAGESIZE - 1) & 0xff00
 
 1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
 	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
 	add	r0, r0, #PAGESIZE
 	cmp	r0, r1
-	blt	1b
+	blo	1b
 	mov	pc, lr
 
 /*
diff -urN linux-2.4.19-pre4/arch/arm/mm/proc-sa110.S linux-2.4.19-pre5/arch/arm/mm/proc-sa110.S
--- linux-2.4.19-pre4/arch/arm/mm/proc-sa110.S	Thu Oct 25 13:53:46 2001
+++ linux-2.4.19-pre5/arch/arm/mm/proc-sa110.S	Fri Mar 29 14:49:19 2002
@@ -69,24 +69,29 @@
 /*
  * cpu_sa110_data_abort()
  *
- * obtain information about current aborted instruction
+ * obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
  *
- * r0 = address of aborted instruction
+ *  r2 = address of aborted instruction
+ *  r3 = cpsr
  *
  * Returns:
  *  r0 = address of abort
  *  r1 != 0 if writing
  *  r3 = FSR
+ *  r4 = corrupted
  */
 	.align	5
 ENTRY(cpu_sa110_data_abort)
 ENTRY(cpu_sa1100_data_abort)
-	ldr	r1, [r0]			@ read aborted instruction
+	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	ldr	r1, [r2]			@ read aborted instruction
+	and	r3, r3, #255
 	tst	r1, r1, lsr #21			@ C = bit 20
-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
 	sbc	r1, r1, r1			@ r1 = C - 1
-	and	r3, r3, #255
 	mov	pc, lr
 
 /*
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/ARM-gcc.h linux-2.4.19-pre5/arch/arm/nwfpe/ARM-gcc.h
--- linux-2.4.19-pre4/arch/arm/nwfpe/ARM-gcc.h	Thu Jun 17 01:11:35 1999
+++ linux-2.4.19-pre5/arch/arm/nwfpe/ARM-gcc.h	Fri Mar 29 14:49:19 2002
@@ -1,11 +1,3 @@
-
-/*
--------------------------------------------------------------------------------
-One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
--------------------------------------------------------------------------------
-*/
-#define LITTLEENDIAN
-
 /*
 -------------------------------------------------------------------------------
 The macro `BITS64' can be defined to indicate that 64-bit integer types are
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/ChangeLog linux-2.4.19-pre5/arch/arm/nwfpe/ChangeLog
--- linux-2.4.19-pre4/arch/arm/nwfpe/ChangeLog	Wed Oct 20 16:29:08 1999
+++ linux-2.4.19-pre5/arch/arm/nwfpe/ChangeLog	Fri Mar 29 14:49:19 2002
@@ -1,3 +1,26 @@
+2002-01-19  Russell King <rmk@arm.linux.org.uk>
+
+	* fpa11.h - Add documentation
+	          - remove userRegisters pointer from this structure.
+	          - add new method to obtain integer register values.
+	* softfloat.c - Remove float128
+	* softfloat.h - Remove float128
+	* softfloat-specialize - Remove float128
+
+	* The FPA11 structure is not a kernel-specific data structure.
+	  It is used by users of ptrace to examine the values of the
+	  floating point registers.  Therefore, any changes to the
+	  FPA11 structure (size or position of elements contained
+	  within) have to be well thought out.
+
+	* Since 128-bit float requires the FPA11 structure to change
+	  size, it has been removed.  128-bit float is currently unused,
+	  and needs various things to be re-worked so that we won't
+	  overflow the available space in the task structure.
+
+	* The changes are designed to break any patch that goes on top
+	  of this code, so that the authors properly review their changes.
+
 1999-08-19  Scott Bambrough  <scottb@netwinder.org>
 
 	* fpmodule.c - Changed version number to 0.95
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/double_cpdo.c linux-2.4.19-pre5/arch/arm/nwfpe/double_cpdo.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/double_cpdo.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/double_cpdo.c	Fri Mar 29 14:49:19 2002
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 
 float64 float64_exp(float64 Fm);
 float64 float64_ln(float64 Fm);
@@ -165,8 +165,7 @@
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fDouble = 
-             int32_to_float64(float64_to_int32(rFm));
+         fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm);
       break;
 
       case SQT_CODE:
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/entry.S linux-2.4.19-pre5/arch/arm/nwfpe/entry.S
--- linux-2.4.19-pre4/arch/arm/nwfpe/entry.S	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/entry.S	Fri Mar 29 14:49:19 2002
@@ -50,11 +50,8 @@
 
 This routine does three things:
 
-1) It saves SP into a variable called userRegisters.  The kernel has
-created a struct pt_regs on the stack and saved the user registers
-into it.  See /usr/include/asm/proc/ptrace.h for details.  The
-emulator code uses userRegisters as the base of an array of words from
-which the contents of the registers can be extracted.
+1) The kernel has created a struct pt_regs on the stack and saved the
+user registers into it.  See inclue/asm-arm/proc/ptrace.h for details.
 
 2) It calls EmulateAll to emulate a floating point instruction.
 EmulateAll returns 1 if the emulation was successful, or 0 if not.
@@ -73,21 +70,16 @@
 
 	.globl	nwfpe_enter
 nwfpe_enter:
-	/* ?? Could put userRegisters and fpa11 into fixed regs during
-	   emulation.  This would reduce load/store overhead at the expense
-	   of stealing two regs from the register allocator.  Not sure if
-	   it's worth it.  */
-	str sp, [r10]                   @ Store the user registers pointer in the fpa11 structure.
-        mov r4, sp			@ use r4 for local pointer
-        mov r10, lr			@ save the failure-return addresses
+        mov r4, lr			@ save the failure-return addresses
+	mov sl, sp			@ we access the registers via 'sl'
 
-        ldr r5, [r4, #60]	 	@ get contents of PC;
+        ldr r5, [sp, #60]	 	@ get contents of PC;
 	sub r8, r5, #4
 .Lx2:	ldrt r0, [r8]			@ get actual instruction into r0
 emulate:
 	bl EmulateAll			@ emulate the instruction
    	cmp r0, #0			@ was emulation successful
-        moveq pc, r10			@ no, return failure
+        moveq pc, r4			@ no, return failure
 
 next:
 .Lx1:	ldrt r6, [r5], #4		@ get the next instruction and
@@ -99,10 +91,10 @@
         teqne r2, #0x0E000000
         movne pc, r9			@ return ok if not a fp insn
 
-        str r5, [r4, #60]		@ update PC copy in regs
+        str r5, [sp, #60]		@ update PC copy in regs
 
         mov r0, r6			@ save a copy
-        ldr r1, [r4, #64]		@ fetch the condition codes
+        ldr r1, [sp, #64]		@ fetch the condition codes
    	bl  checkCondition		@ check the condition
    	cmp r0, #0			@ r0 = 0 ==> condition failed
 
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/entry26.S linux-2.4.19-pre5/arch/arm/nwfpe/entry26.S
--- linux-2.4.19-pre4/arch/arm/nwfpe/entry26.S	Wed Apr 11 19:02:27 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/entry26.S	Fri Mar 29 14:49:19 2002
@@ -65,18 +65,8 @@
 
 	.globl	nwfpe_enter
 nwfpe_enter:
-	ldr	r4, =userRegisters
-	str	sp, [r4]		@ save pointer to user regs
-
-	mov	r10, sp, lsr #13	@ find workspace
-	mov	r10, r10, lsl #13
-	add	r10, r10, #TSS_FPESAVE
-
-	ldr	r4, =fpa11
-	str	r10, [r4]		@ store pointer to our state
-	mov	r4, sp			@ use r4 for local pointer
-
-	ldr	r5, [r4, #60]		@ get contents of PC
+	mov	sl, sp
+	ldr	r5, [sp, #60]		@ get contents of PC
 	bic	r5, r5, #0xfc000003
 	ldr	r0, [r5, #-4]		@ get actual instruction into r0
 	bl	EmulateAll		@ emulate the instruction
@@ -93,10 +83,10 @@
 	teqne	r2, #0x0E000000
 	bne	ret_from_exception	@ return ok if not a fp insn
 
-	ldr	r9, [r4, #60]		@ get new condition codes
+	ldr	r9, [sp, #60]		@ get new condition codes
 	and	r9, r9, #0xfc000003
 	orr	r7, r5, r9
-	str	r7, [r4, #60]		@ update PC copy in regs
+	str	r7, [sp, #60]		@ update PC copy in regs
 
 	mov	r0, r6			@ save a copy
 	mov	r1, r9			@ fetch the condition codes
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/extended_cpdo.c linux-2.4.19-pre5/arch/arm/nwfpe/extended_cpdo.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/extended_cpdo.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/extended_cpdo.c	Fri Mar 29 14:49:19 2002
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 
 floatx80 floatx80_exp(floatx80 Fm);
 floatx80 floatx80_ln(floatx80 Fm);
@@ -157,8 +157,7 @@
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fExtended = 
-             int32_to_floatx80(floatx80_to_int32(rFm));
+         fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm);
       break;
 
       case SQT_CODE:
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/fpa11.c linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/fpa11.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.c	Fri Mar 29 14:49:19 2002
@@ -19,14 +19,15 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <asm/system.h>
-
 #include "fpa11.h"
+
 #include "fpopcode.h"
 
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
+#include <asm/system.h>
+
 /* forward declarations */
 unsigned int EmulateCPDO(const unsigned int);
 unsigned int EmulateCPDT(const unsigned int);
@@ -56,6 +57,7 @@
 void SetRoundingMode(const unsigned int opcode)
 {
 #if MAINTAIN_FPCR
+   FPA11 *fpa11 = GET_FPA11();
    fpa11->fpcr &= ~MASK_ROUNDING_MODE;
 #endif   
    switch (opcode & MASK_ROUNDING_MODE)
@@ -94,6 +96,7 @@
 void SetRoundingPrecision(const unsigned int opcode)
 {
 #if MAINTAIN_FPCR
+   FPA11 *fpa11 = GET_FPA11();
    fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
 #endif   
    switch (opcode & MASK_ROUNDING_PRECISION)
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/fpa11.h linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.h
--- linux-2.4.19-pre4/arch/arm/nwfpe/fpa11.h	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11.h	Fri Mar 29 14:49:19 2002
@@ -22,45 +22,67 @@
 #ifndef __FPA11_H__
 #define __FPA11_H__
 
-/* includes */
-#include "fpsr.h"		/* FP control and status register definitions */
-#include "softfloat.h"
+#define GET_FPA11() ((FPA11 *)(&current->thread.fpstate))
+
+/*
+ * The processes registers are always at the very top of the 8K
+ * stack+task struct.  Use the same method as 'current' uses to
+ * reach them.
+ */
+register unsigned int *user_registers asm("sl");
+
+#define GET_USERREG() (user_registers)
 
 /* Need task_struct */
 #include <linux/sched.h>
 
+/* includes */
+#include "fpsr.h"		/* FP control and status register definitions */
+#include "softfloat.h"
+
 #define		typeNone		0x00
 #define		typeSingle		0x01
 #define		typeDouble		0x02
 #define		typeExtended		0x03
 
+/*
+ * This must be no more and no less than 12 bytes.
+ */
 typedef union tagFPREG {
-   float32  fSingle;
-   float64  fDouble;
    floatx80 fExtended;
+   float64  fDouble;
+   float32  fSingle;
 } FPREG;
 
-/* FPA11 device model */
+/*
+ * FPA11 device model.
+ *
+ * This structure is exported to user space.  Do not re-order.
+ * Only add new stuff to the end, and do not change the size of
+ * any element.  Elements of this structure are used by user
+ * space, and must match struct user_fp in include/asm-arm/user.h.
+ * We include the byte offsets below for documentation purposes.
+ *
+ * The size of this structure and FPREG are checked by fpmodule.c
+ * on initialisation.  If the rules have been broken, NWFPE will
+ * not initialise.
+ */
 typedef struct tagFPA11 {
-  unsigned int *userRegisters;
-  FPREG fpreg[8];		/* 8 floating point registers */
-  FPSR fpsr;			/* floating point status register */
-  FPCR fpcr;			/* floating point control register */
-  unsigned char fType[8];	/* type of floating point value held in
-				   floating point registers.  One of none
-				   single, double or extended. */
-  int initflag;			/* this is special.  The kernel guarantees
-				   to set it to 0 when a thread is launched,
-				   so we can use it to detect whether this
-				   instance of the emulator needs to be
-				   initialised. */
+/*   0 */  FPREG fpreg[8];		/* 8 floating point registers */
+/*  96 */  FPSR fpsr;			/* floating point status register */
+/* 100 */  FPCR fpcr;			/* floating point control register */
+/* 104 */  unsigned char fType[8];	/* type of floating point value held in
+					   floating point registers.  One of none
+					   single, double or extended. */
+/* 112 */  int initflag;		/* this is special.  The kernel guarantees
+					   to set it to 0 when a thread is launched,
+					   so we can use it to detect whether this
+					   instance of the emulator needs to be
+					   initialised. */
 } FPA11;
 
 extern void resetFPA11(void);
 extern void SetRoundingMode(const unsigned int);
 extern void SetRoundingPrecision(const unsigned int);
 
-#define GET_FPA11() ((FPA11 *)(&current->thread.fpstate))
-#define GET_USERREG() (GET_FPA11()->userRegisters)
-
 #endif
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/fpa11_cpdt.c linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cpdt.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/fpa11_cpdt.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cpdt.c	Fri Mar 29 14:49:19 2002
@@ -20,9 +20,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/fpa11_cprt.c linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cprt.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/fpa11_cprt.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/fpa11_cprt.c	Fri Mar 29 14:49:19 2002
@@ -20,10 +20,10 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "milieu.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 #include "fpa11.inl"
 #include "fpmodule.h"
 #include "fpmodule.inl"
@@ -82,8 +82,7 @@
    
    unsigned int nRc = 1;
    SetRoundingMode(opcode);
-   SetRoundingPrecision(opcode);
-   
+
    switch (opcode & MASK_ROUNDING_PRECISION)
    {
       case ROUND_SINGLE:
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/fpmodule.c linux-2.4.19-pre5/arch/arm/nwfpe/fpmodule.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/fpmodule.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/fpmodule.c	Fri Mar 29 14:49:19 2002
@@ -21,6 +21,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
+
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/config.h>
@@ -36,7 +38,6 @@
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpmodule.h"
-#include "fpa11.h"
 #include "fpa11.inl"
 
 /* kernel symbols required for signal handling */
@@ -86,6 +87,11 @@
     return -EINVAL;
   }
 
+  if (sizeof(FPREG) != 12) {
+    printk(KERN_ERR "nwfpe: bad register size\n");
+    return -EINVAL;
+  }
+
 #ifdef MODULE
   if (!mod_member_present(&__this_module, can_unload))
     return -EINVAL;
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/fpopcode.c linux-2.4.19-pre5/arch/arm/nwfpe/fpopcode.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/fpopcode.c	Wed Apr 11 19:02:27 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/fpopcode.c	Fri Mar 29 14:49:19 2002
@@ -19,10 +19,10 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpsr.h"
-#include "fpa11.h"
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/single_cpdo.c linux-2.4.19-pre5/arch/arm/nwfpe/single_cpdo.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/single_cpdo.c	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre5/arch/arm/nwfpe/single_cpdo.c	Fri Mar 29 14:49:19 2002
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 
 float32 float32_exp(float32 Fm);
 float32 float32_ln(float32 Fm);
@@ -139,8 +139,7 @@
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fSingle = 
-             int32_to_float32(float32_to_int32(rFm));
+         fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm);
       break;
 
       case SQT_CODE:
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/softfloat-specialize linux-2.4.19-pre5/arch/arm/nwfpe/softfloat-specialize
--- linux-2.4.19-pre4/arch/arm/nwfpe/softfloat-specialize	Thu Jun 17 01:11:35 1999
+++ linux-2.4.19-pre5/arch/arm/nwfpe/softfloat-specialize	Fri Mar 29 14:49:19 2002
@@ -364,108 +364,3 @@
 }
 
 #endif
-
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-The pattern for a default generated quadruple-precision NaN.  The `high' and
-`low' values hold the most- and least-significant bits, respectively.
--------------------------------------------------------------------------------
-*/
-#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
-#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
-otherwise returns 0.
--------------------------------------------------------------------------------
-*/
-flag float128_is_nan( float128 a )
-{
-
-    return
-           ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
-        && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is a
-signaling NaN; otherwise returns 0.
--------------------------------------------------------------------------------
-*/
-flag float128_is_signaling_nan( float128 a )
-{
-
-    return
-           ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
-        && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point NaN
-`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
-exception is raised.
--------------------------------------------------------------------------------
-*/
-static commonNaNT float128ToCommonNaN( float128 a )
-{
-    commonNaNT z;
-
-    if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
-    z.sign = a.high>>63;
-    shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the canonical NaN `a' to the quadruple-
-precision floating-point format.
--------------------------------------------------------------------------------
-*/
-static float128 commonNaNToFloat128( commonNaNT a )
-{
-    float128 z;
-
-    shift128Right( a.high, a.low, 16, &z.high, &z.low );
-    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Takes two quadruple-precision floating-point values `a' and `b', one of
-which is a NaN, and returns the appropriate NaN result.  If either `a' or
-`b' is a signaling NaN, the invalid exception is raised.
--------------------------------------------------------------------------------
-*/
-static float128 propagateFloat128NaN( float128 a, float128 b )
-{
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
-
-    aIsNaN = float128_is_nan( a );
-    aIsSignalingNaN = float128_is_signaling_nan( a );
-    bIsNaN = float128_is_nan( b );
-    bIsSignalingNaN = float128_is_signaling_nan( b );
-    a.high |= LIT64( 0x0000800000000000 );
-    b.high |= LIT64( 0x0000800000000000 );
-    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
-    if ( aIsNaN ) {
-        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
-    }
-    else {
-        return b;
-    }
-
-}
-
-#endif
-
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/softfloat.c linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.c
--- linux-2.4.19-pre4/arch/arm/nwfpe/softfloat.c	Mon Nov 27 17:07:59 2000
+++ linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.c	Fri Mar 29 14:49:19 2002
@@ -28,6 +28,7 @@
 ===============================================================================
 */
 
+#include "fpa11.h"
 #include "milieu.h"
 #include "softfloat.h"
 
@@ -753,277 +754,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the least-significant 64 fraction bits of the quadruple-precision
-floating-point value `a'.
--------------------------------------------------------------------------------
-*/
-INLINE bits64 extractFloat128Frac1( float128 a )
-{
-
-    return a.low;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the most-significant 48 fraction bits of the quadruple-precision
-floating-point value `a'.
--------------------------------------------------------------------------------
-*/
-INLINE bits64 extractFloat128Frac0( float128 a )
-{
-
-    return a.high & LIT64( 0x0000FFFFFFFFFFFF );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the exponent bits of the quadruple-precision floating-point value
-`a'.
--------------------------------------------------------------------------------
-*/
-INLINE int32 extractFloat128Exp( float128 a )
-{
-
-    return ( a.high>>48 ) & 0x7FFF;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the sign bit of the quadruple-precision floating-point value `a'.
--------------------------------------------------------------------------------
-*/
-INLINE flag extractFloat128Sign( float128 a )
-{
-
-    return a.high>>63;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Normalizes the subnormal quadruple-precision floating-point value
-represented by the denormalized significand formed by the concatenation of
-`aSig0' and `aSig1'.  The normalized exponent is stored at the location
-pointed to by `zExpPtr'.  The most significant 49 bits of the normalized
-significand are stored at the location pointed to by `zSig0Ptr', and the
-least significant 64 bits of the normalized significand are stored at the
-location pointed to by `zSig1Ptr'.
--------------------------------------------------------------------------------
-*/
-static void
- normalizeFloat128Subnormal(
-     bits64 aSig0,
-     bits64 aSig1,
-     int32 *zExpPtr,
-     bits64 *zSig0Ptr,
-     bits64 *zSig1Ptr
- )
-{
-    int8 shiftCount;
-
-    if ( aSig0 == 0 ) {
-        shiftCount = countLeadingZeros64( aSig1 ) - 15;
-        if ( shiftCount < 0 ) {
-            *zSig0Ptr = aSig1>>( - shiftCount );
-            *zSig1Ptr = aSig1<<( shiftCount & 63 );
-        }
-        else {
-            *zSig0Ptr = aSig1<<shiftCount;
-            *zSig1Ptr = 0;
-        }
-        *zExpPtr = - shiftCount - 63;
-    }
-    else {
-        shiftCount = countLeadingZeros64( aSig0 ) - 15;
-        shortShift128Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
-        *zExpPtr = 1 - shiftCount;
-    }
-
-}
-
-/*
--------------------------------------------------------------------------------
-Packs the sign `zSign', the exponent `zExp', and the significand formed
-by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
-floating-point value, returning the result.  After being shifted into the
-proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
-added together to form the most significant 32 bits of the result.  This
-means that any integer portion of `zSig0' will be added into the exponent.
-Since a properly normalized significand will have an integer portion equal
-to 1, the `zExp' input should be 1 less than the desired result exponent
-whenever `zSig0' and `zSig1' concatenated form a complete, normalized
-significand.
--------------------------------------------------------------------------------
-*/
-INLINE float128
- packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
-{
-    float128 z;
-
-    z.low = zSig1;
-    z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Takes an abstract floating-point value having sign `zSign', exponent `zExp',
-and extended significand formed by the concatenation of `zSig0', `zSig1',
-and `zSig2', and returns the proper quadruple-precision floating-point value
-corresponding to the abstract input.  Ordinarily, the abstract value is
-simply rounded and packed into the quadruple-precision format, with the
-inexact exception raised if the abstract input cannot be represented
-exactly.  If the abstract value is too large, however, the overflow and
-inexact exceptions are raised and an infinity or maximal finite value is
-returned.  If the abstract value is too small, the input value is rounded to
-a subnormal number, and the underflow and inexact exceptions are raised if
-the abstract input cannot be represented exactly as a subnormal quadruple-
-precision floating-point number.
-    The input significand must be normalized or smaller.  If the input
-significand is not normalized, `zExp' must be 0; in that case, the result
-returned is a subnormal number, and it must not require rounding.  In the
-usual case that the input significand is normalized, `zExp' must be 1 less
-than the ``true'' floating-point exponent.  The handling of underflow and
-overflow follows the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-static float128
- roundAndPackFloat128(
-     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
-{
-    int8 roundingMode;
-    flag roundNearestEven, increment, isTiny;
-
-    roundingMode = float_rounding_mode;
-    roundNearestEven = ( roundingMode == float_round_nearest_even );
-    increment = ( (sbits64) zSig2 < 0 );
-    if ( ! roundNearestEven ) {
-        if ( roundingMode == float_round_to_zero ) {
-            increment = 0;
-        }
-        else {
-            if ( zSign ) {
-                increment = ( roundingMode == float_round_down ) && zSig2;
-            }
-            else {
-                increment = ( roundingMode == float_round_up ) && zSig2;
-            }
-        }
-    }
-    if ( 0x7FFD <= (bits32) zExp ) {
-        if (    ( 0x7FFD < zExp )
-             || (    ( zExp == 0x7FFD )
-                  && eq128(
-                         LIT64( 0x0001FFFFFFFFFFFF ),
-                         LIT64( 0xFFFFFFFFFFFFFFFF ),
-                         zSig0,
-                         zSig1
-                     )
-                  && increment
-                )
-           ) {
-            float_raise( float_flag_overflow | float_flag_inexact );
-            if (    ( roundingMode == float_round_to_zero )
-                 || ( zSign && ( roundingMode == float_round_up ) )
-                 || ( ! zSign && ( roundingMode == float_round_down ) )
-               ) {
-                return
-                    packFloat128(
-                        zSign,
-                        0x7FFE,
-                        LIT64( 0x0000FFFFFFFFFFFF ),
-                        LIT64( 0xFFFFFFFFFFFFFFFF )
-                    );
-            }
-            return packFloat128( zSign, 0x7FFF, 0, 0 );
-        }
-        if ( zExp < 0 ) {
-            isTiny =
-                   ( float_detect_tininess == float_tininess_before_rounding )
-                || ( zExp < -1 )
-                || ! increment
-                || lt128(
-                       zSig0,
-                       zSig1,
-                       LIT64( 0x0001FFFFFFFFFFFF ),
-                       LIT64( 0xFFFFFFFFFFFFFFFF )
-                   );
-            shift128ExtraRightJamming(
-                zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
-            zExp = 0;
-            if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
-            if ( roundNearestEven ) {
-                increment = ( (sbits64) zSig2 < 0 );
-            }
-            else {
-                if ( zSign ) {
-                    increment = ( roundingMode == float_round_down ) && zSig2;
-                }
-                else {
-                    increment = ( roundingMode == float_round_up ) && zSig2;
-                }
-            }
-        }
-    }
-    if ( zSig2 ) float_exception_flags |= float_flag_inexact;
-    if ( increment ) {
-        add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
-        zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
-    }
-    else {
-        if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
-    }
-    return packFloat128( zSign, zExp, zSig0, zSig1 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Takes an abstract floating-point value having sign `zSign', exponent `zExp',
-and significand formed by the concatenation of `zSig0' and `zSig1', and
-returns the proper quadruple-precision floating-point value corresponding to
-the abstract input.  This routine is just like `roundAndPackFloat128' except
-that the input significand has fewer bits and does not have to be normalized
-in any way.  In all cases, `zExp' must be 1 less than the ``true'' floating-
-point exponent.
--------------------------------------------------------------------------------
-*/
-static float128
- normalizeRoundAndPackFloat128(
-     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
-{
-    int8 shiftCount;
-    bits64 zSig2;
-
-    if ( zSig0 == 0 ) {
-        zSig0 = zSig1;
-        zSig1 = 0;
-        zExp -= 64;
-    }
-    shiftCount = countLeadingZeros64( zSig0 ) - 15;
-    if ( 0 <= shiftCount ) {
-        zSig2 = 0;
-        shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
-    }
-    else {
-        shift128ExtraRightJamming(
-            zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
-    }
-    zExp -= shiftCount;
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Returns the result of converting the 32-bit two's complement integer `a' to
@@ -1093,33 +823,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the 32-bit two's complement integer `a' to
-the quadruple-precision floating-point format.  The conversion is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 int32_to_float128( int32 a )
-{
-    flag zSign;
-    uint32 absA;
-    int8 shiftCount;
-    bits64 zSig0;
-
-    if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
-    zSign = ( a < 0 );
-    absA = zSign ? - a : a;
-    shiftCount = countLeadingZeros32( absA ) + 17;
-    zSig0 = absA;
-    return packFloat128( zSign, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Returns the result of converting the single-precision floating-point value
@@ -1256,40 +959,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the single-precision floating-point value
-`a' to the double-precision floating-point format.  The conversion is
-performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float32_to_float128( float32 a )
-{
-    flag aSign;
-    int16 aExp;
-    bits32 aSig;
-
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
-    if ( aExp == 0xFF ) {
-        if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) );
-        return packFloat128( aSign, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
-        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
-        --aExp;
-    }
-    return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Rounds the single-precision floating-point value `a' to an integer, and
@@ -2183,41 +1852,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the double-precision floating-point value
-`a' to the quadruple-precision floating-point format.  The conversion is
-performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float64_to_float128( float64 a )
-{
-    flag aSign;
-    int16 aExp;
-    bits64 aSig, zSig0, zSig1;
-
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
-    if ( aExp == 0x7FF ) {
-        if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a ) );
-        return packFloat128( aSign, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
-        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
-        --aExp;
-    }
-    shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
-    return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Rounds the double-precision floating-point value `a' to an integer, and
@@ -3029,35 +2663,6 @@
 
 }
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the extended double-precision floating-
-point value `a' to the quadruple-precision floating-point format.  The
-conversion is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 floatx80_to_float128( floatx80 a )
-{
-    flag aSign;
-    int16 aExp;
-    bits64 aSig, zSig0, zSig1;
-
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
-    if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
-        return commonNaNToFloat128( floatx80ToCommonNaN( a ) );
-    }
-    shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
-    return packFloat128( aSign, aExp, zSig0, zSig1 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Rounds the extended double-precision floating-point value `a' to an integer,
@@ -3825,1048 +3430,6 @@
                  != 0 );
     }
     return
-          aSign ? lt128( b.high, b.low, a.high, a.low )
-        : lt128( a.high, a.low, b.high, b.low );
-
-}
-
-#endif
-
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the 32-bit two's complement integer format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic---which means in particular that the conversion is rounded
-according to the current rounding mode.  If `a' is a NaN, the largest
-positive integer is returned.  Otherwise, if the conversion overflows, the
-largest integer with the same sign as `a' is returned.
--------------------------------------------------------------------------------
-*/
-int32 float128_to_int32( float128 a )
-{
-    flag aSign;
-    int32 aExp, shiftCount;
-    bits64 aSig0, aSig1;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
-    if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
-    aSig0 |= ( aSig1 != 0 );
-    shiftCount = 0x4028 - aExp;
-    if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
-    return roundAndPackInt32( aSign, aSig0 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the 32-bit two's complement integer format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic, except that the conversion is always rounded toward zero.  If
-`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
-conversion overflows, the largest integer with the same sign as `a' is
-returned.
--------------------------------------------------------------------------------
-*/
-int32 float128_to_int32_round_to_zero( float128 a )
-{
-    flag aSign;
-    int32 aExp, shiftCount;
-    bits64 aSig0, aSig1, savedASig;
-    int32 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    aSig0 |= ( aSig1 != 0 );
-    shiftCount = 0x402F - aExp;
-    if ( shiftCount < 17 ) {
-        if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
-        goto invalid;
-    }
-    else if ( 48 < shiftCount ) {
-        if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact;
-        return 0;
-    }
-    aSig0 |= LIT64( 0x0001000000000000 );
-    savedASig = aSig0;
-    aSig0 >>= shiftCount;
-    z = aSig0;
-    if ( aSign ) z = - z;
-    if ( ( z < 0 ) ^ aSign ) {
- invalid:
-        float_exception_flags |= float_flag_invalid;
-        return aSign ? 0x80000000 : 0x7FFFFFFF;
-    }
-    if ( ( aSig0<<shiftCount ) != savedASig ) {
-        float_exception_flags |= float_flag_inexact;
-    }
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the single-precision floating-point format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float32 float128_to_float32( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
-    bits32 zSig;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) {
-            return commonNaNToFloat32( float128ToCommonNaN( a ) );
-        }
-        return packFloat32( aSign, 0xFF, 0 );
-    }
-    aSig0 |= ( aSig1 != 0 );
-    shift64RightJamming( aSig0, 18, &aSig0 );
-    zSig = aSig0;
-    if ( aExp || zSig ) {
-        zSig |= 0x40000000;
-        aExp -= 0x3F81;
-    }
-    return roundAndPackFloat32( aSign, aExp, zSig );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the double-precision floating-point format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float64 float128_to_float64( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) {
-            return commonNaNToFloat64( float128ToCommonNaN( a ) );
-        }
-        return packFloat64( aSign, 0x7FF, 0 );
-    }
-    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
-    aSig0 |= ( aSig1 != 0 );
-    if ( aExp || aSig0 ) {
-        aSig0 |= LIT64( 0x4000000000000000 );
-        aExp -= 0x3C01;
-    }
-    return roundAndPackFloat64( aSign, aExp, aSig0 );
-
-}
-
-#ifdef FLOATX80
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the extended double-precision floating-point format.  The
-conversion is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-floatx80 float128_to_floatx80( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) {
-            return commonNaNToFloatx80( float128ToCommonNaN( a ) );
-        }
-        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    else {
-        aSig0 |= LIT64( 0x0001000000000000 );
-    }
-    shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 );
-    return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 );
-
-}
-
-#endif
-
-/*
--------------------------------------------------------------------------------
-Rounds the quadruple-precision floating-point value `a' to an integer, and
-returns the result as a quadruple-precision floating-point value.  The
-operation is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_round_to_int( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 lastBitMask, roundBitsMask;
-    int8 roundingMode;
-    float128 z;
-
-    aExp = extractFloat128Exp( a );
-    if ( 0x402F <= aExp ) {
-        if ( 0x406F <= aExp ) {
-            if (    ( aExp == 0x7FFF )
-                 && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
-               ) {
-                return propagateFloat128NaN( a, a );
-            }
-            return a;
-        }
-        lastBitMask = 1;
-        lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
-        roundBitsMask = lastBitMask - 1;
-        z = a;
-        roundingMode = float_rounding_mode;
-        if ( roundingMode == float_round_nearest_even ) {
-            if ( lastBitMask ) {
-                add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
-                if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
-            }
-            else {
-                if ( (sbits64) z.low < 0 ) {
-                    ++z.high;
-                    if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
-                }
-            }
-        }
-        else if ( roundingMode != float_round_to_zero ) {
-            if (   extractFloat128Sign( z )
-                 ^ ( roundingMode == float_round_up ) ) {
-                add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
-            }
-        }
-        z.low &= ~ roundBitsMask;
-    }
-    else {
-        if ( aExp <= 0x3FFE ) {
-            if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
-            float_exception_flags |= float_flag_inexact;
-            aSign = extractFloat128Sign( a );
-            switch ( float_rounding_mode ) {
-             case float_round_nearest_even:
-                if (    ( aExp == 0x3FFE )
-                     && (   extractFloat128Frac0( a )
-                          | extractFloat128Frac1( a ) )
-                   ) {
-                    return packFloat128( aSign, 0x3FFF, 0, 0 );
-                }
-                break;
-             case float_round_down:
-                return
-                      aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
-                    : packFloat128( 0, 0, 0, 0 );
-             case float_round_up:
-                return
-                      aSign ? packFloat128( 1, 0, 0, 0 )
-                    : packFloat128( 0, 0x3FFF, 0, 0 );
-            }
-            return packFloat128( aSign, 0, 0, 0 );
-        }
-        lastBitMask = 1;
-        lastBitMask <<= 0x402F - aExp;
-        roundBitsMask = lastBitMask - 1;
-        z.low = 0;
-        z.high = a.high;
-        roundingMode = float_rounding_mode;
-        if ( roundingMode == float_round_nearest_even ) {
-            z.high += lastBitMask>>1;
-            if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
-                z.high &= ~ lastBitMask;
-            }
-        }
-        else if ( roundingMode != float_round_to_zero ) {
-            if (   extractFloat128Sign( z )
-                 ^ ( roundingMode == float_round_up ) ) {
-                z.high |= ( a.low != 0 );
-                z.high += roundBitsMask;
-            }
-        }
-        z.high &= ~ roundBitsMask;
-    }
-    if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
-        float_exception_flags |= float_flag_inexact;
-    }
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of adding the absolute values of the quadruple-precision
-floating-point values `a' and `b'.  If `zSign' is true, the sum is negated
-before being returned.  `zSign' is ignored if the result is a NaN.  The
-addition is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-static float128 addFloat128Sigs( float128 a, float128 b, flag zSign )
-{
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
-    int32 expDiff;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    expDiff = aExp - bExp;
-    if ( 0 < expDiff ) {
-        if ( aExp == 0x7FFF ) {
-            if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
-            return a;
-        }
-        if ( bExp == 0 ) {
-            --expDiff;
-        }
-        else {
-            bSig0 |= LIT64( 0x0001000000000000 );
-        }
-        shift128ExtraRightJamming(
-            bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
-        zExp = aExp;
-    }
-    else if ( expDiff < 0 ) {
-        if ( bExp == 0x7FFF ) {
-            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-            return packFloat128( zSign, 0x7FFF, 0, 0 );
-        }
-        if ( aExp == 0 ) {
-            ++expDiff;
-        }
-        else {
-            aSig0 |= LIT64( 0x0001000000000000 );
-        }
-        shift128ExtraRightJamming(
-            aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
-        zExp = bExp;
-    }
-    else {
-        if ( aExp == 0x7FFF ) {
-            if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
-                return propagateFloat128NaN( a, b );
-            }
-            return a;
-        }
-        add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-        if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
-        zSig2 = 0;
-        zSig0 |= LIT64( 0x0002000000000000 );
-        zExp = aExp;
-        goto shiftRight1;
-    }
-    aSig0 |= LIT64( 0x0001000000000000 );
-    add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-    --zExp;
-    if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
-    ++zExp;
- shiftRight1:
-    shift128ExtraRightJamming(
-        zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
- roundAndPack:
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of subtracting the absolute values of the quadruple-
-precision floating-point values `a' and `b'.  If `zSign' is true, the
-difference is negated before being returned.  `zSign' is ignored if the
-result is a NaN.  The subtraction is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-static float128 subFloat128Sigs( float128 a, float128 b, flag zSign )
-{
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
-    int32 expDiff;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    expDiff = aExp - bExp;
-    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
-    shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
-    if ( 0 < expDiff ) goto aExpBigger;
-    if ( expDiff < 0 ) goto bExpBigger;
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
-            return propagateFloat128NaN( a, b );
-        }
-        float_raise( float_flag_invalid );
-        z.low = float128_default_nan_low;
-        z.high = float128_default_nan_high;
-        return z;
-    }
-    if ( aExp == 0 ) {
-        aExp = 1;
-        bExp = 1;
-    }
-    if ( bSig0 < aSig0 ) goto aBigger;
-    if ( aSig0 < bSig0 ) goto bBigger;
-    if ( bSig1 < aSig1 ) goto aBigger;
-    if ( aSig1 < bSig1 ) goto bBigger;
-    return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 );
- bExpBigger:
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        ++expDiff;
-    }
-    else {
-        aSig0 |= LIT64( 0x4000000000000000 );
-    }
-    shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
-    bSig0 |= LIT64( 0x4000000000000000 );
- bBigger:
-    sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
-    zExp = bExp;
-    zSign ^= 1;
-    goto normalizeRoundAndPack;
- aExpBigger:
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
-        return a;
-    }
-    if ( bExp == 0 ) {
-        --expDiff;
-    }
-    else {
-        bSig0 |= LIT64( 0x4000000000000000 );
-    }
-    shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
-    aSig0 |= LIT64( 0x4000000000000000 );
- aBigger:
-    sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-    zExp = aExp;
- normalizeRoundAndPack:
-    --zExp;
-    return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of adding the quadruple-precision floating-point values
-`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
-for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_add( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign == bSign ) {
-        return addFloat128Sigs( a, b, aSign );
-    }
-    else {
-        return subFloat128Sigs( a, b, aSign );
-    }
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of subtracting the quadruple-precision floating-point
-values `a' and `b'.  The operation is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_sub( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign == bSign ) {
-        return subFloat128Sigs( a, b, aSign );
-    }
-    else {
-        return addFloat128Sigs( a, b, aSign );
-    }
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of multiplying the quadruple-precision floating-point
-values `a' and `b'.  The operation is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_mul( float128 a, float128 b )
-{
-    flag aSign, bSign, zSign;
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
-    zSign = aSign ^ bSign;
-    if ( aExp == 0x7FFF ) {
-        if (    ( aSig0 | aSig1 )
-             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
-            return propagateFloat128NaN( a, b );
-        }
-        if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
-        return packFloat128( zSign, 0x7FFF, 0, 0 );
-    }
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
- invalid:
-            float_raise( float_flag_invalid );
-            z.low = float128_default_nan_low;
-            z.high = float128_default_nan_high;
-            return z;
-        }
-        return packFloat128( zSign, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    if ( bExp == 0 ) {
-        if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
-        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
-    }
-    zExp = aExp + bExp - 0x4000;
-    aSig0 |= LIT64( 0x0001000000000000 );
-    shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
-    mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
-    add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
-    zSig2 |= ( zSig3 != 0 );
-    if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
-        shift128ExtraRightJamming(
-            zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
-        ++zExp;
-    }
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of dividing the quadruple-precision floating-point value
-`a' by the corresponding value `b'.  The operation is performed according to
-the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_div( float128 a, float128 b )
-{
-    flag aSign, bSign, zSign;
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
-    zSign = aSign ^ bSign;
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
-        if ( bExp == 0x7FFF ) {
-            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-            goto invalid;
-        }
-        return packFloat128( zSign, 0x7FFF, 0, 0 );
-    }
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        return packFloat128( zSign, 0, 0, 0 );
-    }
-    if ( bExp == 0 ) {
-        if ( ( bSig0 | bSig1 ) == 0 ) {
-            if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
- invalid:
-                float_raise( float_flag_invalid );
-                z.low = float128_default_nan_low;
-                z.high = float128_default_nan_high;
-                return z;
-            }
-            float_raise( float_flag_divbyzero );
-            return packFloat128( zSign, 0x7FFF, 0, 0 );
-        }
-        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    zExp = aExp - bExp + 0x3FFD;
-    shortShift128Left(
-        aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
-    shortShift128Left(
-        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
-    if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
-        shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
-        ++zExp;
-    }
-    zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
-    mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
-    sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
-    while ( (sbits64) rem0 < 0 ) {
-        --zSig0;
-        add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
-    }
-    zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
-    if ( ( zSig1 & 0x3FFF ) <= 4 ) {
-        mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
-        sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
-            --zSig1;
-            add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
-        }
-        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
-    }
-    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the remainder of the quadruple-precision floating-point value `a'
-with respect to the corresponding value `b'.  The operation is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_rem( float128 a, float128 b )
-{
-    flag aSign, bSign, zSign;
-    int32 aExp, bExp, expDiff;
-    bits64 aSig0, aSig1, bSig0, bSig1;
-    bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1;
-    bits64 sigMean1;
-    sbits64 sigMean0;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
-    if ( aExp == 0x7FFF ) {
-        if (    ( aSig0 | aSig1 )
-             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
-            return propagateFloat128NaN( a, b );
-        }
-        goto invalid;
-    }
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        return a;
-    }
-    if ( bExp == 0 ) {
-        if ( ( bSig0 | bSig1 ) == 0 ) {
- invalid:
-            float_raise( float_flag_invalid );
-            z.low = float128_default_nan_low;
-            z.high = float128_default_nan_high;
-            return z;
-        }
-        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return a;
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    expDiff = aExp - bExp;
-    if ( expDiff < -1 ) return a;
-    shortShift128Left(
-        aSig0 | LIT64( 0x0001000000000000 ),
-        aSig1,
-        15 - ( expDiff < 0 ),
-        &aSig0,
-        &aSig1
-    );
-    shortShift128Left(
-        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
-    q = le128( bSig0, bSig1, aSig0, aSig1 );
-    if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
-    expDiff -= 64;
-    while ( 0 < expDiff ) {
-        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
-        q = ( 4 < q ) ? q - 4 : 0;
-        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
-        shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
-        shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
-        sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
-        expDiff -= 61;
-    }
-    if ( -64 < expDiff ) {
-        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
-        q = ( 4 < q ) ? q - 4 : 0;
-        q >>= - expDiff;
-        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
-        expDiff += 52;
-        if ( expDiff < 0 ) {
-            shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
-        }
-        else {
-            shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
-        }
-        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
-        sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
-    }
-    else {
-        shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
-        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
-    }
-    do {
-        alternateASig0 = aSig0;
-        alternateASig1 = aSig1;
-        ++q;
-        sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
-    } while ( 0 <= (sbits64) aSig0 );
-    add128(
-        aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
-    if (    ( sigMean0 < 0 )
-         || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
-        aSig0 = alternateASig0;
-        aSig1 = alternateASig1;
-    }
-    zSign = ( (sbits64) aSig0 < 0 );
-    if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
-    return
-        normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the square root of the quadruple-precision floating-point value `a'.
-The operation is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_sqrt( float128 a )
-{
-    flag aSign;
-    int32 aExp, zExp;
-    bits64 aSig0, aSig1, zSig0, zSig1, zSig2;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
-    bits64 shiftedRem0, shiftedRem1;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a );
-        if ( ! aSign ) return a;
-        goto invalid;
-    }
-    if ( aSign ) {
-        if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
- invalid:
-        float_raise( float_flag_invalid );
-        z.low = float128_default_nan_low;
-        z.high = float128_default_nan_high;
-        return z;
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
-    aSig0 |= LIT64( 0x0001000000000000 );
-    zSig0 = estimateSqrt32( aExp, aSig0>>17 );
-    zSig0 <<= 31;
-    shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
-    zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4;
-    if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF );
-    shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 );
-    mul64To128( zSig0, zSig0, &term0, &term1 );
-    sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
-    while ( (sbits64) rem0 < 0 ) {
-        --zSig0;
-        shortShift128Left( 0, zSig0, 1, &term0, &term1 );
-        term1 |= 1;
-        add128( rem0, rem1, term0, term1, &rem0, &rem1 );
-    }
-    shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 );
-    zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 );
-    if ( ( zSig1 & 0x3FFF ) <= 5 ) {
-        if ( zSig1 == 0 ) zSig1 = 1;
-        mul64To128( zSig0, zSig1, &term1, &term2 );
-        shortShift128Left( term1, term2, 1, &term1, &term2 );
-        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
-        mul64To128( zSig1, zSig1, &term2, &term3 );
-        sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
-            --zSig1;
-            shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 );
-            term3 |= 1;
-            add192(
-                rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 );
-        }
-        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
-    }
-    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
-    return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is equal to
-the corresponding value `b', and 0 otherwise.  The comparison is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_eq( float128 a, float128 b )
-{
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid );
-        }
-        return 0;
-    }
-    return
-           ( a.low == b.low )
-        && (    ( a.high == b.high )
-             || (    ( a.low == 0 )
-                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
-           );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-or equal to the corresponding value `b', and 0 otherwise.  The comparison
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_le( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        float_raise( float_flag_invalid );
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 == 0 );
-    }
-    return
-          aSign ? le128( b.high, b.low, a.high, a.low )
-        : le128( a.high, a.low, b.high, b.low );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-the corresponding value `b', and 0 otherwise.  The comparison is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_lt( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        float_raise( float_flag_invalid );
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 != 0 );
-    }
-    return
-          aSign ? lt128( b.high, b.low, a.high, a.low )
-        : lt128( a.high, a.low, b.high, b.low );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is equal to
-the corresponding value `b', and 0 otherwise.  The invalid exception is
-raised if either operand is a NaN.  Otherwise, the comparison is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_eq_signaling( float128 a, float128 b )
-{
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        float_raise( float_flag_invalid );
-        return 0;
-    }
-    return
-           ( a.low == b.low )
-        && (    ( a.high == b.high )
-             || (    ( a.low == 0 )
-                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
-           );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-or equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
-cause an exception.  Otherwise, the comparison is performed according to the
-IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_le_quiet( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid );
-        }
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 == 0 );
-    }
-    return
-          aSign ? le128( b.high, b.low, a.high, a.low )
-        : le128( a.high, a.low, b.high, b.low );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
-exception.  Otherwise, the comparison is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_lt_quiet( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid );
-        }
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 != 0 );
-    }
-    return
           aSign ? lt128( b.high, b.low, a.high, a.low )
         : lt128( a.high, a.low, b.high, b.low );
 
diff -urN linux-2.4.19-pre4/arch/arm/nwfpe/softfloat.h linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.h
--- linux-2.4.19-pre4/arch/arm/nwfpe/softfloat.h	Thu Jun 17 01:11:35 1999
+++ linux-2.4.19-pre5/arch/arm/nwfpe/softfloat.h	Fri Mar 29 14:49:19 2002
@@ -37,12 +37,10 @@
 The macro `FLOATX80' must be defined to enable the extended double-precision
 floating-point format `floatx80'.  If this macro is not defined, the
 `floatx80' type will not be defined, and none of the functions that either
-input or output the `floatx80' type will be defined.  The same applies to
-the `FLOAT128' macro and the quadruple-precision format `float128'.
+input or output the `floatx80' type will be defined.
 -------------------------------------------------------------------------------
 */
 #define FLOATX80
-/* #define FLOAT128 */
 
 /*
 -------------------------------------------------------------------------------
@@ -51,17 +49,10 @@
 */
 typedef unsigned long int float32;
 typedef unsigned long long float64;
-#ifdef FLOATX80
 typedef struct {
     unsigned short high;
     unsigned long long low;
 } floatx80;
-#endif
-#ifdef FLOAT128
-typedef struct {
-    unsigned long long high, low;
-} float128;
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -131,9 +122,6 @@
 #ifdef FLOATX80
 floatx80 int32_to_floatx80( signed int );
 #endif
-#ifdef FLOAT128
-float128 int32_to_float128( signed int );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -146,9 +134,6 @@
 #ifdef FLOATX80
 floatx80 float32_to_floatx80( float32 );
 #endif
-#ifdef FLOAT128
-float128 float32_to_float128( float32 );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -181,9 +166,6 @@
 #ifdef FLOATX80
 floatx80 float64_to_floatx80( float64 );
 #endif
-#ifdef FLOAT128
-float128 float64_to_float128( float64 );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -216,9 +198,6 @@
 signed int floatx80_to_int32_round_to_zero( floatx80 );
 float32 floatx80_to_float32( floatx80 );
 float64 floatx80_to_float64( floatx80 );
-#ifdef FLOAT128
-float128 floatx80_to_float128( floatx80 );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -250,41 +229,4 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Software IEC/IEEE quadruple-precision conversion routines.
--------------------------------------------------------------------------------
-*/
-signed int float128_to_int32( float128 );
-signed int float128_to_int32_round_to_zero( float128 );
-float32 float128_to_float32( float128 );
-float64 float128_to_float64( float128 );
-#ifdef FLOATX80
-floatx80 float128_to_floatx80( float128 );
-#endif
-
-/*
--------------------------------------------------------------------------------
-Software IEC/IEEE quadruple-precision operations.
--------------------------------------------------------------------------------
-*/
-float128 float128_round_to_int( float128 );
-float128 float128_add( float128, float128 );
-float128 float128_sub( float128, float128 );
-float128 float128_mul( float128, float128 );
-float128 float128_div( float128, float128 );
-float128 float128_rem( float128, float128 );
-float128 float128_sqrt( float128 );
-char float128_eq( float128, float128 );
-char float128_le( float128, float128 );
-char float128_lt( float128, float128 );
-char float128_eq_signaling( float128, float128 );
-char float128_le_quiet( float128, float128 );
-char float128_lt_quiet( float128, float128 );
-char float128_is_signaling_nan( float128 );
-
-#endif
-
 #endif
diff -urN linux-2.4.19-pre4/arch/arm/tools/Makefile linux-2.4.19-pre5/arch/arm/tools/Makefile
--- linux-2.4.19-pre4/arch/arm/tools/Makefile	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/arch/arm/tools/Makefile	Fri Mar 29 14:49:19 2002
@@ -15,13 +15,17 @@
 # what we want.  We do this in several stages so make picks up on
 # any errors that occur along the way.
 
-$(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c
-	$(CC) $(CFLAGS) -S -o - getconstants.c > $@.tmp.1
+constants.h: constants-hdr getconstants.c
+	$(CC) $(CFLAGS) -S -o $@.tmp.1 getconstants.c
 	sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' $@.tmp.1 > $@.tmp.2
-	cat constants-hdr $@.tmp.2 > $@.tmp
-	cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@
+	cat constants-hdr $@.tmp.2 > $@
 	$(RM) $@.tmp*
 
+# Only update include/asm-arm/constants.h when it has actually changed.
+
+$(TOPDIR)/include/asm-arm/constants.h: constants.h
+	cmp constants.h $@ >/dev/null 2>&1 || cp -p constants.h $@
+
 # Build our dependencies, and then generate the constants and
 # mach-types header files.  If we do it now, mkdep will pick
 # the dependencies up later on when it runs through the other
@@ -29,7 +33,7 @@
 
 dep:
 	$(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- getconstants.c |\
-	 sed s,getconstants.o,$(TOPDIR)/include/asm-arm/constants.h, > .depend
+	 sed s,getconstants.o,constants.h, > .depend
 	$(MAKE) all
 
 .PHONY:	all dep
diff -urN linux-2.4.19-pre4/arch/arm/tools/mach-types linux-2.4.19-pre5/arch/arm/tools/mach-types
--- linux-2.4.19-pre4/arch/arm/tools/mach-types	Fri Nov  9 13:58:02 2001
+++ linux-2.4.19-pre5/arch/arm/tools/mach-types	Fri Mar 29 14:49:19 2002
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Fri Oct 26 17:37:13 2001
+# Last update: Sat Mar 16 15:56:27 2002
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -118,10 +118,10 @@
 cdb89712		ARCH_CDB89712		CDB89712		107
 graphicsmaster		SA1100_GRAPHICSMASTER	GRAPHICSMASTER		108
 adsbitsy		SA1100_ADSBITSY		ADSBITSY		109
-cotulla_idp		ARCH_COTULLA_IDP	COTULLA_IDP		110
+pxa_idp			ARCH_PXA_IDP		PXA_IDP			110
 plce			ARCH_PLCE		PLCE			111
 pt_system3		SA1100_PT_SYSTEM3	PT_SYSTEM3		112
-medalb			ARCH_MEDALB		MEDALB			113
+murphy			ARCH_MEDALB		MEDALB			113
 eagle			ARCH_EAGLE		EAGLE			114
 dsc21			ARCH_DSC21		DSC21			115
 dsc24			ARCH_DSC24		DSC24			116
@@ -137,3 +137,44 @@
 elroy			SA1100_ELROY		ELROY			126
 gms720			ARCH_GMS720		GMS720			127
 s24x			ARCH_S24X		S24X			128
+jtel_clep7312		ARCH_JTEL_CLEP7312	JTEL_CLEP7312		129
+cx821xx			ARCH_CX821XX		CX821XX			130
+edb7312			ARCH_EDB7312		EDB7312			131
+bsa1110			SA1100_BSA1110		BSA1110			132
+powerpin		ARCH_POWERPIN		POWERPIN		133
+openarm			ARCH_OPENARM		OPENARM			134
+whitechapel		SA1100_WHITECHAPEL	WHITECHAPEL		135
+h3100			SA1100_H3100		H3100			136
+h3800			SA1100_H3800		H3800			137
+blue_v1			ARCH_BLUE_V1		BLUE_V1			138
+pxa_cerf		ARCH_PXA_CERF		PXA_CERF		139
+arm7tevb		ARCH_ARM7TEVB		ARM7TEVB		140
+d7400			ARCH_D7400		D7400			141
+piranha			ARCH_PIRANHA		PIRANHA			142
+sbcamelot		SA1100_SBCAMELOT	SBCAMELOT		143
+kings			SA1100_KINGS		KINGS			144
+smdk2400		ARCH_SMDK2400		SMDK2400		145
+collie			ARCH_COLLIE		COLLIE			146
+idr			ARCH_IDR		IDR			147
+badge4			SA1100_BADGE4		BADGE4			148
+webnet			ARCH_WEBNET		WEBNET			149
+d7300			SA1100_D7300		D7300			150
+cep			SA1100_CEP		CEP			151
+fortunet		ARCH_FORTUNET		FORTUNET		152
+vc547x			ARCH_VC547X		VC547X			153
+filewalker		SA1100_FILEWALKER	FILEWALKER		154
+netgateway		SA1100_NETGATEWAY	NETGATEWAY		155
+symbol2800		SA1100_SYMBOL2800	SYMBOL2800		156
+suns			SA1100_SUNS		SUNS			157
+frodo			SA1100_FRODO		FRODO			158
+ms301			SA1100_MACH_TYTE_MS301	MACH_TYTE_MS301		159
+mx1ads			ARCH_MX1ADS		MX1ADS			160
+h7201			ARCH_H7201		H7201			161
+h7202			ARCH_H7202		H7202			162
+amico			ARCH_AMICO		AMICO			163
+iam			SA1100_IAM		IAM			164
+tt530			SA1100_TT530		TT530			165
+sam2400			ARCH_SAM2400		SAM2400			166
+jornada56x		ARCH_JORNADA56X		JORNADA56X		167
+active			SA1100_ACTIVE		ACTIVE			168
+iq80321			ARCH_IQ80321		IQ80321			169
diff -urN linux-2.4.19-pre4/arch/cris/mm/init.c linux-2.4.19-pre5/arch/cris/mm/init.c
--- linux-2.4.19-pre4/arch/cris/mm/init.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre5/arch/cris/mm/init.c	Fri Mar 29 14:49:19 2002
@@ -465,7 +465,7 @@
                 free_page(addr);
                 totalram_pages++;
         }
-        printk ("Freeing unused kernel memory: %luk freed\n", 
+        printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n", 
 		(&__init_end - &__init_begin) >> 10);
 }
 
diff -urN linux-2.4.19-pre4/arch/i386/config.in linux-2.4.19-pre5/arch/i386/config.in
--- linux-2.4.19-pre4/arch/i386/config.in	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/config.in	Fri Mar 29 14:49:19 2002
@@ -424,7 +424,6 @@
    bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
-   bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
 fi
 
 endmenu
diff -urN linux-2.4.19-pre4/arch/i386/kernel/apm.c linux-2.4.19-pre5/arch/i386/kernel/apm.c
--- linux-2.4.19-pre4/arch/i386/kernel/apm.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/apm.c	Fri Mar 29 14:49:19 2002
@@ -471,6 +471,28 @@
 };
 #define ERROR_COUNT	(sizeof(error_table)/sizeof(lookup_t))
 
+/**
+ *	apm_error	-	display an APM error
+ *	@str: information string
+ *	@err: APM BIOS return code
+ *
+ *	Write a meaningful log entry to the kernel log in the event of
+ *	an APM error.
+ */
+ 
+static void apm_error(char *str, int err)
+{
+	int	i;
+
+	for (i = 0; i < ERROR_COUNT; i++)
+		if (error_table[i].key == err) break;
+	if (i < ERROR_COUNT)
+		printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
+	else
+		printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
+			str, err);
+}
+
 /*
  * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
  * apm_info.allow_ints, we are being really paranoid here!  Not only
@@ -702,13 +724,13 @@
 }
 
 /**
- *	apm_set_power_state - set system wide power state
+ *	set_system_power_state - set system wide power state
  *	@state: which state to enter
  *
  *	Transition the entire system into a new APM power state.
  */
  
-static int apm_set_power_state(u_short state)
+static int set_system_power_state(u_short state)
 {
 	return set_power_state(APM_DEVICE_ALL, state);
 }
@@ -884,7 +906,7 @@
 	if (apm_info.realmode_power_off)
 		machine_real_restart(po_bios_call, sizeof(po_bios_call));
 	else
-		(void) apm_set_power_state(APM_STATE_OFF);
+		(void) set_system_power_state(APM_STATE_OFF);
 }
 
 /**
@@ -1029,28 +1051,6 @@
 	return APM_SUCCESS;
 }
 
-/**
- *	apm_error	-	display an APM error
- *	@str: information string
- *	@err: APM BIOS return code
- *
- *	Write a meaningful log entry to the kernel log in the event of
- *	an APM error.
- */
- 
-static void apm_error(char *str, int err)
-{
-	int	i;
-
-	for (i = 0; i < ERROR_COUNT; i++)
-		if (error_table[i].key == err) break;
-	if (i < ERROR_COUNT)
-		printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
-	else
-		printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
-			str, err);
-}
-
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 
 /**
@@ -1189,7 +1189,7 @@
 		/* Vetoed */
 		if (vetoable) {
 			if (apm_info.connection_version > 0x100)
-				apm_set_power_state(APM_STATE_REJECT);
+				set_system_power_state(APM_STATE_REJECT);
 			err = -EBUSY;
 			ignore_sys_suspend = 0;
 			printk(KERN_WARNING "apm: suspend was vetoed.\n");
@@ -1199,9 +1199,10 @@
 	}
 	get_time_diff();
 	cli();
-	err = apm_set_power_state(APM_STATE_SUSPEND);
+	err = set_system_power_state(APM_STATE_SUSPEND);
 	reinit_timer();
 	set_time();
+	ignore_normal_resume = 1;
 	sti();
 	if (err == APM_NO_ERROR)
 		err = APM_SUCCESS;
@@ -1210,7 +1211,6 @@
 	err = (err == APM_SUCCESS) ? 0 : -EIO;
 	pm_send_all(PM_RESUME, (void *)0);
 	queue_event(APM_NORMAL_RESUME, NULL);
-	ignore_normal_resume = 1;
  out:
 	for (as = user_list; as != NULL; as = as->next) {
 		as->suspend_wait = 0;
@@ -1226,7 +1226,7 @@
 
 	/* If needed, notify drivers here */
 	get_time_diff();
-	err = apm_set_power_state(APM_STATE_STANDBY);
+	err = set_system_power_state(APM_STATE_STANDBY);
 	if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
 		apm_error("standby", err);
 }
@@ -1280,13 +1280,13 @@
 		case APM_USER_SUSPEND:
 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
 			if (apm_info.connection_version > 0x100)
-				apm_set_power_state(APM_STATE_REJECT);
+				set_system_power_state(APM_STATE_REJECT);
 			break;
 #endif
 		case APM_SYS_SUSPEND:
 			if (ignore_bounce) {
 				if (apm_info.connection_version > 0x100)
-					apm_set_power_state(APM_STATE_REJECT);
+					set_system_power_state(APM_STATE_REJECT);
 				break;
 			}
 			/*
@@ -1352,7 +1352,7 @@
 			pending_count = 4;
 			if (debug)
 				printk(KERN_DEBUG "apm: setting state busy\n");
-			err = apm_set_power_state(APM_STATE_BUSY);
+			err = set_system_power_state(APM_STATE_BUSY);
 			if (err)
 				apm_error("busy", err);
 		}
diff -urN linux-2.4.19-pre4/arch/i386/kernel/dmi_scan.c linux-2.4.19-pre5/arch/i386/kernel/dmi_scan.c
--- linux-2.4.19-pre4/arch/i386/kernel/dmi_scan.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/dmi_scan.c	Fri Mar 29 14:49:19 2002
@@ -453,6 +453,11 @@
 			MATCH(DMI_BIOS_VERSION, "A04"),
 			MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH
 			} },
+	{ broken_apm_power, "Dell Inspiron 2500", {	/* Handle problems with APM on Inspiron 2500 */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "A12"),
+			MATCH(DMI_BIOS_DATE, "02/04/2002"), NO_MATCH
+			} },
 	{ set_realmode_power_off, "Award Software v4.60 PGMA", {	/* broken PM poweroff bios */
 			MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
 			MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
diff -urN linux-2.4.19-pre4/arch/i386/kernel/i386_ksyms.c linux-2.4.19-pre5/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.19-pre4/arch/i386/kernel/i386_ksyms.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/i386_ksyms.c	Fri Mar 29 14:49:19 2002
@@ -173,9 +173,5 @@
 EXPORT_SYMBOL(atomic_dec_and_lock);
 #endif
 
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-EXPORT_SYMBOL(do_BUG);
-#endif
-
 extern int is_sony_vaio_laptop;
 EXPORT_SYMBOL(is_sony_vaio_laptop);
diff -urN linux-2.4.19-pre4/arch/i386/kernel/microcode.c linux-2.4.19-pre5/arch/i386/kernel/microcode.c
--- linux-2.4.19-pre4/arch/i386/kernel/microcode.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/microcode.c	Fri Mar 29 14:49:19 2002
@@ -55,6 +55,8 @@
  *		Tigran Aivazian <tigran@veritas.com>,
  *		Serialize updates as required on HT processors due to speculative
  *		nature of implementation.
+ *	1.11	22 Mar 2001 Tigran Aivazian <tigran@veritas.com>
+ *		Fix the panic when writing zero-length microcode chunk.
  */
 
 #include <linux/init.h>
@@ -73,7 +75,7 @@
 
 static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
 
-#define MICROCODE_VERSION 	"1.10"
+#define MICROCODE_VERSION 	"1.11"
 
 MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
@@ -330,11 +332,15 @@
 {
 	ssize_t ret;
 
-	if (len % sizeof(struct microcode) != 0) {
+	if (!len || len % sizeof(struct microcode) != 0) {
 		printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", 
 			sizeof(struct microcode));
 		return -EINVAL;
 	}
+	if ((len >> PAGE_SHIFT) > num_physpages) {
+		printk(KERN_ERR "microcode: too much data (max %d pages)\n", num_physpages);
+		return -EINVAL;
+	}
 	down_write(&microcode_rwsem);
 	if (!mc_applied) {
 		mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
diff -urN linux-2.4.19-pre4/arch/i386/kernel/pci-irq.c linux-2.4.19-pre5/arch/i386/kernel/pci-irq.c
--- linux-2.4.19-pre4/arch/i386/kernel/pci-irq.c	Mon Feb 25 11:37:53 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/pci-irq.c	Fri Mar 29 14:49:19 2002
@@ -206,6 +206,24 @@
 }
 
 /*
+ * ITE 8330G pirq rules are nibble-based
+ * FIXME: pirqmap may be { 1, 0, 3, 2 },
+ * 	  2+3 are both mapped to irq 9 on my system
+ */
+static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+	return read_config_nybble(router,0x43, pirqmap[pirq-1]);
+}
+
+static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+	write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
+	return 1;
+}
+
+/*
  * OPTI: high four bits are nibble pointer..
  * I wonder what the low bits do?
  */
@@ -447,6 +465,8 @@
 
 	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 
+	{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
+
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
diff -urN linux-2.4.19-pre4/arch/i386/kernel/pci-pc.c linux-2.4.19-pre5/arch/i386/kernel/pci-pc.c
--- linux-2.4.19-pre4/arch/i386/kernel/pci-pc.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/pci-pc.c	Fri Mar 29 14:49:19 2002
@@ -421,7 +421,7 @@
 		    pci_sanity_check(&pci_direct_conf1)) {
 			outl (tmp, 0xCF8);
 			__restore_flags(flags);
-			printk("PCI: Using configuration type 1\n");
+			printk(KERN_INFO "PCI: Using configuration type 1\n");
 			request_region(0xCF8, 8, "PCI conf1");
 			return &pci_direct_conf1;
 		}
@@ -438,7 +438,7 @@
 		if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
 		    pci_sanity_check(&pci_direct_conf2)) {
 			__restore_flags(flags);
-			printk("PCI: Using configuration type 2\n");
+			printk(KERN_INFO "PCI: Using configuration type 2\n");
 			request_region(0xCF8, 4, "PCI conf2");
 			return &pci_direct_conf2;
 		}
@@ -546,10 +546,10 @@
 		case 0:
 			return address + entry;
 		case 0x80:	/* Not present */
-			printk("bios32_service(0x%lx): not present\n", service);
+			printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
 			return 0;
 		default: /* Shouldn't happen */
-			printk("bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
+			printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
 				service, return_code);
 			return 0;
 	}
@@ -599,7 +599,7 @@
 				status, signature);
 			return 0;
 		}
-		printk("PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
+		printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
 			major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
 #ifdef CONFIG_PCI_DIRECT
 		if (!(hw_mech & PCIBIOS_HW_TYPE1))
@@ -901,7 +901,7 @@
 				}
 			}
 			if (ln == &pci_devices) {
-				printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+				printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
 				/*
 				 * We must not continue scanning as several buggy BIOSes
 				 * return garbage after the last device. Grr.
@@ -910,7 +910,7 @@
 			}
 		}
 		if (!found) {
-			printk("PCI: Device %02x:%02x not found by BIOS\n",
+			printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
 				dev->bus->number, dev->devfn);
 			list_del(&dev->global_list);
 			list_add_tail(&dev->global_list, &sorted_devices);
@@ -970,7 +970,7 @@
 			rt->size = opt.size + sizeof(struct irq_routing_table);
 			rt->exclusive_irqs = map;
 			memcpy(rt->slots, (void *) page, opt.size);
-			printk("PCI: Using BIOS Interrupt Routing Table\n");
+			printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
 		}
 	}
 	free_page(page);
@@ -1035,7 +1035,7 @@
 	}
 	if (!seen_host_bridge)
 		return;
-	printk("PCI: Ignoring ghost devices on bus %02x\n", b->number);
+	printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
 
 	ln = &b->devices;
 	while (ln->next != &b->devices) {
@@ -1073,7 +1073,7 @@
 			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
 			    l != 0x0000 && l != 0xffff) {
 				DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
-				printk("PCI: Discovered peer bus %02x\n", n);
+				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
 				pci_scan_bus(n, pci_root_ops, NULL);
 				break;
 			}
@@ -1116,7 +1116,7 @@
 	 */
 	u8 busno;
 	pci_read_config_byte(d, 0x4a, &busno);
-	printk("PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
+	printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
 	pci_scan_bus(busno, pci_root_ops, NULL);
 	pcibios_last_bus = -1;
 }
@@ -1129,7 +1129,7 @@
 	 */
 	int i;
 
-	printk("PCI: Fixing base address flags for device %s\n", d->slot_name);
+	printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name);
 	for(i=0; i<4; i++)
 		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 }
@@ -1280,11 +1280,11 @@
 	if (!pci_root_ops)
 		pcibios_config_init();
 	if (!pci_root_ops) {
-		printk("PCI: System does not support PCI\n");
+		printk(KERN_WARNING "PCI: System does not support PCI\n");
 		return;
 	}
 
-	printk("PCI: Probing PCI hardware\n");
+	printk(KERN_INFO "PCI: Probing PCI hardware\n");
 	pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
 	if (clustered_apic_mode && (numnodes > 1)) {
 		for (quad = 1; quad < numnodes; ++quad) {
diff -urN linux-2.4.19-pre4/arch/i386/kernel/traps.c linux-2.4.19-pre5/arch/i386/kernel/traps.c
--- linux-2.4.19-pre4/arch/i386/kernel/traps.c	Fri Mar 29 14:48:54 2002
+++ linux-2.4.19-pre5/arch/i386/kernel/traps.c	Fri Mar 29 14:49:20 2002
@@ -237,6 +237,41 @@
 	printk("\n");
 }	
 
+static void handle_BUG(struct pt_regs *regs)
+{
+	unsigned short ud2;
+	unsigned short line;
+	char *file;
+	char c;
+	unsigned long eip;
+
+	if (regs->xcs & 3)
+		goto no_bug;		/* Not in kernel */
+
+	eip = regs->eip;
+
+	if (eip < PAGE_OFFSET)
+		goto no_bug;
+	if (__get_user(ud2, (unsigned short *)eip))
+		goto no_bug;
+	if (ud2 != 0x0b0f)
+		goto no_bug;
+	if (__get_user(line, (unsigned short *)(eip + 2)))
+		goto bug;
+	if (__get_user(file, (char **)(eip + 4)) ||
+		(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
+		file = "<bad filename>";
+
+	printk("kernel BUG at %s:%d!\n", file, line);
+
+no_bug:
+	return;
+
+	/* Here we know it was a BUG but file-n-line is unavailable */
+bug:
+	printk("Kernel BUG\n");
+}
+
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -244,6 +279,7 @@
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
+	handle_BUG(regs);
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
 	bust_spinlocks(0);
diff -urN linux-2.4.19-pre4/arch/i386/mm/fault.c linux-2.4.19-pre5/arch/i386/mm/fault.c
--- linux-2.4.19-pre4/arch/i386/mm/fault.c	Mon Feb 25 11:37:53 2002
+++ linux-2.4.19-pre5/arch/i386/mm/fault.c	Fri Mar 29 14:49:20 2002
@@ -125,12 +125,6 @@
 	}
 }
 
-void do_BUG(const char *file, int line)
-{
-	bust_spinlocks(1);
-	printk("kernel BUG at %s:%d!\n", file, line);
-}
-
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 extern unsigned long idt;
 
diff -urN linux-2.4.19-pre4/arch/i386/mm/init.c linux-2.4.19-pre5/arch/i386/mm/init.c
--- linux-2.4.19-pre4/arch/i386/mm/init.c	Fri Mar 29 14:48:55 2002
+++ linux-2.4.19-pre5/arch/i386/mm/init.c	Fri Mar 29 14:49:20 2002
@@ -503,7 +503,7 @@
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
-	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
+	printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
 		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 		max_mapnr << (PAGE_SHIFT-10),
 		codesize >> 10,
@@ -567,14 +567,14 @@
 		free_page(addr);
 		totalram_pages++;
 	}
-	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+	printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
 	if (start < end)
-		printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+		printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
 		set_page_count(virt_to_page(start), 1);
diff -urN linux-2.4.19-pre4/arch/mips64/math-emu/cp1emu.c linux-2.4.19-pre5/arch/mips64/math-emu/cp1emu.c
--- linux-2.4.19-pre4/arch/mips64/math-emu/cp1emu.c	Fri Mar 29 14:49:02 2002
+++ linux-2.4.19-pre5/arch/mips64/math-emu/cp1emu.c	Fri Mar 29 14:49:23 2002
@@ -29,7 +29,7 @@
  * Notes: 
  *  1) the IEEE754 library (-le) performs the actual arithmetic;
  *  2) if you know that you won't have an fpu, then you'll get much 
- *     better performance by compiling with -msoft-float!  */
+ *     better performance by compiling with -msoft-float!
  *
  *  Nov 7, 2000
  *  Massive changes to integrate with Linux kernel.
diff -urN linux-2.4.19-pre4/arch/ppc64/Makefile linux-2.4.19-pre5/arch/ppc64/Makefile
--- linux-2.4.19-pre4/arch/ppc64/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/Makefile	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,80 @@
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+# Changes for PPC by Gary Thomas
+# Rewritten by Cort Dougan and Paul Mackerras
+# Adjusted for PPC64 by Tom Gall
+#
+
+KERNELLOAD	=0xc000000000000000
+
+ifeq ($(shell uname -m),ppc64)
+CHECKS		= checks
+endif
+
+LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Bstatic \
+		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
+CFLAGS		:= $(CFLAGS) -fsigned-char -msoft-float -pipe \
+		-Wno-uninitialized -mminimal-toc -fno-builtin
+CPP		= $(CC) -E $(CFLAGS)
+
+
+HEAD := arch/ppc64/kernel/head.o
+
+ARCH_SUBDIRS = arch/ppc64/kernel arch/ppc64/mm arch/ppc64/lib
+SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
+ARCHIVES := arch/ppc64/kernel/kernel.o arch/ppc64/mm/mm.o arch/ppc64/lib/lib.o $(ARCHIVES)
+CORE_FILES := arch/ppc64/kernel/kernel.o arch/ppc64/mm/mm.o arch/ppc64/lib/lib.o $(CORE_FILES)
+
+ifdef CONFIG_XMON
+SUBDIRS += arch/ppc64/xmon
+CORE_FILES += arch/ppc64/xmon/x.o
+endif
+ifdef CONFIG_KDB
+SUBDIRS += arch/ppc64/kdb
+CORE_FILES += arch/ppc64/kdb/kdba.o
+endif
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+checks:
+	@$(MAKE) -C arch/$(ARCH)/kernel checks
+
+ifdef CONFIG_PPC_PSERIES
+BOOT_TARGETS = zImage znetboot.initrd zImage.initrd
+endif
+
+ifdef CONFIG_PPC_ISERIES
+BOOT_TARGETS = vmlinux.sminitrd vmlinux.initrd vmlinux.sm
+endif
+
+$(BOOT_TARGETS): vmlinux
+	@$(MAKEBOOT) $@
+
+znetboot: vmlinux
+ifdef CONFIG_SMP
+	cp -f vmlinux /tftpboot/vmlinux.smp
+else
+	cp -f vmlinux /tftpboot/vmlinux
+endif
+	@$(MAKEBOOT) $@
+
+%_config: arch/ppc64/configs/%_defconfig
+	rm -f .config arch/ppc64/defconfig
+	cp -f arch/ppc64/configs/$(@:config=defconfig) arch/ppc64/defconfig
+
+archclean:
+	rm -f arch/ppc64/kernel/{ppc_defs.h,checks,mk_defs.s,mk_defs_out.c,mk_defs_tpl}
+	@$(MAKEBOOT) clean
+
+archmrproper:
+
+archdep:
+	$(MAKEBOOT) fastdep
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/Makefile linux-2.4.19-pre5/arch/ppc64/boot/Makefile
--- linux-2.4.19-pre4/arch/ppc64/boot/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/Makefile	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,129 @@
+# Makefile for making ELF bootable images for booting on CHRP
+# using Open Firmware.
+#
+# Geert Uytterhoeven	September 1997
+#
+# Based on coffboot by Paul Mackerras
+# Simplified for ppc64 by Todd Inglett
+#
+# NOTE:	this code is built for 32 bit in ELF32 format even though
+#	it packages a 64 bit kernel.  We do this to simplify the
+#	bootloader and increase compatibility with OpenFirmware.
+#
+#	To this end we need to define BOOTCC, etc, as the tools
+#	needed to build the 32 bit image.  These are normally HOSTCC,
+#	but may be a third compiler if, for example, you are cross
+#	compiling from an intel box.  Once the 64bit ppc gcc is
+#	stable it will probably simply be a compiler switch to
+#	compile for 32bit mode.
+#	To make it easier to setup a cross compiler,
+#	CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
+#	in the toplevel makefile.
+
+CROSS32_COMPILE =
+#CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux-
+
+BOOTCC = $(CROSS32_COMPILE)gcc
+BOOTCFLAGS = $(HOSTCFLAGS) -I$(HPATH)
+BOOTLD = $(CROSS32_COMPILE)ld
+BOOTAS = $(CROSS32_COMPILE)as
+BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS)
+
+.c.o:
+	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
+.S.o:
+	$(BOOTCC) $(BOOTAFLAGS) -traditional -c -o $*.o $<
+
+CFLAGS	= $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
+LD_ARGS = -Ttext 0x00400000 -e _start
+
+OBJS = crt0.o start.o main.o zlib.o image.o imagesize.o
+#LIBS = $(TOPDIR)/lib/lib.a
+LIBS =
+
+ifeq ($(CONFIG_SMP),y)
+TFTPIMAGE=/tftpboot/zImage.chrp.smp
+else
+TFTPIMAGE=/tftpboot/zImage.chrp
+endif
+
+
+ifeq ($(CONFIG_PPC_ISERIES),y)
+all:	vmlinux.sm
+else
+all:	$(TOPDIR)/zImage
+endif
+
+
+znetboot: zImage
+	cp zImage $(TFTPIMAGE)
+
+
+ifeq ($(CONFIG_PPC_ISERIES),y)
+
+addSystemMap: addSystemMap.c
+	$(HOSTCC) $(HOSTCFLAGS) -o addSystemMap addSystemMap.c
+
+vmlinux.sm: $(TOPDIR)/vmlinux addSystemMap
+	./addSystemMap $(TOPDIR)/System.map $(TOPDIR)/vmlinux vmlinux.sm
+
+
+addRamDisk: addRamDisk.c
+	$(HOSTCC) $(HOSTCFLAGS) -o addRamDisk addRamDisk.c
+
+vmlinux.initrd: $(TOPDIR)/vmlinux addRamDisk ramdisk.image.gz $(TOPDIR)/System.map
+	./addRamDisk ramdisk.image.gz $(TOPDIR)/System.map $(TOPDIR)/vmlinux vmlinux.initrd
+
+vmlinux.sminitrd: vmlinux.sm addRamDisk ramdisk.image.gz $(TOPDIR)/System.map
+	./addRamDisk ramdisk.image.gz $(TOPDIR)/System.map vmlinux.sm vmlinux.sminitrd
+
+endif
+
+
+znetboot.initrd: zImage.initrd
+	cp zImage.initrd $(TFTPIMAGE)
+
+floppy: zImage
+	mcopy zImage a:zImage
+
+piggyback: piggyback.c
+	$(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c
+
+addnote: addnote.c
+	$(HOSTCC) $(HOSTCFLAGS) -o addnote addnote.c
+
+image.o: piggyback vmlinux.gz
+	./piggyback image < vmlinux.gz | $(BOOTAS) -o image.o
+
+sysmap.o: piggyback ../../../System.map
+	./piggyback sysmap < ../../../System.map | $(BOOTAS) -o sysmap.o
+
+initrd.o: ramdisk.image.gz piggyback
+	./piggyback initrd < ramdisk.image.gz | $(BOOTAS) -o initrd.o
+
+zImage: $(OBJS) no_initrd.o addnote
+	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) no_initrd.o $(LIBS)
+	./addnote $@
+
+zImage.initrd: $(OBJS) initrd.o addnote
+	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) initrd.o $(LIBS)
+	./addnote $@
+
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+	$(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux
+	ls -l vmlinux | awk '{printf "/* generated -- do not edit! */\nint uncompressed_size = %d;\n", $$5}' > imagesize.c
+	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "long vmlinux_end = 0x%s;\n", substr($$1,8)}' >> imagesize.c
+	gzip -vf9 vmlinux
+
+imagesize.c: vmlinux.gz
+
+clean:
+	rm -f piggyback note addnote $(OBJS) zImage zImage.initrd vmlinux.gz no_initrd.o imagesize.c addSystemMap vmlinux.sm addRamDisk vmlinux.initrd vmlinux.sminitrd 
+
+fastdep:
+	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+	$(CPP) $(CPPFLAGS) -M *.S *.c > .depend
+
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/addRamDisk.c linux-2.4.19-pre5/arch/ppc64/boot/addRamDisk.c
--- linux-2.4.19-pre4/arch/ppc64/boot/addRamDisk.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/addRamDisk.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,301 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#define ElfHeaderSize  (64 * 1024)
+#define ElfPages  (ElfHeaderSize / 4096)
+#define KERNELBASE (0xc000000000000000)
+
+void get4k(FILE *file, char *buf )
+{
+	unsigned j;
+	unsigned num = fread(buf, 1, 4096, file);
+	for ( j=num; j<4096; ++j )
+		buf[j] = 0;
+}
+
+void put4k(FILE *file, char *buf )
+{
+	fwrite(buf, 1, 4096, file);
+}
+
+void death(const char *msg, FILE *fdesc, const char *fname) 
+{
+	printf(msg);
+	fclose(fdesc);
+	unlink(fname);
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	char inbuf[4096];
+	FILE *ramDisk = NULL;
+	FILE *sysmap = NULL;
+	FILE *inputVmlinux = NULL;
+	FILE *outputVmlinux = NULL;
+  
+	unsigned i = 0;
+	unsigned long ramFileLen = 0;
+	unsigned long ramLen = 0;
+	unsigned long roundR = 0;
+  
+	unsigned long sysmapFileLen = 0;
+	unsigned long sysmapLen = 0;
+	unsigned long sysmapPages = 0;
+	char* ptr_end = NULL; 
+	unsigned long offset_end = 0;
+
+	unsigned long kernelLen = 0;
+	unsigned long actualKernelLen = 0;
+	unsigned long round = 0;
+	unsigned long roundedKernelLen = 0;
+	unsigned long ramStartOffs = 0;
+	unsigned long ramPages = 0;
+	unsigned long roundedKernelPages = 0;
+	unsigned long hvReleaseData = 0;
+	u_int32_t eyeCatcher = 0xc8a5d9c4;
+	unsigned long naca = 0;
+	unsigned long xRamDisk = 0;
+	unsigned long xRamDiskSize = 0;
+	long padPages = 0;
+  
+  
+	if (argc < 2) {
+		printf("Name of RAM disk file missing.\n");
+		exit(1);
+	}
+
+	if (argc < 3) {
+		printf("Name of System Map input file is missing.\n");
+		exit(1);
+	}
+  
+	if (argc < 4) {
+		printf("Name of vmlinux file missing.\n");
+		exit(1);
+	}
+
+	if (argc < 5) {
+		printf("Name of vmlinux output file missing.\n");
+		exit(1);
+	}
+
+
+	ramDisk = fopen(argv[1], "r");
+	if ( ! ramDisk ) {
+		printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
+		exit(1);
+	}
+
+	sysmap = fopen(argv[2], "r");
+	if ( ! sysmap ) {
+		printf("System Map file \"%s\" failed to open.\n", argv[2]);
+		exit(1);
+	}
+  
+	inputVmlinux = fopen(argv[3], "r");
+	if ( ! inputVmlinux ) {
+		printf("vmlinux file \"%s\" failed to open.\n", argv[3]);
+		exit(1);
+	}
+  
+	outputVmlinux = fopen(argv[4], "w+");
+	if ( ! outputVmlinux ) {
+		printf("output vmlinux file \"%s\" failed to open.\n", argv[4]);
+		exit(1);
+	}
+  
+  
+  
+	/* Input Vmlinux file */
+	fseek(inputVmlinux, 0, SEEK_END);
+	kernelLen = ftell(inputVmlinux);
+	fseek(inputVmlinux, 0, SEEK_SET);
+	printf("kernel file size = %d\n", kernelLen);
+	if ( kernelLen == 0 ) {
+		printf("You must have a linux kernel specified as argv[3]\n");
+		exit(1);
+	}
+
+	actualKernelLen = kernelLen - ElfHeaderSize;
+
+	printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
+
+	round = actualKernelLen % 4096;
+	roundedKernelLen = actualKernelLen;
+	if ( round )
+		roundedKernelLen += (4096 - round);
+	printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen, roundedKernelLen);
+	roundedKernelPages = roundedKernelLen / 4096;
+	printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages);
+
+
+
+	/* Input System Map file */
+	/* (needs to be processed simply to determine if we need to add pad pages due to the static variables not being included in the vmlinux) */
+	fseek(sysmap, 0, SEEK_END);
+	sysmapFileLen = ftell(sysmap);
+	fseek(sysmap, 0, SEEK_SET);
+	printf("%s file size = %ld/0x%lx \n", argv[2], sysmapFileLen, sysmapFileLen);
+
+	sysmapLen = sysmapFileLen;
+
+	roundR = 4096 - (sysmapLen % 4096);
+	if (roundR) {
+		printf("Rounding System Map file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
+		sysmapLen += roundR;
+	}
+	printf("Rounded System Map size is %ld/0x%lx \n", sysmapLen, sysmapLen);
+  
+	/* Process the Sysmap file to determine where _end is */
+	sysmapPages = sysmapLen / 4096;
+	for (i=0; i<sysmapPages; ++i) {
+		get4k(sysmap, inbuf);
+	}
+	/* search for _end in the last page of the system map */
+	ptr_end = strstr(inbuf, " _end");
+	if (!ptr_end) {
+		printf("Unable to find _end in the sysmap file \n");
+		printf("inbuf: \n");
+		printf("%s \n", inbuf);
+		exit(1);
+	}
+	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
+	/* convert address of _end in system map to hex offset. */
+	offset_end = (unsigned int)strtol(ptr_end-10, NULL, 16);
+	/* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
+	padPages = offset_end/4096 - roundedKernelPages;
+
+	/* Check and see if the vmlinux is already larger than _end in System.map */
+	if (padPages < 0) {
+		/* vmlinux is larger than _end - adjust the offset to the start of the embedded ram disk */ 
+		offset_end = roundedKernelLen;
+		printf("vmlinux is larger than _end indicates it needs to be - offset_end = %lx \n", offset_end);
+		padPages = 0;
+		printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
+	}
+	else {
+		/* _end is larger than vmlinux - use the offset to _end that we calculated from the system map */
+		printf("vmlinux is smaller than _end indicates is needed - offset_end = %lx \n", offset_end);
+		printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
+	}
+
+
+
+	/* Input Ram Disk file */
+	// Set the offset that the ram disk will be started at.
+	ramStartOffs = offset_end;  /* determined from the input vmlinux file and the system map */
+	printf("Ram Disk will start at offset = 0x%lx \n", ramStartOffs);
+  
+	fseek(ramDisk, 0, SEEK_END);
+	ramFileLen = ftell(ramDisk);
+	fseek(ramDisk, 0, SEEK_SET);
+	printf("%s file size = %ld/0x%lx \n", argv[1], ramFileLen, ramFileLen);
+
+	ramLen = ramFileLen;
+
+	roundR = 4096 - (ramLen % 4096);
+	if ( roundR ) {
+		printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
+		ramLen += roundR;
+	}
+
+	printf("Rounded RAM disk size is %ld/0x%lx \n", ramLen, ramLen);
+	ramPages = ramLen / 4096;
+	printf("RAM disk pages to copy = %ld/0x%lx\n", ramPages, ramPages);
+
+
+
+  // Copy 64K ELF header
+	for (i=0; i<(ElfPages); ++i) {
+		get4k( inputVmlinux, inbuf );
+		put4k( outputVmlinux, inbuf );
+	}
+
+	/* Copy the vmlinux (as full pages). */
+	fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
+	for ( i=0; i<roundedKernelPages; ++i ) {
+		get4k( inputVmlinux, inbuf );
+		put4k( outputVmlinux, inbuf );
+	}
+  
+	/* Insert pad pages (if appropriate) that are needed between */
+	/* | the end of the vmlinux and the ram disk. */
+	for (i=0; i<padPages; ++i) {
+		memset(inbuf, 0, 4096);
+		put4k(outputVmlinux, inbuf);
+	}
+
+	/* Copy the ram disk (as full pages). */
+	for ( i=0; i<ramPages; ++i ) {
+		get4k( ramDisk, inbuf );
+		put4k( outputVmlinux, inbuf );
+	}
+
+	/* Close the input files */
+	fclose(ramDisk);
+	fclose(inputVmlinux);
+	/* And flush the written output file */
+	fflush(outputVmlinux);
+
+
+
+	/* Fixup the new vmlinux to contain the ram disk starting offset (xRamDisk) and the ram disk size (xRamDiskSize) */
+	/* fseek to the hvReleaseData pointer */
+	fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
+	if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
+		death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[4]);
+	}
+	hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
+	printf("hvReleaseData is at %08x\n", hvReleaseData);
+
+	/* fseek to the hvReleaseData */
+	fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
+	if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
+		death("Could not read hvReleaseData\n", outputVmlinux, argv[4]);
+	}
+	/* Check hvReleaseData sanity */
+	if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
+		death("hvReleaseData is invalid\n", outputVmlinux, argv[4]);
+	}
+	/* Get the naca pointer */
+	naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
+	printf("Naca is at offset 0x%lx \n", naca);
+
+	/* fseek to the naca */
+	fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
+	if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
+		death("Could not read naca\n", outputVmlinux, argv[4]);
+	}
+	xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
+	xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
+	/* Make sure a RAM disk isn't already present */
+	if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
+		death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[4]);
+	}
+	/* Fill in the values */
+	*((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
+	*((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
+
+	/* Write out the new naca */
+	fflush(outputVmlinux);
+	fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
+	if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
+		death("Could not write naca\n", outputVmlinux, argv[4]);
+	}
+	printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08x\n",
+	       ramPages, ramStartOffs);
+
+	/* Done */
+	fclose(outputVmlinux);
+	/* Set permission to executable */
+	chmod(argv[4], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
+
+	return 0;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/addSystemMap.c linux-2.4.19-pre5/arch/ppc64/boot/addSystemMap.c
--- linux-2.4.19-pre4/arch/ppc64/boot/addSystemMap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/addSystemMap.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,250 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <byteswap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+void xlate( char * inb, char * trb, unsigned len )
+{
+	unsigned i;
+	for (  i=0; i<len; ++i )
+	{
+		char c = *inb++;
+		char c1 = c >> 4;
+		char c2 = c & 0xf;
+		if ( c1 > 9 )
+			c1 = c1 + 'A' - 10;
+		else
+			c1 = c1 + '0';
+		if ( c2 > 9 )
+			c2 = c2 + 'A' - 10;
+		else
+			c2 = c2 + '0';
+		*trb++ = c1;
+		*trb++ = c2;
+	}
+	*trb = 0;
+}
+
+#define ElfHeaderSize  (64 * 1024)
+#define ElfPages  (ElfHeaderSize / 4096)
+
+void get4k( /*istream *inf*/FILE *file, char *buf )
+{
+	unsigned j;
+	unsigned num = fread(buf, 1, 4096, file);
+	for ( j=num; j<4096; ++j )
+		buf[j] = 0;
+}
+
+void put4k( /*ostream *outf*/FILE *file, char *buf )
+{
+	fwrite(buf, 1, 4096, file);
+}
+
+int main(int argc, char **argv)
+{
+	char inbuf[4096];
+	FILE *sysmap = NULL;
+	char* ptr_end = NULL; 
+	FILE *inputVmlinux = NULL;
+	FILE *outputVmlinux = NULL;
+	long i = 0;
+	unsigned long sysmapFileLen = 0;
+	unsigned long sysmapLen = 0;
+	unsigned long roundR = 0;
+	unsigned long kernelLen = 0;
+	unsigned long actualKernelLen = 0;
+	unsigned long round = 0;
+	unsigned long roundedKernelLen = 0;
+	unsigned long sysmapStartOffs = 0;
+	unsigned long sysmapPages = 0;
+	unsigned long roundedKernelPages = 0;
+	long padPages = 0;
+	if ( argc < 2 )
+	{
+		printf("Name of System Map file missing.\n");
+		exit(1);
+	}
+
+	if ( argc < 3 )
+	{
+		printf("Name of vmlinux file missing.\n");
+		exit(1);
+	}
+
+	if ( argc < 4 )
+	{
+		printf("Name of vmlinux output file missing.\n");
+		exit(1);
+	}
+
+	sysmap = fopen(argv[1], "r");
+	if ( ! sysmap )
+	{
+		printf("System Map file \"%s\" failed to open.\n", argv[1]);
+		exit(1);
+	}
+	inputVmlinux = fopen(argv[2], "r");
+	if ( ! inputVmlinux )
+	{
+		printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
+		exit(1);
+	}
+	outputVmlinux = fopen(argv[3], "w");
+	if ( ! outputVmlinux )
+	{
+		printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
+		exit(1);
+	}
+
+
+  
+	fseek(inputVmlinux, 0, SEEK_END);
+	kernelLen = ftell(inputVmlinux);
+	fseek(inputVmlinux, 0, SEEK_SET);
+	printf("kernel file size = %ld\n", kernelLen);
+	if ( kernelLen == 0 )
+	{
+		printf("You must have a linux kernel specified as argv[2]\n");
+		exit(1);
+	}
+
+
+	actualKernelLen = kernelLen - ElfHeaderSize;
+
+	printf("actual kernel length (minus ELF header) = %ld/%lxx \n", actualKernelLen, actualKernelLen);
+
+	round = actualKernelLen % 4096;
+	roundedKernelLen = actualKernelLen;
+	if ( round )
+		roundedKernelLen += (4096 - round);
+
+	printf("Kernel length rounded up to a 4k multiple = %ld/%lxx \n", roundedKernelLen, roundedKernelLen);
+	roundedKernelPages = roundedKernelLen / 4096;
+	printf("Kernel pages to copy = %ld/%lxx\n", roundedKernelPages, roundedKernelPages);
+
+
+
+	/* Sysmap file */
+	fseek(sysmap, 0, SEEK_END);
+	sysmapFileLen = ftell(sysmap);
+	fseek(sysmap, 0, SEEK_SET);
+	printf("%s file size = %ld\n", argv[1], sysmapFileLen);
+
+	sysmapLen = sysmapFileLen;
+
+	roundR = 4096 - (sysmapLen % 4096);
+	if (roundR)
+	{
+		printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR);
+		sysmapLen += roundR;
+	}
+	printf("Rounded System Map size is %ld\n", sysmapLen);
+  
+  /* Process the Sysmap file to determine the true end of the kernel */
+	sysmapPages = sysmapLen / 4096;
+	printf("System map pages to copy = %ld\n", sysmapPages);
+	for (i=0; i<sysmapPages; ++i)
+	{
+		get4k(sysmap, inbuf);
+	}
+	/* search for _end in the last page of the system map */
+	ptr_end = strstr(inbuf, " _end");
+	if (!ptr_end)
+	{
+		printf("Unable to find _end in the sysmap file \n");
+		printf("inbuf: \n");
+		printf("%s \n", inbuf);
+		exit(1);
+	}
+	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
+	sysmapStartOffs = (unsigned int)strtol(ptr_end-10, NULL, 16);
+	/* calc how many pages we need to insert between the vmlinux and the start of the sysmap */
+	padPages = sysmapStartOffs/4096 - roundedKernelPages;
+
+	/* Check and see if the vmlinux is larger than _end in System.map */
+	if (padPages < 0)
+	{ /* vmlinux is larger than _end - adjust the offset to start the embedded system map */ 
+		sysmapStartOffs = roundedKernelLen;
+		printf("vmlinux is larger than _end indicates it needs to be - sysmapStartOffs = %lx \n", sysmapStartOffs);
+		padPages = 0;
+		printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages);
+	}
+	else
+	{ /* _end is larger than vmlinux - use the sysmapStartOffs we calculated from the system map */
+		printf("vmlinux is smaller than _end indicates is needed - sysmapStartOffs = %lx \n", sysmapStartOffs);
+		printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages);
+	}
+
+
+
+
+	/* Copy 64K ELF header */
+	for (i=0; i<(ElfPages); ++i)
+	{
+		get4k( inputVmlinux, inbuf );
+		put4k( outputVmlinux, inbuf );
+	}
+
+  
+	/* Copy the vmlinux (as full pages). */
+	fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
+	for ( i=0; i<roundedKernelPages; ++i )
+	{
+		get4k( inputVmlinux, inbuf );
+    
+		/* Set the offsets (of the start and end) of the embedded sysmap so it is set in the vmlinux.sm */
+		if ( i == 0 )
+		{
+			unsigned long * p;
+			printf("Storing embedded_sysmap_start at 0x3c\n");
+			p = (unsigned long *)(inbuf + 0x3c);
+
+#if (BYTE_ORDER == __BIG_ENDIAN)
+			*p = sysmapStartOffs;
+#else
+			*p = bswap_32(sysmapStartOffs);
+#endif
+
+			printf("Storing embedded_sysmap_end at 0x44\n");
+			p = (unsigned long *)(inbuf + 0x44);
+
+#if (BYTE_ORDER == __BIG_ENDIAN)
+			*p = sysmapStartOffs + sysmapFileLen;
+#else
+			*p = bswap_32(sysmapStartOffs + sysmapFileLen);
+#endif
+		}
+    
+		put4k( outputVmlinux, inbuf );
+	}
+  
+  
+	/* Insert any pad pages between the end of the vmlinux and where the system map needs to be. */
+	for (i=0; i<padPages; ++i)
+	{
+		memset(inbuf, 0, 4096);
+		put4k(outputVmlinux, inbuf);
+	}
+
+
+	/* Copy the system map (as full pages). */
+	fseek(sysmap, 0, SEEK_SET);  /* start reading from begining of the system map */
+	for ( i=0; i<sysmapPages; ++i )
+	{
+		get4k( sysmap, inbuf );
+		put4k( outputVmlinux, inbuf );
+	}
+
+
+	fclose(sysmap);
+	fclose(inputVmlinux);
+	fclose(outputVmlinux);
+	/* Set permission to executable */
+	chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
+
+	return 0;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/addnote.c linux-2.4.19-pre5/arch/ppc64/boot/addnote.c
--- linux-2.4.19-pre4/arch/ppc64/boot/addnote.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/addnote.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,164 @@
+/*
+ * Program to hack in a PT_NOTE program header entry in an ELF file.
+ * This is needed for OF on RS/6000s to load an image correctly.
+ * Note that OF needs a program header entry for the note, not an
+ * ELF section.
+ *
+ * Copyright 2000 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Usage: addnote zImage
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+char arch[] = "PowerPC";
+
+#define N_DESCR	6
+unsigned int descr[N_DESCR] = {
+	0xffffffff,		/* real-mode = true */
+	0x00c00000,		/* real-base, i.e. where we expect OF to be */
+	0xffffffff,		/* real-size */
+	0xffffffff,		/* virt-base */
+	0xffffffff,		/* virt-size */
+	0x4000,			/* load-base */
+};
+
+unsigned char buf[512];
+
+#define GET_16BE(off)	((buf[off] << 8) + (buf[(off)+1]))
+#define GET_32BE(off)	((GET_16BE(off) << 16) + GET_16BE((off)+2))
+
+#define PUT_16BE(off, v)	(buf[off] = ((v) >> 8) & 0xff, \
+				 buf[(off) + 1] = (v) & 0xff)
+#define PUT_32BE(off, v)	(PUT_16BE((off), (v) >> 16), \
+				 PUT_16BE((off) + 2, (v)))
+
+/* Structure of an ELF file */
+#define E_IDENT		0	/* ELF header */
+#define	E_PHOFF		28
+#define E_PHENTSIZE	42
+#define E_PHNUM		44
+#define E_HSIZE		52	/* size of ELF header */
+
+#define EI_MAGIC	0	/* offsets in E_IDENT area */
+#define EI_CLASS	4
+#define EI_DATA		5
+
+#define PH_TYPE		0	/* ELF program header */
+#define PH_OFFSET	4
+#define PH_FILESZ	16
+#define PH_HSIZE	32	/* size of program header */
+
+#define PT_NOTE		4	/* Program header type = note */
+
+#define ELFCLASS32	1
+#define ELFDATA2MSB	2
+
+unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
+
+int
+main(int ac, char **av)
+{
+	int fd, n, i;
+	int ph, ps, np;
+	int nnote, ns;
+
+	if (ac != 2) {
+		fprintf(stderr, "Usage: %s elf-file\n", av[0]);
+		exit(1);
+	}
+	fd = open(av[1], O_RDWR);
+	if (fd < 0) {
+		perror(av[1]);
+		exit(1);
+	}
+
+	nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4;
+
+	n = read(fd, buf, sizeof(buf));
+	if (n < 0) {
+		perror("read");
+		exit(1);
+	}
+
+	if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
+		goto notelf;
+
+	if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
+	    || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
+		fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
+			av[1]);
+		exit(1);
+	}
+
+	ph = GET_32BE(E_PHOFF);
+	ps = GET_16BE(E_PHENTSIZE);
+	np = GET_16BE(E_PHNUM);
+	if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
+		goto notelf;
+	if (ph + (np + 1) * ps + nnote > n)
+		goto nospace;
+
+	for (i = 0; i < np; ++i) {
+		if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
+			fprintf(stderr, "%s already has a note entry\n",
+				av[1]);
+			exit(0);
+		}
+		ph += ps;
+	}
+
+	/* XXX check that the area we want to use is all zeroes */
+	for (i = 0; i < ps + nnote; ++i)
+		if (buf[ph + i] != 0)
+			goto nospace;
+
+	/* fill in the program header entry */
+	ns = ph + ps;
+	PUT_32BE(ph + PH_TYPE, PT_NOTE);
+	PUT_32BE(ph + PH_OFFSET, ns);
+	PUT_32BE(ph + PH_FILESZ, nnote);
+
+	/* fill in the note area we point to */
+	/* XXX we should probably make this a proper section */
+	PUT_32BE(ns, strlen(arch) + 1);
+	PUT_32BE(ns + 4, N_DESCR * 4);
+	PUT_32BE(ns + 8, 0x1275);
+	strcpy(&buf[ns + 12], arch);
+	ns += 12 + strlen(arch) + 1;
+	for (i = 0; i < N_DESCR; ++i)
+		PUT_32BE(ns + i * 4, descr[i]);
+
+	/* Update the number of program headers */
+	PUT_16BE(E_PHNUM, np + 1);
+
+	/* write back */
+	lseek(fd, (long) 0, SEEK_SET);
+	i = write(fd, buf, n);
+	if (i < 0) {
+		perror("write");
+		exit(1);
+	}
+	if (i < n) {
+		fprintf(stderr, "%s: write truncated\n", av[1]);
+		exit(1);
+	}
+
+	exit(0);
+
+ notelf:
+	fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]);
+	exit(1);
+
+ nospace:
+	fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
+		av[0]);
+	exit(1);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/crt0.S linux-2.4.19-pre5/arch/ppc64/boot/crt0.S
--- linux-2.4.19-pre4/arch/ppc64/boot/crt0.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/crt0.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * NOTE: this code runs in 32 bit mode and is packaged as ELF32.
+ */
+	.text
+	.globl	_start
+_start:
+	lis	9,_start@h
+	lis	8,_etext@ha
+	addi	8,8,_etext@l
+1:	dcbf	0,9
+	icbi	0,9
+	addi	9,9,0x20
+	cmplwi	0,9,8
+	blt	1b
+	sync
+	isync
+
+	## Clear out the BSS as per ANSI C requirements
+
+	lis 7,_end@ha
+	addi    7,7,_end@l		# r7 = &_end 
+	lis 8,__bss_start@ha		# 
+	addi    8,8,__bss_start@l	# r8 = &_bss_start
+
+	## Determine how large an area, in number of words, to clear
+
+	subf	7,8,7			# r7 = &_end - &_bss_start + 1 
+	addi	7,7,3			# r7 += 3 
+	srwi.	7,7,2			# r7 = size in words.
+	beq	3f			# If the size is zero, do not bother
+	addi	8,8,-4			# r8 -= 4 
+	mtctr	7			# SPRN_CTR = number of words to clear
+	li	0,0			# r0 = 0
+2:	stwu	0,4(8)			# Clear out a word
+	bdnz	2b			# If we are not done yet, keep clearing
+3:
+
+
+	b	start
+
+
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+	.global	flush_cache
+flush_cache:
+	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
+	rlwinm.	4,4,27,5,31
+	mtctr	4
+	beqlr
+1:	dcbf	0,3
+	icbi	0,3
+	addi	3,3,0x20
+	bdnz	1b
+	sync
+	isync
+	blr
+
+
+#define r0	0
+#define r3	3
+#define r4	4
+#define r5	5
+#define r6	6
+#define r7	7
+#define r8	8
+
+	.globl	strcpy
+strcpy:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strncpy
+strncpy:
+	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	blr
+
+	.globl	strcat
+strcat:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r5)
+	cmpwi	0,r0,0
+	bne	1b
+	addi	r5,r5,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strcmp
+strcmp:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r5)
+	cmpwi	1,r3,0
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	beqlr	1
+	beq	1b
+	blr
+
+	.globl	strlen
+strlen:
+	addi	r4,r3,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	bne	1b
+	subf	r3,r3,r4
+	blr
+
+	.globl	memset
+memset:
+	rlwimi	r4,r4,8,16,23
+	rlwimi	r4,r4,16,0,15
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	rlwinm	r0,r5,32-2,2,31
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+
+	.globl	bcopy
+bcopy:
+	mr	r6,r3
+	mr	r3,r4
+	mr	r4,r6
+	b	memcpy
+
+	.globl	memmove
+memmove:
+	cmplw	0,r3,r4
+	bgt	backwards_memcpy
+	/* fall through */
+
+	.globl	memcpy
+memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	addi	r6,r3,-4
+	addi	r4,r4,-4
+	beq	2f			/* if less than 8 bytes to do */
+	andi.	r0,r6,3			/* get dest word aligned */
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,4(r4)
+	lwzu	r8,8(r4)
+	stw	r7,4(r6)
+	stwu	r8,8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,4(r4)
+	addi	r5,r5,-4
+	stwu	r0,4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r4,r4,3
+	addi	r6,r6,3
+4:	lbzu	r0,1(r4)
+	stbu	r0,1(r6)
+	bdnz	4b
+	blr
+5:	subfic	r0,r0,4
+	mtctr	r0
+6:	lbz	r7,4(r4)
+	addi	r4,r4,1
+	stb	r7,4(r6)
+	addi	r6,r6,1
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	backwards_memcpy
+backwards_memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	add	r6,r3,r5
+	add	r4,r4,r5
+	beq	2f
+	andi.	r0,r6,3
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,-4(r4)
+	lwzu	r8,-8(r4)
+	stw	r7,-4(r6)
+	stwu	r8,-8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,-4(r4)
+	subi	r5,r5,4
+	stwu	r0,-4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+4:	lbzu	r0,-1(r4)
+	stbu	r0,-1(r6)
+	bdnz	4b
+	blr
+5:	mtctr	r0
+6:	lbzu	r7,-1(r4)
+	stbu	r7,-1(r6)
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	memcmp
+memcmp:
+	cmpwi	0,r5,0
+	blelr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r6)
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	bdnzt	2,1b
+	blr
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/main.c linux-2.4.19-pre5/arch/ppc64/boot/main.c
--- linux-2.4.19-pre4/arch/ppc64/boot/main.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/main.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Updates for PPC64 by Todd Inglett & Dave Engebretsen.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define __KERNEL__
+#include "zlib.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+
+void memmove(void *dst, void *im, int len);
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+extern void printf(const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...);
+void gunzip(void *, int, unsigned char *, int *);
+void *claim(unsigned int, unsigned int, unsigned int);
+void flush_cache(void *, int);
+void pause(void);
+static struct bi_record *make_bi_recs(unsigned long);
+
+#define RAM_START	0x00000000
+#define RAM_END		(64<<20)
+
+#define BOOT_START	((unsigned long)_start)
+#define BOOT_END	((unsigned long)_end)
+
+/* Value picked to match that used by yaboot */
+#define PROG_START	0x01400000
+
+char *avail_ram;
+char *begin_avail, *end_avail;
+char *avail_high;
+unsigned int heap_use;
+unsigned int heap_max;
+unsigned long initrd_start = 0;
+unsigned long initrd_size = 0;
+
+extern char _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+extern char sysmap_data[];
+extern int sysmap_len;
+extern int uncompressed_size;
+extern long vmlinux_end;
+
+static char scratch[128<<10];	/* 128kB of scratch space for gunzip */
+
+typedef void (*kernel_entry_t)( unsigned long,
+                                unsigned long,
+                                void *,
+				struct bi_record *);
+
+void
+chrpboot(unsigned long a1, unsigned long a2, void *prom)
+{
+	unsigned len;
+	void *dst = (void *)-1;
+	unsigned long claim_addr;
+	unsigned char *im;
+	extern char _start;
+	struct bi_record *bi_recs;
+	kernel_entry_t kernel_entry;
+    
+	printf("chrpboot starting: loaded at 0x%x\n\r", (unsigned)&_start);
+
+	if (initrd_len) {
+		initrd_size = initrd_len;
+		initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+		a1 = a2 = 0;
+		claim(initrd_start, RAM_END - initrd_start, 0);
+		printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r",
+		       initrd_start, (unsigned long)initrd_data, initrd_size);
+		memcpy((void *)initrd_start, (void *)initrd_data, initrd_size);
+	}
+
+	im = image_data;
+	len = image_len;
+	uncompressed_size = PAGE_ALIGN(uncompressed_size);
+
+	for(claim_addr = PROG_START; 
+	    claim_addr <= PROG_START * 8; 
+	    claim_addr += 0x100000) {
+		printf("    trying: 0x%08lx\n\r", claim_addr);
+		dst = claim(claim_addr, uncompressed_size, 0);
+		if (dst != (void *)-1) break;
+	}
+	if (dst == (void *)-1) {
+		printf("claim error, can't allocate kernel memory\n\r");
+		return;
+	}
+
+	if (im[0] == 0x1f && im[1] == 0x8b) {
+		avail_ram = scratch;
+		begin_avail = avail_high = avail_ram;
+		end_avail = scratch + sizeof(scratch);
+		printf("gunzipping (0x%x <- 0x%x:0x%0x)...",
+		       (unsigned)dst, (unsigned)im, (unsigned)im+len);
+		gunzip(dst, uncompressed_size, im, &len);
+		printf("done %u bytes\n\r", len);
+		printf("%u bytes of heap consumed, max in use %u\n\r",
+		       (unsigned)(avail_high - begin_avail), heap_max);
+	} else {
+		memmove(dst, im, len);
+	}
+
+	flush_cache(dst, len);
+
+	bi_recs = make_bi_recs((unsigned long)dst + vmlinux_end);
+
+	kernel_entry = (kernel_entry_t)dst;
+	printf( "kernel:\n\r"
+		"        entry addr = 0x%lx\n\r"
+		"        a1         = 0x%lx,\n\r"
+		"        a2         = 0x%lx,\n\r"
+		"        prom       = 0x%lx,\n\r"
+		"        bi_recs    = 0x%lx,\n\r",
+		(unsigned long)kernel_entry, a1, a2,
+		(unsigned long)prom, (unsigned long)bi_recs);
+
+	kernel_entry( a1, a2, prom, bi_recs );
+
+	printf("returned?\n\r");
+
+	pause();
+}
+
+static struct bi_record *
+make_bi_recs(unsigned long addr)
+{
+	struct bi_record *bi_recs;
+	struct bi_record *rec;
+
+	bi_recs = rec = bi_rec_init(addr);
+
+	rec = bi_rec_alloc(rec, 2);
+	rec->tag = BI_FIRST;
+	/* rec->data[0] = ...;	# Written below before return */
+	/* rec->data[1] = ...;	# Written below before return */
+
+	rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1);
+	rec->tag = BI_BOOTLOADER_ID;
+	sprintf( (char *)rec->data, "chrpboot");
+
+	rec = bi_rec_alloc(rec, 2);
+	rec->tag = BI_MACHTYPE;
+	rec->data[0] = _MACH_pSeries;
+	rec->data[1] = 1;
+
+	if ( initrd_size > 0 ) {
+		rec = bi_rec_alloc(rec, 2);
+		rec->tag = BI_INITRD;
+		rec->data[0] = initrd_start;
+		rec->data[1] = initrd_size;
+	}
+
+#if 0
+	if ( sysmap_len > 0 ) {
+		rec = bi_rec_alloc(rec, 2);
+		rec->tag = BI_SYSMAP;
+		rec->data[0] = (unsigned long)sysmap_data;
+		rec->data[1] = sysmap_len;
+	}
+#endif
+
+	rec = bi_rec_alloc(rec, 1);
+	rec->tag = BI_LAST;
+	rec->data[0] = (bi_rec_field)bi_recs;
+
+	/* Save the _end_ address of the bi_rec's in the first bi_rec
+	 * data field for easy access by the kernel.
+	 */
+	bi_recs->data[0] = (bi_rec_field)rec;
+	bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs;
+
+	return bi_recs;
+}
+
+struct memchunk {
+	unsigned int size;
+	unsigned int pad;
+	struct memchunk *next;
+};
+
+static struct memchunk *freechunks;
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+	void *p;
+	struct memchunk **mpp, *mp;
+
+	size *= items;
+	size = _ALIGN(size, sizeof(struct memchunk));
+	heap_use += size;
+	if (heap_use > heap_max)
+		heap_max = heap_use;
+	for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) {
+		if (mp->size == size) {
+			*mpp = mp->next;
+			return mp;
+		}
+	}
+	p = avail_ram;
+	avail_ram += size;
+	if (avail_ram > avail_high)
+		avail_high = avail_ram;
+	if (avail_ram > end_avail) {
+		printf("oops... out of memory\n\r");
+		pause();
+	}
+	return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+	struct memchunk *mp = addr;
+
+	nb = _ALIGN(nb, sizeof(struct memchunk));
+	heap_use -= nb;
+	if (avail_ram == addr + nb) {
+		avail_ram = addr;
+		return;
+	}
+	mp->size = nb;
+	mp->next = freechunks;
+	freechunks = mp;
+}
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+	z_stream s;
+	int r, i, flags;
+
+	/* skip header */
+	i = 10;
+	flags = src[3];
+	if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+		printf("bad gzipped data\n\r");
+		exit();
+	}
+	if ((flags & EXTRA_FIELD) != 0)
+		i = 12 + src[10] + (src[11] << 8);
+	if ((flags & ORIG_NAME) != 0)
+		while (src[i++] != 0)
+			;
+	if ((flags & COMMENT) != 0)
+		while (src[i++] != 0)
+			;
+	if ((flags & HEAD_CRC) != 0)
+		i += 2;
+	if (i >= *lenp) {
+		printf("gunzip: ran out of data in header\n\r");
+		exit();
+	}
+
+	s.zalloc = zalloc;
+	s.zfree = zfree;
+	r = inflateInit2(&s, -MAX_WBITS);
+	if (r != Z_OK) {
+		printf("inflateInit2 returned %d\n\r", r);
+		exit();
+	}
+	s.next_in = src + i;
+	s.avail_in = *lenp - i;
+	s.next_out = dst;
+	s.avail_out = dstlen;
+	r = inflate(&s, Z_FINISH);
+	if (r != Z_OK && r != Z_STREAM_END) {
+		printf("inflate returned %d msg: %s\n\r", r, s.msg);
+		exit();
+	}
+	*lenp = s.next_out - (unsigned char *) dst;
+	inflateEnd(&s);
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/mknote.c linux-2.4.19-pre5/arch/ppc64/boot/mknote.c
--- linux-2.4.19-pre4/arch/ppc64/boot/mknote.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/mknote.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Cort Dougan 1999.
+ *
+ * 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.
+ *
+ * Generate a note section as per the CHRP specification.
+ *
+ */
+
+#include <stdio.h>
+
+#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
+
+int main(void)
+{
+/* header */
+	/* namesz */
+	PL(strlen("PowerPC")+1);
+	/* descrsz */
+	PL(6*4);
+	/* type */
+	PL(0x1275);
+	/* name */
+	printf("PowerPC"); printf("%c", 0);
+	
+/* descriptor */
+	/* real-mode */
+	PL(0xffffffff);
+	/* real-base */
+	PL(0x00c00000);
+	/* real-size */
+	PL(0xffffffff);
+	/* virt-base */
+	PL(0xffffffff);
+	/* virt-size */
+	PL(0xffffffff);
+	/* load-base */
+	PL(0x4000);
+	return 0;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/no_initrd.c linux-2.4.19-pre5/arch/ppc64/boot/no_initrd.c
--- linux-2.4.19-pre4/arch/ppc64/boot/no_initrd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/no_initrd.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,2 @@
+char initrd_data[1];
+int initrd_len = 0;
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/piggyback.c linux-2.4.19-pre5/arch/ppc64/boot/piggyback.c
--- linux-2.4.19-pre4/arch/ppc64/boot/piggyback.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/piggyback.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2001 IBM Corp 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdio.h>
+#include <unistd.h>
+
+extern long ce_exec_config[];
+
+int main(int argc, char *argv[])
+{
+	int i, cnt, pos, len;
+	unsigned int cksum, val;
+	unsigned char *lp;
+	unsigned char buf[8192];
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: %s name <in-file >out-file\n",
+			argv[0]);
+		exit(1);
+	}
+	fprintf(stdout, "#\n");
+	fprintf(stdout, "# Miscellaneous data structures:\n");
+	fprintf(stdout, "# WARNING - this file is automatically generated!\n");
+	fprintf(stdout, "#\n");
+	fprintf(stdout, "\n");
+	fprintf(stdout, "\t.data\n");
+	fprintf(stdout, "\t.globl %s_data\n", argv[1]);
+	fprintf(stdout, "%s_data:\n", argv[1]);
+	pos = 0;
+	cksum = 0;
+	while ((len = read(0, buf, sizeof(buf))) > 0)
+	{
+		cnt = 0;
+		lp = (unsigned char *)buf;
+		len = (len + 3) & ~3;  /* Round up to longwords */
+		for (i = 0;  i < len;  i += 4)
+		{
+			if (cnt == 0)
+			{
+				fprintf(stdout, "\t.long\t");
+			}
+			fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+			val = *(unsigned long *)lp;
+			cksum ^= val;
+			lp += 4;
+			if (++cnt == 4)
+			{
+				cnt = 0;
+				fprintf(stdout, " # %x \n", pos+i-12);
+				fflush(stdout);
+			} else
+			{
+				fprintf(stdout, ",");
+			}
+		}
+		if (cnt)
+		{
+			fprintf(stdout, "0\n");
+		}
+		pos += len;
+	}
+	fprintf(stdout, "\t.globl %s_len\n", argv[1]);
+	fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos);
+	fflush(stdout);
+	fclose(stdout);
+	fprintf(stderr, "cksum = %x\n", cksum);
+	exit(0);
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/start.c linux-2.4.19-pre5/arch/ppc64/boot/start.c
--- linux-2.4.19-pre4/arch/ppc64/boot/start.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/start.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <asm/div64.h>
+
+int (*prom)(void *);
+
+void *chosen_handle;
+void *stdin;
+void *stdout;
+void *stderr;
+
+void exit(void);
+void *finddevice(const char *name);
+int getprop(void *phandle, const char *name, void *buf, int buflen);
+void chrpboot(int a1, int a2, void *prom);	/* in main.c */
+
+void printk(char *fmt, ...);
+
+void
+start(int a1, int a2, void *promptr)
+{
+	prom = (int (*)(void *)) promptr;
+	chosen_handle = finddevice("/chosen");
+	if (chosen_handle == (void *) -1)
+		exit();
+	if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+		exit();
+	stderr = stdout;
+	if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
+	exit();
+
+	chrpboot(a1, a2, promptr);
+	for (;;)
+		exit();
+}
+
+int
+write(void *handle, void *ptr, int nb)
+{
+	struct prom_args {
+		char *service;
+		int nargs;
+		int nret;
+		void *ihandle;
+		void *addr;
+		int len;
+		int actual;
+	} args;
+
+	args.service = "write";
+	args.nargs = 3;
+	args.nret = 1;
+	args.ihandle = handle;
+	args.addr = ptr;
+	args.len = nb;
+	args.actual = -1;
+	(*prom)(&args);
+	return args.actual;
+}
+
+int
+read(void *handle, void *ptr, int nb)
+{
+	struct prom_args {
+		char *service;
+		int nargs;
+		int nret;
+		void *ihandle;
+		void *addr;
+		int len;
+		int actual;
+	} args;
+
+	args.service = "read";
+	args.nargs = 3;
+	args.nret = 1;
+	args.ihandle = handle;
+	args.addr = ptr;
+	args.len = nb;
+	args.actual = -1;
+	(*prom)(&args);
+	return args.actual;
+}
+
+void
+exit()
+{
+	struct prom_args {
+		char *service;
+	} args;
+
+	for (;;) {
+		args.service = "exit";
+		(*prom)(&args);
+	}
+}
+
+void
+pause(void)
+{
+	struct prom_args {
+		char *service;
+	} args;
+
+	args.service = "enter";
+	(*prom)(&args);
+}
+
+void *
+finddevice(const char *name)
+{
+	struct prom_args {
+		char *service;
+		int nargs;
+		int nret;
+		const char *devspec;
+		void *phandle;
+	} args;
+
+	args.service = "finddevice";
+	args.nargs = 1;
+	args.nret = 1;
+	args.devspec = name;
+	args.phandle = (void *) -1;
+	(*prom)(&args);
+	return args.phandle;
+}
+
+void *
+claim(unsigned long virt, unsigned long size, unsigned long align)
+{
+	struct prom_args {
+		char *service;
+		int nargs;
+		int nret;
+		unsigned int virt;
+		unsigned int size;
+		unsigned int align;
+		void *ret;
+	} args;
+
+	args.service = "claim";
+	args.nargs = 3;
+	args.nret = 1;
+	args.virt = virt;
+	args.size = size;
+	args.align = align;
+	(*prom)(&args);
+	return args.ret;
+}
+
+int
+getprop(void *phandle, const char *name, void *buf, int buflen)
+{
+	struct prom_args {
+		char *service;
+		int nargs;
+		int nret;
+		void *phandle;
+		const char *name;
+		void *buf;
+		int buflen;
+		int size;
+	} args;
+
+	args.service = "getprop";
+	args.nargs = 4;
+	args.nret = 1;
+	args.phandle = phandle;
+	args.name = name;
+	args.buf = buf;
+	args.buflen = buflen;
+	args.size = -1;
+	(*prom)(&args);
+	return args.size;
+}
+
+int
+putc(int c, void *f)
+{
+	char ch = c;
+
+	if (c == '\n')
+		putc('\r', f);
+	return write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+	return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+	int n = strlen(str);
+
+	return write(f, str, n) == n? 0: -1;
+}
+
+int
+readchar(void)
+{
+	char ch;
+
+	for (;;) {
+		switch (read(stdin, &ch, 1)) {
+		case 1:
+			return ch;
+		case -1:
+			printk("read(stdin) returned -1\r\n");
+			return -1;
+		}
+	}
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar(void)
+{
+	int c;
+
+	if (lineleft == 0) {
+		lineptr = line;
+		for (;;) {
+			c = readchar();
+			if (c == -1 || c == 4)
+				break;
+			if (c == '\r' || c == '\n') {
+				*lineptr++ = '\n';
+				putchar('\n');
+				break;
+			}
+			switch (c) {
+			case 0177:
+			case '\b':
+				if (lineptr > line) {
+					putchar('\b');
+					putchar(' ');
+					putchar('\b');
+					--lineptr;
+				}
+				break;
+			case 'U' & 0x1F:
+				while (lineptr > line) {
+					putchar('\b');
+					putchar(' ');
+					putchar('\b');
+					--lineptr;
+				}
+				break;
+			default:
+				if (lineptr >= &line[sizeof(line) - 1])
+					putchar('\a');
+				else {
+					putchar(c);
+					*lineptr++ = c;
+				}
+			}
+		}
+		lineleft = lineptr - line;
+		lineptr = line;
+	}
+	if (lineleft == 0)
+		return -1;
+	--lineleft;
+	return *lineptr++;
+}
+
+
+
+/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
+
+size_t strnlen(const char * s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((*cp == 'x') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	}
+	while (isxdigit(*cp) &&
+	       (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+	if(*cp=='-')
+		return -simple_strtoul(cp+1,endp,base);
+	return simple_strtoul(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+	int i=0;
+
+	while (isdigit(**s))
+		i = i*10 + *((*s)++) - '0';
+	return i;
+}
+
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+#define SPECIAL	32		/* 0x */
+#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * str, long long num, int base, int size, int precision, int type)
+{
+	char c,sign,tmp[66];
+	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	int i;
+
+	if (type & LARGE)
+		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if (num < 0) {
+			sign = '-';
+			num = -num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[do_div(num,base)];
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT)))
+		while(size-->0)
+			*str++ = ' ';
+	if (sign)
+		*str++ = sign;
+	if (type & SPECIAL) {
+		if (base==8)
+			*str++ = '0';
+		else if (base==16) {
+			*str++ = '0';
+			*str++ = digits[33];
+		}
+	}
+	if (!(type & LEFT))
+		while (size-- > 0)
+			*str++ = c;
+	while (i < precision--)
+		*str++ = '0';
+	while (i-- > 0)
+		*str++ = tmp[i];
+	while (size-- > 0)
+		*str++ = ' ';
+	return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+	int len;
+	unsigned long long num;
+	int i, base;
+	char * str;
+	const char *s;
+
+	int flags;		/* flags to number() */
+
+	int field_width;	/* width of output field */
+	int precision;		/* min. # of digits for integers; max
+				   number of chars for from string */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+	                        /* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+
+	
+	for (str=buf ; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			*str++ = *fmt;
+			continue;
+		}
+			
+		/* process flags */
+		flags = 0;
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-': flags |= LEFT; goto repeat;
+				case '+': flags |= PLUS; goto repeat;
+				case ' ': flags |= SPACE; goto repeat;
+				case '#': flags |= SPECIAL; goto repeat;
+				case '0': flags |= ZEROPAD; goto repeat;
+				}
+		
+		/* get field width */
+		field_width = -1;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			field_width = va_arg(args, int);
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= LEFT;
+			}
+		}
+
+		/* get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			++fmt;	
+			if (isdigit(*fmt))
+				precision = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				precision = va_arg(args, int);
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
+			qualifier = *fmt;
+			++fmt;
+		}
+
+		/* default base */
+		base = 10;
+
+		switch (*fmt) {
+		case 'c':
+			if (!(flags & LEFT))
+				while (--field_width > 0)
+					*str++ = ' ';
+			*str++ = (unsigned char) va_arg(args, int);
+			while (--field_width > 0)
+				*str++ = ' ';
+			continue;
+
+		case 's':
+			s = va_arg(args, char *);
+			if (!s)
+				s = "<NULL>";
+
+			len = strnlen(s, precision);
+
+			if (!(flags & LEFT))
+				while (len < field_width--)
+					*str++ = ' ';
+			for (i = 0; i < len; ++i)
+				*str++ = *s++;
+			while (len < field_width--)
+				*str++ = ' ';
+			continue;
+
+		case 'p':
+			if (field_width == -1) {
+				field_width = 2*sizeof(void *);
+				flags |= ZEROPAD;
+			}
+			str = number(str,
+				(unsigned long) va_arg(args, void *), 16,
+				field_width, precision, flags);
+			continue;
+
+
+		case 'n':
+			if (qualifier == 'l') {
+				long * ip = va_arg(args, long *);
+				*ip = (str - buf);
+			} else if (qualifier == 'Z') {
+				size_t * ip = va_arg(args, size_t *);
+				*ip = (str - buf);
+			} else {
+				int * ip = va_arg(args, int *);
+				*ip = (str - buf);
+			}
+			continue;
+
+		case '%':
+			*str++ = '%';
+			continue;
+
+		/* integer number formats - set up the flags and "break" */
+		case 'o':
+			base = 8;
+			break;
+
+		case 'X':
+			flags |= LARGE;
+		case 'x':
+			base = 16;
+			break;
+
+		case 'd':
+		case 'i':
+			flags |= SIGN;
+		case 'u':
+			break;
+
+		default:
+			*str++ = '%';
+			if (*fmt)
+				*str++ = *fmt;
+			else
+				--fmt;
+			continue;
+		}
+		if (qualifier == 'L')
+			num = va_arg(args, long long);
+		else if (qualifier == 'l') {
+			num = va_arg(args, unsigned long);
+			if (flags & SIGN)
+				num = (signed long) num;
+		} else if (qualifier == 'Z') {
+			num = va_arg(args, size_t);
+		} else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
+			if (flags & SIGN)
+				num = (signed short) num;
+		} else {
+			num = va_arg(args, unsigned int);
+			if (flags & SIGN)
+				num = (signed int) num;
+		}
+		str = number(str, num, base, field_width, precision, flags);
+	}
+	*str = '\0';
+	return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsprintf(buf,fmt,args);
+	va_end(args);
+	return i;
+}
+
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	write(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	write(stdout, sprint_buf, n);
+	return n;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/zImage.lds linux-2.4.19-pre5/arch/ppc64/boot/zImage.lds
--- linux-2.4.19-pre4/arch/ppc64/boot/zImage.lds	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/zImage.lds	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,78 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)      }
+  .dynsym        : { *(.dynsym)        }
+  .dynstr        : { *(.dynstr)        }
+  .rel.text      : { *(.rel.text)      }
+  .rela.text     : { *(.rela.text)     }
+  .rel.data      : { *(.rel.data)      }
+  .rela.data     : { *(.rela.data)     }
+  .rel.rodata    : { *(.rel.rodata)    }
+  .rela.rodata   : { *(.rela.rodata)   }
+  .rel.got       : { *(.rel.got)       }
+  .rela.got      : { *(.rela.got)      }
+  .rel.ctors     : { *(.rel.ctors) }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors) }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.bss       : { *(.rel.bss)       }
+  .rela.bss      : { *(.rela.bss)      }
+  .rel.plt       : { *(.rel.plt)       }
+  .rela.plt      : { *(.rela.plt)      }
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  . = ALIGN(4096);
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .kstrtab   : { *(.kstrtab) }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  /* Read-write section, merged into data segment: */
+  . = ALIGN(4096);
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  . = ALIGN(4096);
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  .fixup   : { *(.fixup) }
+
+  . = ALIGN(4096);
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  . = ALIGN(4096);
+  _end = . ;
+  PROVIDE (end = .);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/zlib.c linux-2.4.19-pre5/arch/ppc64/boot/zlib.c
--- linux-2.4.19-pre4/arch/ppc64/boot/zlib.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/zlib.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,2170 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+  Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+
+ *
+ * 
+ */
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL	((void *) 0)
+#endif
+
+        /* common constants */
+
+#define DEFLATED   8
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+         /* functions */
+
+#include <linux/string.h>
+#define zmemcpy memcpy
+#define zmemzero(dest, len)	memset(dest, 0, len)
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void   zcfree  OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size)	\
+	   (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+    z_stream *z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+local int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));                      /* initial return code */
+
+local void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_addhistory OF((
+    inflate_blocks_statef *,
+    z_stream *));
+
+local int inflate_packet_flush OF((
+    inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt Nalloc;	/* number of these allocated here */
+    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
+  union {
+    uInt Base;          /* literal, length base, or distance base */
+    inflate_huft *Next; /* pointer to next level of table */
+  } more;
+};
+
+#ifdef DEBUG_ZLIB
+  local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *));     /* distance tree result */
+
+local int inflate_trees_free OF((
+    inflate_huft *,             /* tables to free */
+    z_stream *));               /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_stream *));
+
+local int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+local void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+    mode;               /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state, sizeof(struct internal_state));
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+/*  if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/*  if (z->zfree == Z_NULL) z->zfree = zcfree; */
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+       inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+  return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = "unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      if ((b = NEXTBYTE) & 0x20)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid reserved bit";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      z->state->mode = BLOCKS;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = BAD;
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONEB,     /* finished last block, done */
+      BADB}      /* got a data error--stuck here */
+    mode;               /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+      int nblens;		/* # elements allocated at blens */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_huft *tl, *td;    /* trees to free */
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/*
+ * The IBM 150 firmware munges the data right after _etext[].  This
+ * protects it. -- Cort
+ */
+local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0};
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  if (s->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s, sizeof(struct inflate_blocks_state));
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->check);
+  return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = "invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if (((~b) >> 16) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = "invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : TYPE;
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = "too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      s->sub.trees.nblens = t;
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = BADB;
+            z->msg = "invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          inflate_trees_free(td, z);
+          inflate_trees_free(tl, z);
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONEB;
+    case DONEB:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADB:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  inflate_blocks_reset(s, z, c);
+  ZFREE(z, s->window, s->end - s->window);
+  ZFREE(z, s, sizeof(struct inflate_blocks_state));
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+	return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+	t = n;  /* how many to do */
+	/* is there room until end of buffer? */
+	if (t > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	zmemcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WRAP  */ 	/* expand WRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+    inflate_blocks_statef *s;
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    uIntf *,            /* list of base values for non-simple codes */
+    uIntf *,            /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    z_stream *));       /* for zalloc function */
+
+local voidpf falloc OF((
+    voidpf,             /* opaque pointer (not used) */
+    uInt,               /* number of items */
+    uInt));             /* size of item */
+
+local void ffree OF((
+    voidpf q,           /* opaque pointer (not used) */
+    voidpf p,           /* what to free (not used) */
+    uInt n));		/* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local uInt cpdext[] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+  uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= N_MAX) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+uIntf *d;               /* list of base values for non-simple codes */
+uIntf *e;               /* list of extra bits for non-simple codes */  
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+z_stream *zs;           /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+   over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  uInt v[N_MAX];                /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (uInt)l ? l : z;      /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (inflate_huft *)ZALLOC
+             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+        {
+          if (h)
+            inflate_trees_free(u[0], zs);
+          return Z_MEM_ERROR;   /* not enough memory */
+        }
+	q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->next)) = Z_NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          r.next = q;           /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+  if (r == Z_DATA_ERROR)
+    z->msg = "oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = "incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  /* build literal/length tree */
+  if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    inflate_trees_free(*tl, z);
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530      /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q;        /* opaque pointer (not used) */
+uInt n;         /* number of items */
+uInt s;         /* size of item */
+{
+  Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+         "inflate_trees falloc overflow");
+  if (q) s++; /* to make some compilers happy */
+  fixed_left -= n;
+  return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+  Assert(0, "inflate_trees ffree called!");
+  if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+{
+  /* build fixed tables if not built already--lock out other instances */
+  while (++fixed_lock > 1)
+    fixed_lock--;
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    unsigned c[288];    /* length list for huft_build */
+    z_stream z;         /* for falloc function */
+
+    /* set up fake z_stream for memory routines */
+    z.zalloc = falloc;
+    z.zfree = ffree;
+    z.opaque = Z_NULL;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    fixed_built = 1;
+  }
+  fixed_lock--;
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t;        /* table to free */
+z_stream *z;            /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register inflate_huft *p, *q;
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != Z_NULL)
+  {
+    q = (--p)->next;
+    ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+    p = q;
+  } 
+  return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+    mode;               /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+  ZFREE(z, c, sizeof(struct inflate_codes_state));
+  Tracev((stderr, "inflate:       codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt n;
+  Bytef *p, *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (q - s->window);  /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = "invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = "invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end",          /* Z_STREAM_END    1 */
+"",                    /* Z_OK            0 */
+"file error",          /* Z_ERRNO        (-1) */
+"stream error",        /* Z_STREAM_ERROR (-2) */
+"data error",          /* Z_DATA_ERROR   (-3) */
+"insufficient memory", /* Z_MEM_ERROR    (-4) */
+"buffer error",        /* Z_BUF_ERROR    (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf)  {s1 += *buf++; s2 += s1;}
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+    uLong adler;
+    Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+            k -= 16;
+        }
+        if (k != 0) do {
+            DO1(buf);
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/boot/zlib.h linux-2.4.19-pre5/arch/ppc64/boot/zlib.h
--- linux-2.4.19-pre4/arch/ppc64/boot/zlib.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/boot/zlib.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,432 @@
+/*		*/
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ *  ==FILEVERSION 960122==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 0.95, Aug 16th, 1995.
+
+  Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */	/* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+     The library does not install any signal handler. It is recommended to
+  add at least a handler for SIGSEGV when decompressing; the library checks
+  the consistency of the input data whenever possible but may go nuts
+  for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+#  if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+#    define STDC
+#  endif
+#endif
+
+#ifdef	__MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+#  include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            1 << (windowBits+2)   +  1 << (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms may be added later and will have the same
+  stream interface.
+
+     For compression the application must provide the output buffer and
+  may optionally provide the input buffer for optimization. For decompression,
+  the application must provide the input buffer and may optionally provide
+  the output buffer for optimization.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidp      opaque;  /* private data object passed to zalloc and zfree */
+
+    Byte     data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH    2
+#define Z_SYNC_FLUSH    3 /* experimental: partial_flush + byte align */
+#define Z_FINISH        4
+#define Z_PACKET_FLUSH	5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Used to set the data_type field */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+ */
+
+                        /* basic functions */
+
+extern int inflateInit OF((z_stream *strm));
+/* 
+     Initializes the internal stream state for decompression. The fields
+   zalloc and zfree must be initialized before by the caller.  If zalloc and
+   zfree are set to Z_NULL, inflateInit updates them to use default allocation
+   functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory.  msg is set to null if there is no error message.
+   inflateInit does not perform any decompression: this will be done by
+   inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() always provides as much output as possible
+    (until there is no more input data or no more space in the output buffer).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate().
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+  inflate flushes as much output as possible to the output buffer. The
+  flushing behavior of inflate is not specified for values of the flush
+  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+  current implementation actually flushes as much output as possible
+  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
+  has been consumed, it is expecting to see the length field of a stored
+  block; if not, it returns Z_DATA_ERROR.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+    inflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if the end of the
+  compressed data has been reached and all uncompressed output has been
+  produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+  the stream structure was inconsistent (for example if next_in or next_out
+  was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+  progress is possible or if there was not enough room in the output buffer
+  when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+  call inflateSync to look for a good compression block.  */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* advanced functions */
+
+extern int inflateInit2 OF((z_stream *strm,
+                            int  windowBits));
+/*   
+     This is another version of inflateInit with more compression options. The
+   fields next_out, zalloc and zfree must be initialized before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library (the value 16 will be allowed soon). The
+   default value is 15 if inflateInit is used instead. If a compressed stream
+   with a larger window size is given as input, inflate() will return with
+   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     If next_out is not null, the library will use this buffer for the history
+   buffer; the buffer must either be large enough to hold the entire output
+   data, or have at least 1<<windowBits bytes.  If next_out is null, the
+   library will allocate its own buffer (and leave next_out null). next_in
+   need not be provided here but must be provided by the application for the
+   next call of inflate().
+
+     If the history buffer is provided by the application, next_out must
+   never be changed by the application since the decompressor maintains
+   history information inside this buffer from call to call; the application
+   can only reset next_out to the beginning of the history buffer when
+   avail_out is zero and all output has been consumed.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   windowBits < 8). msg is set to null if there is no error message.
+   inflateInit2 does not perform any decompression: this will be done by
+   inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/* 
+    Skips invalid compressed data until the special marker (see deflate()
+  above) can be found, or until all available input is skipped. No output
+  is provided.
+
+    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no marker has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* checksum functions */
+
+/*
+     This function is not related to compression but is exported
+   anyway because it might be useful in applications using the
+   compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/config.in linux-2.4.19-pre5/arch/ppc64/config.in
--- linux-2.4.19-pre4/arch/ppc64/config.in	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/config.in	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,242 @@
+# 
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+#
+define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
+define_bool CONFIG_GENERIC_BUST_SPINLOCK n
+define_bool CONFIG_GENERIC_ISA_DMA y
+define_bool CONFIG_HAVE_DEC_LOCK y
+
+mainmenu_name "64 bit PowerPC Linux Kernel Configuration"
+
+mainmenu_option next_comment
+   comment 'Code maturity level options'
+   bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Platform support'
+define_bool CONFIG_PPC y
+define_bool CONFIG_PPC64 y
+define_bool CONFIG_SERIAL_CONSOLE y
+
+choice 'Machine Type'	\
+	"pSeries       		CONFIG_PPC_PSERIES \
+	 iSeries                CONFIG_PPC_ISERIES" CONFIG_PPC_PSERIES
+
+bool 'Symmetric multi-processing support' CONFIG_SMP
+if [ "$CONFIG_SMP" = "y" ]; then
+  bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
+  if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
+    bool '  Hardware multithreading' CONFIG_HMT
+    bool '  PCI Enhanced Error Handling' CONFIG_PPC_EEH
+  fi
+fi
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+   define_bool CONFIG_MSCHUNKS y
+else
+bool 'MsChunks Physical to Absolute address translation support' CONFIG_MSCHUNKS
+fi
+
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
+define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
+define_bool CONFIG_MCA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_PCI y
+
+bool 'Networking support' CONFIG_NET
+bool 'Sysctl support' CONFIG_SYSCTL
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+
+# only elf supported, a.out is not -- Cort
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+   define_bool CONFIG_KCORE_ELF y
+fi
+
+bool 'Kernel Support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
+
+tristate 'Kernel support for 32 bit binaries' CONFIG_BINFMT_ELF32
+
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+source drivers/pci/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ]; then
+   source drivers/pcmcia/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+fi
+
+source drivers/parport/Config.in
+
+if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
+   bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
+   bool 'Support for frame buffer devices' CONFIG_FB
+
+   bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+fi
+
+endmenu
+
+source drivers/mtd/Config.in
+source drivers/pnp/Config.in
+source drivers/block/Config.in
+source drivers/md/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+fi
+
+mainmenu_option next_comment
+comment 'ATA/IDE/MFM/RLL support'
+
+tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+
+if [ "$CONFIG_IDE" != "n" ]; then
+  source drivers/ide/Config.in
+else
+  define_bool CONFIG_BLK_DEV_IDE_MODES n
+  define_bool CONFIG_BLK_DEV_HD n
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'SCSI support'
+tristate 'SCSI support' CONFIG_SCSI
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
+endmenu
+
+source drivers/ieee1394/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Network device support'
+
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
+   fi
+   endmenu
+fi
+
+source net/ax25/Config.in
+
+source net/irda/Config.in
+
+mainmenu_option next_comment
+comment 'ISDN subsystem'
+
+tristate 'ISDN support' CONFIG_ISDN
+if [ "$CONFIG_ISDN" != "n" ]; then
+   source drivers/isdn/Config.in
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+   source drivers/cdrom/Config.in
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Console drivers'
+source drivers/video/Config.in
+endmenu
+
+source drivers/input/Config.in
+
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+mainmenu_option next_comment
+comment 'iSeries device drivers'
+   dep_tristate 'iSeries Virtual Console Support' CONFIG_VIOCONS $CONFIG_PPC_ISERIES
+   dep_tristate 'iSeries Virtual I/O disk support' CONFIG_VIODASD $CONFIG_PPC_ISERIES
+   if [ "$CONFIG_VIODASD" = "y" -o "$CONFIG_VIODASD" = "m" ]; then
+      bool 'iSeries Virtual disk IDE emulation' CONFIG_VIODASD_IDE
+   fi
+   dep_tristate 'iSeries Virtual I/O CD support' CONFIG_VIOCD $CONFIG_PPC_ISERIES
+   if [ "$CONFIG_VIOCD" = "y" -o "$CONFIG_VIOCD" = "m" ]; then
+      bool 'iSeries Virtual CD Aztech emulation' CONFIG_VIOCD_AZTECH
+   fi
+   dep_tristate 'iSeries Virtual Tape Support' CONFIG_VIOTAPE  $CONFIG_PPC_ISERIES
+   dep_tristate 'iSeries Virtual Ethernet driver support' CONFIG_VETH $CONFIG_PPC_ISERIES
+endmenu
+fi
+
+if [ "$CONFIG_VIOCONS" = "n" ]; then
+   if [ "$CONFIG_VIODASD" = "n" ]; then
+      if [ "$CONFIG_VIOTAPE" = "n" ]; then
+         if [ "$CONFIG_VIOCD" = "n" ]; then
+		    define_bool CONFIG_VIOPATH n
+		 else
+		    define_bool CONFIG_VIOPATH y
+         fi
+	  else
+	     define_bool CONFIG_VIOPATH y
+      fi
+   else
+      define_bool CONFIG_VIOPATH y
+   fi
+else
+   define_bool CONFIG_VIOPATH y
+fi
+
+if [ "$CONFIG_VIOCD" = "y" ]; then
+   define_bool CONFIG_CD_NO_IDESCSI y
+fi
+
+source drivers/char/Config.in
+source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Sound'
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source drivers/sound/dmasound/Config.in
+   source drivers/sound/Config.in
+fi
+
+endmenu
+
+source drivers/usb/Config.in
+
+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
+#bool 'Include kdb kernel debugger' CONFIG_KDB
+#if [ "$CONFIG_KDB" = "y" ]; then
+#  bool '  KDB off by default' CONFIG_KDB_OFF
+#  define_bool CONFIG_KALLSYMS y
+#fi
+bool 'Include PPCDBG realtime debugging' CONFIG_PPCDBG
+endmenu
diff -urN linux-2.4.19-pre4/arch/ppc64/configs/iSeries_devfs_defconfig linux-2.4.19-pre5/arch/ppc64/configs/iSeries_devfs_defconfig
--- linux-2.4.19-pre4/arch/ppc64/configs/iSeries_devfs_defconfig	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/configs/iSeries_devfs_defconfig	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,699 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_PPC_PSERIES is not set
+CONFIG_PPC_ISERIES=y
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_MSCHUNKS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_EISA is not set
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_ELF32=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_LVM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+CONFIG_TR=y
+CONFIG_IBMOL=m
+# CONFIG_IBMLS is not set
+# CONFIG_TMS380TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# iSeries device drivers
+#
+CONFIG_VIOCONS=y
+CONFIG_VIODASD=y
+# CONFIG_VIODASD_IDE is not set
+CONFIG_VIOCD=m
+# CONFIG_VIOCD_AZTECH is not set
+CONFIG_VIOTAPE=m
+CONFIG_VETH=y
+CONFIG_VIOPATH=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=1024
+# CONFIG_HVC_CONSOLE is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_MWAVE is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_PPCDBG is not set
diff -urN linux-2.4.19-pre4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linux-2.4.19-pre5/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig
--- linux-2.4.19-pre4/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,724 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_PPC_PSERIES is not set
+CONFIG_PPC_ISERIES=y
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_MSCHUNKS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_EISA is not set
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_ELF32=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=64000
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_LARGE_TABLES=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+CONFIG_TR=y
+CONFIG_IBMOL=m
+# CONFIG_IBMLS is not set
+# CONFIG_TMS380TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+CONFIG_CD_NO_IDESCSI=y
+# CONFIG_AZTCD is not set
+# CONFIG_GSCD is not set
+# CONFIG_SBPCD is not set
+# CONFIG_MCD is not set
+# CONFIG_MCDX is not set
+# CONFIG_OPTCD is not set
+# CONFIG_CM206 is not set
+# CONFIG_SJCD is not set
+# CONFIG_ISP16_CDI is not set
+# CONFIG_CDU31A is not set
+# CONFIG_CDU535 is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# iSeries device drivers
+#
+CONFIG_VIOCONS=y
+CONFIG_VIODASD=y
+CONFIG_VIODASD_IDE=y
+CONFIG_VIOCD=m
+# CONFIG_VIOCD_AZTECH is not set
+CONFIG_VIOTAPE=m
+CONFIG_VETH=y
+CONFIG_VIOPATH=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+CONFIG_ICOM=m
+# CONFIG_SYNCLINK is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=1024
+# CONFIG_HVC_CONSOLE is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_MWAVE is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=y
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_NCP_FS=y
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_PPCDBG is not set
diff -urN linux-2.4.19-pre4/arch/ppc64/configs/pSeries_defconfig linux-2.4.19-pre5/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.19-pre4/arch/ppc64/configs/pSeries_defconfig	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/configs/pSeries_defconfig	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,804 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_PPC_PSERIES=y
+# CONFIG_PPC_ISERIES is not set
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+# CONFIG_HMT is not set
+# CONFIG_PPC_EEH is not set
+# CONFIG_MSCHUNKS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_EISA is not set
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_ELF32=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+CONFIG_PROC_DEVICETREE=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+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_HD is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=y
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+CONFIG_TR=y
+CONFIG_IBMOL=y
+# CONFIG_IBMLS is not set
+# CONFIG_TMS380TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_G450 is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_VIOPATH=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_HVC_CONSOLE=y
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+CONFIG_NVRAM=y
+CONFIG_RTC=y
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_MWAVE is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+CONFIG_XMON=y
+CONFIG_PPCDBG=y
diff -urN linux-2.4.19-pre4/arch/ppc64/defconfig linux-2.4.19-pre5/arch/ppc64/defconfig
--- linux-2.4.19-pre4/arch/ppc64/defconfig	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/defconfig	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,804 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_PPC_PSERIES=y
+# CONFIG_PPC_ISERIES is not set
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+# CONFIG_HMT is not set
+# CONFIG_PPC_EEH is not set
+# CONFIG_MSCHUNKS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_EISA is not set
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_ELF32=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+CONFIG_PROC_DEVICETREE=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+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_HD is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=y
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+CONFIG_TR=y
+CONFIG_IBMOL=y
+# CONFIG_IBMLS is not set
+# CONFIG_TMS380TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_G450 is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_VIOPATH=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_HVC_CONSOLE=y
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+CONFIG_NVRAM=y
+CONFIG_RTC=y
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_MWAVE is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+CONFIG_XMON=y
+CONFIG_PPCDBG=y
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/HvCall.c linux-2.4.19-pre5/arch/ppc64/kernel/HvCall.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/HvCall.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/HvCall.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,115 @@
+/*
+ * HvCall.c
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/iSeries/HvCall.h>
+#ifndef  _HVCALLSC_H
+#include <asm/iSeries/HvCallSc.h>
+#endif
+#include <asm/iSeries/LparData.h>
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+
+/*=====================================================================
+ * Note that this call takes at MOST one page worth of data
+ */
+int HvCall_readLogBuffer(HvLpIndex lpIndex, void *buffer, u64 bufLen)
+{
+	struct HvLpBufferList *bufList;
+	u64 bytesLeft = bufLen;
+	u64 leftThisPage;
+	u64 curPtr = virt_to_absolute( (unsigned long) buffer );
+	u64 retVal;
+	int npages;
+	int i;
+
+	npages = 0;
+	while (bytesLeft) {
+		npages++;
+		leftThisPage = ((curPtr & PAGE_MASK) + PAGE_SIZE) - curPtr;
+
+		if (leftThisPage > bytesLeft)
+			bytesLeft = 0;
+		else
+			bytesLeft -= leftThisPage;
+
+		curPtr = (curPtr & PAGE_MASK) + PAGE_SIZE;
+	}
+
+	if (npages == 0)
+		return 0;
+
+	bufList = (struct HvLpBufferList *)
+		kmalloc(npages * sizeof(struct HvLpBufferList), GFP_ATOMIC);
+	bytesLeft = bufLen;
+	curPtr = virt_to_absolute( (unsigned long) buffer );
+	for(i=0; i<npages; i++) {
+		bufList[i].addr = curPtr;
+      
+		leftThisPage = ((curPtr & PAGE_MASK) + PAGE_SIZE) - curPtr;
+
+		if (leftThisPage > bytesLeft) {
+			bufList[i].len = bytesLeft;
+			bytesLeft = 0;
+		} else {
+			bufList[i].len = leftThisPage;
+			bytesLeft -= leftThisPage;
+		}
+
+		curPtr = (curPtr & PAGE_MASK) + PAGE_SIZE;
+	}
+
+
+	retVal = HvCall3(HvCallBaseReadLogBuffer, lpIndex,
+			 virt_to_absolute((unsigned long)bufList), bufLen);
+
+	kfree(bufList);
+
+	return (int)retVal;
+}
+
+/*=====================================================================
+ */
+void HvCall_writeLogBuffer(const void *buffer, u64 bufLen)
+{
+	struct HvLpBufferList bufList;
+	u64 bytesLeft = bufLen;
+	u64 leftThisPage;
+	u64 curPtr = virt_to_absolute( (unsigned long) buffer );
+
+	while (bytesLeft) {
+		bufList.addr = curPtr;
+      
+		leftThisPage = ((curPtr & PAGE_MASK) + PAGE_SIZE) - curPtr;
+
+		if (leftThisPage > bytesLeft) {
+			bufList.len = bytesLeft;
+			bytesLeft = 0;
+		} else {
+			bufList.len = leftThisPage;
+			bytesLeft -= leftThisPage;
+		}
+
+		curPtr = (curPtr & PAGE_MASK) + PAGE_SIZE;
+	}
+
+
+	HvCall2(HvCallBaseWriteLogBuffer,
+		virt_to_absolute((unsigned long)&bufList), bufLen);
+
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/HvLpConfig.c linux-2.4.19-pre5/arch/ppc64/kernel/HvLpConfig.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/HvLpConfig.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/HvLpConfig.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,28 @@
+/*
+ * HvLpConfig.c
+ * Copyright (C) 2001  Kyle A. Lucke, IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _HVLPCONFIG_H
+#include <asm/iSeries/HvLpConfig.h>
+#endif
+
+HvLpIndex HvLpConfig_getLpIndex_outline(void)
+{
+	return HvLpConfig_getLpIndex();
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/HvLpEvent.c linux-2.4.19-pre5/arch/ppc64/kernel/HvLpEvent.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/HvLpEvent.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/HvLpEvent.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2001 Mike Corrigan IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvCallEvent.h>
+#include <asm/iSeries/LparData.h>
+
+/* Array of LpEvent handler functions */
+LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
+unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
+
+/* Register a handler for an LpEvent type */
+
+int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler handler )
+{
+	int rc = 1;
+	if ( eventType < HvLpEvent_Type_NumTypes ) {
+		lpEventHandler[eventType] = handler;
+		rc = 0;
+	}
+	return rc;
+	
+}
+
+int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType )
+{
+	int rc = 1;
+	if ( eventType < HvLpEvent_Type_NumTypes ) {
+		if ( !lpEventHandlerPaths[eventType] ) {
+			lpEventHandler[eventType] = NULL;
+			rc = 0;
+		}
+	}
+	return rc;
+}
+
+/* (lpIndex is the partition index of the target partition.  
+ * needed only for VirtualIo, VirtualLan and SessionMgr.  Zero
+ * indicates to use our partition index - for the other types)
+ */
+int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex )
+{
+	int rc = 1;
+	if ( eventType < HvLpEvent_Type_NumTypes &&
+	     lpEventHandler[eventType] ) {
+		if ( lpIndex == 0 )
+			lpIndex = itLpNaca.xLpIndex;
+		HvCallEvent_openLpEventPath( lpIndex, eventType );
+		++lpEventHandlerPaths[eventType];
+		rc = 0;
+	}
+	return rc;
+}
+
+int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex )
+{
+	int rc = 1;
+	if ( eventType < HvLpEvent_Type_NumTypes &&
+	     lpEventHandler[eventType] &&
+	     lpEventHandlerPaths[eventType] ) {
+		if ( lpIndex == 0 )
+			lpIndex = itLpNaca.xLpIndex;
+		HvCallEvent_closeLpEventPath( lpIndex, eventType );
+		--lpEventHandlerPaths[eventType];
+		rc = 0;
+	}
+	return rc;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ItLpQueue.c linux-2.4.19-pre5/arch/ppc64/kernel/ItLpQueue.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ItLpQueue.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ItLpQueue.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,170 @@
+/*
+ * ItLpQueue.c
+ * Copyright (C) 2001 Mike Corrigan  IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvCallEvent.h>
+#include <asm/iSeries/LparData.h>
+
+static __inline__ int set_inUse( struct ItLpQueue * lpQueue )
+{
+	int t;
+	u32 * inUseP = &(lpQueue->xInUseWord);
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2		\n\
+	cmpi	0,%0,0		\n\
+	li	%0,0		\n\
+	bne-	2f		\n\
+	addi	%0,%0,1		\n\
+	stwcx.	%0,0,%2		\n\
+	bne-	1b		\n\
+2:	eieio"
+	: "=&r" (t), "=m" (lpQueue->xInUseWord)
+	: "r" (inUseP), "m" (lpQueue->xInUseWord)
+	: "cc");
+
+	return t;
+}
+
+static __inline__ void clear_inUse( struct ItLpQueue * lpQueue )
+{
+	lpQueue->xInUseWord = 0;
+}
+
+/* Array of LpEvent handler functions */
+extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
+unsigned long ItLpQueueInProcess = 0;
+
+struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue )
+{
+	struct HvLpEvent * nextLpEvent = 
+		(struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
+	if ( nextLpEvent->xFlags.xValid ) {
+		/* rmb() needed only for weakly consistent machines (regatta) */
+		rmb();
+		/* Set pointer to next potential event */
+		lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
+				      LpEventAlign ) /
+				      LpEventAlign ) *
+				      LpEventAlign;
+		/* Wrap to beginning if no room at end */
+		if (lpQueue->xSlicCurEventPtr > lpQueue->xSlicLastValidEventPtr)
+			lpQueue->xSlicCurEventPtr = lpQueue->xSlicEventStackPtr;
+	}
+	else 
+		nextLpEvent = NULL;
+
+	return nextLpEvent;
+}
+
+int ItLpQueue_isLpIntPending( struct ItLpQueue * lpQueue )
+{
+	int retval = 0;
+	struct HvLpEvent * nextLpEvent;
+	if ( lpQueue ) {
+		nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
+		retval = nextLpEvent->xFlags.xValid | lpQueue->xPlicOverflowIntPending;
+	}
+	return retval;
+}
+
+void ItLpQueue_clearValid( struct HvLpEvent * event )
+{
+	/* Clear the valid bit of the event
+	 * Also clear bits within this event that might
+	 * look like valid bits (on 64-byte boundaries)
+   	 */
+	unsigned extra = (( event->xSizeMinus1 + LpEventAlign ) /
+						 LpEventAlign ) - 1;
+	switch ( extra ) {
+	  case 3:
+	   ((struct HvLpEvent*)((char*)event+3*LpEventAlign))->xFlags.xValid=0;
+	  case 2:
+	   ((struct HvLpEvent*)((char*)event+2*LpEventAlign))->xFlags.xValid=0;
+	  case 1:
+	   ((struct HvLpEvent*)((char*)event+1*LpEventAlign))->xFlags.xValid=0;
+	  case 0:
+	   ;	
+	}
+	mb();
+	event->xFlags.xValid = 0;
+}
+
+unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs )
+{
+	unsigned numIntsProcessed = 0;
+	struct HvLpEvent * nextLpEvent;
+
+	/* If we have recursed, just return */
+	if ( !set_inUse( lpQueue ) )
+		return 0;
+	
+	if (ItLpQueueInProcess == 0)
+		ItLpQueueInProcess = 1;
+	else
+		BUG();
+
+	for (;;) {
+		nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue );
+		if ( nextLpEvent ) {
+			/* Count events to return to caller
+			 * and count processed events in lpQueue
+ 			 */
+			++numIntsProcessed;
+			lpQueue->xLpIntCount++;		
+			/* Call appropriate handler here, passing 
+			 * a pointer to the LpEvent.  The handler
+			 * must make a copy of the LpEvent if it
+			 * needs it in a bottom half. (perhaps for
+			 * an ACK)
+			 *	
+			 *  Handlers are responsible for ACK processing 
+			 *
+			 * The Hypervisor guarantees that LpEvents will
+			 * only be delivered with types that we have
+			 * registered for, so no type check is necessary
+			 * here!
+  			 */
+			if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes )
+				lpQueue->xLpIntCountByType[nextLpEvent->xType]++;
+			if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes &&
+			     lpEventHandler[nextLpEvent->xType] ) 
+				lpEventHandler[nextLpEvent->xType](nextLpEvent, regs);
+			else
+				printk(KERN_INFO "Unexpected Lp Event type=%d\n", nextLpEvent->xType );
+			
+			ItLpQueue_clearValid( nextLpEvent );
+		}
+		else 	/* No more valid events
+			 * If overflow events are pending
+			 * process them
+			 */
+			if ( lpQueue->xPlicOverflowIntPending ) {
+				HvCallEvent_getOverflowLpEvents( 
+						lpQueue->xIndex);
+			}
+			else	/* If nothing left then we are done */
+				break;
+	}
+
+	ItLpQueueInProcess = 0;
+	mb();
+	clear_inUse( lpQueue );
+
+	get_paca()->lpEvent_count += numIntsProcessed;
+
+	return numIntsProcessed;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/LparData.c linux-2.4.19-pre5/arch/ppc64/kernel/LparData.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/LparData.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/LparData.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,252 @@
+/* 
+ * Copyright 2001 Mike Corrigan, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define __KERNEL__ 1
+#include <asm/types.h>
+#include <asm/page.h>
+#include <stddef.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/init.h>
+#include <asm/Naca.h>
+#include <asm/abs_addr.h>
+#include <asm/bitops.h>
+#include <asm/iSeries/ItLpNaca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpRegSave.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/HvReleaseData.h>
+#include <asm/iSeries/LparMap.h>
+#include <asm/iSeries/ItVpdAreas.h>
+#include <asm/iSeries/ItIplParmsReal.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/IoHriProcessorVpd.h>
+#include <asm/iSeries/ItSpCommArea.h>
+
+extern char _start_boltedStacks[];
+
+/* The LparMap data is now located at offset 0x6000 in head.S
+ * It was put there so that the HvReleaseData could address it
+ * with a 32-bit offset as required by the iSeries hypervisor
+ *
+ * The Naca has a pointer to the ItVpdAreas.  The hypervisor finds
+ * the Naca via the HvReleaseData area.  The HvReleaseData has the
+ * offset into the Naca of the pointer to the ItVpdAreas.
+ */
+
+extern struct ItVpdAreas itVpdAreas;
+
+/* The LpQueue is used to pass event data from the hypervisor to
+ * the partition.  This is where I/O interrupt events are communicated.
+ * The ItLpQueue must be initialized (even though only to all zeros)
+ * If it were uninitialized (in .bss) it would get zeroed after the
+ * kernel gets control.  The hypervisor will have filled in some fields
+ * before the kernel gets control.  By initializing it we keep it out
+ * of the .bss
+ */
+
+struct ItLpQueue xItLpQueue = {};
+
+
+/* The HvReleaseData is the root of the information shared between 
+ * the hypervisor and Linux.  
+ */
+
+struct HvReleaseData hvReleaseData = {
+	0xc8a5d9c4,	/* desc = "HvRD" ebcdic */
+	sizeof(struct HvReleaseData),
+	offsetof(struct Naca, xItVpdAreas),
+	(struct Naca *)(KERNELBASE+0x4000),	/* 64-bit Naca address */
+	0x6000,		/* offset of LparMap within loadarea (see head.S) */
+	0,
+	1,		/* tags inactive       */
+	0,		/* 64 bit              */
+	0,		/* shared processors   */
+	0,		/* HMT allowed         */
+	6,		/* TEMP: This allows non-GA driver */
+	4,		/* We are v5r2m0               */
+	3,		/* Min supported PLIC = v5r1m0 */
+	3,		/* Min usuable PLIC   = v5r1m0 */
+	{ 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4   "*/
+	  0xa7, 0x40, 0xf2, 0x4b,
+	  0xf4, 0x4b, 0xf6, 0xf4 },
+	{0}  
+};
+
+extern void SystemReset_Iseries(void);
+extern void MachineCheck_Iseries(void);
+extern void DataAccess_Iseries(void);
+extern void InstructionAccess_Iseries(void);
+extern void HardwareInterrupt_Iseries(void);
+extern void Alignment_Iseries(void);
+extern void ProgramCheck_Iseries(void);
+extern void FPUnavailable_Iseries(void);
+extern void Decrementer_Iseries(void);
+extern void Trap_0a_Iseries(void);
+extern void Trap_0b_Iseries(void);
+extern void SystemCall_Iseries(void);
+extern void SingleStep_Iseries(void);
+extern void Trap_0e_Iseries(void);
+extern void PerformanceMonitor_Iseries(void);
+extern void DataAccessSLB_Iseries(void);
+extern void InstructionAccessSLB_Iseries(void);
+	
+struct ItLpNaca itLpNaca = {
+	0xd397d581,	/* desc = "LpNa" ebcdic */
+	0x0400,		/* size of ItLpNaca     */
+	0x0300, 19,	/* offset to int array, # ents */
+	0, 0, 0,	/* Part # of primary, serv, me */
+	0, 0x100,	/* # of LP queues, offset */
+	0, 0, 0,	/* Piranha stuff */
+	{ 0,0,0,0,0 },	/* reserved */
+	0,0,0,0,0,0,0,	/* stuff    */
+	{ 0,0,0,0,0 },	/* reserved */
+	0,		/* reserved */
+	0,		/* VRM index of PLIC */
+	0, 0,		/* min supported, compat SLIC */
+	0,		/* 64-bit addr of load area   */
+	0,		/* chunks for load area  */
+	0, 0,		/* PASE mask, seg table  */
+	{ 0 },		/* 64 reserved bytes  */
+	{ 0 }, 		/* 128 reserved bytes */
+	{ 0 }, 		/* Old LP Queue       */
+	{ 0 }, 		/* 384 reserved bytes */
+	{
+		(u64)SystemReset_Iseries,	/* 0x100 System Reset */
+		(u64)MachineCheck_Iseries,	/* 0x200 Machine Check */
+		(u64)DataAccess_Iseries,	/* 0x300 Data Access */
+		(u64)InstructionAccess_Iseries,	/* 0x400 Instruction Access */
+		(u64)HardwareInterrupt_Iseries,	/* 0x500 External */
+		(u64)Alignment_Iseries,		/* 0x600 Alignment */
+		(u64)ProgramCheck_Iseries,	/* 0x700 Program Check */
+		(u64)FPUnavailable_Iseries,	/* 0x800 FP Unavailable */
+		(u64)Decrementer_Iseries,	/* 0x900 Decrementer */
+		(u64)Trap_0a_Iseries,		/* 0xa00 Trap 0A */
+		(u64)Trap_0b_Iseries,		/* 0xb00 Trap 0B */
+		(u64)SystemCall_Iseries,	/* 0xc00 System Call */
+		(u64)SingleStep_Iseries,	/* 0xd00 Single Step */
+		(u64)Trap_0e_Iseries,		/* 0xe00 Trap 0E */
+		(u64)PerformanceMonitor_Iseries,/* 0xf00 Performance Monitor */
+		0,				/* int 0x1000 */
+		0,				/* int 0x1010 */
+		0,				/* int 0x1020 CPU ctls */
+		(u64)HardwareInterrupt_Iseries, /* SC Ret Hdlr */
+		(u64)DataAccessSLB_Iseries,	/* 0x380 D-SLB */
+		(u64)InstructionAccessSLB_Iseries /* 0x480 I-SLB */
+	}
+};
+
+struct ItIplParmsReal xItIplParmsReal = {};
+
+struct IoHriProcessorVpd xIoHriProcessorVpd[maxProcessors] = {
+	{
+		xInstCacheOperandSize: 32,
+		xDataCacheOperandSize: 32,
+		xProcFreq:     50000000,
+		xTimeBaseFreq: 50000000,
+		xPVR: 0x3600
+	}
+};
+	
+
+u64    xMsVpd[3400] = {};		/* Space for Main Store Vpd 27,200 bytes */
+
+u64    xRecoveryLogBuffer[32] = {};	/* Space for Recovery Log Buffer */
+
+struct SpCommArea xSpCommArea = {
+	0xE2D7C3C2,
+	1,
+	{0},
+	0, 0, 0, 0, {0}
+};
+
+struct ItVpdAreas itVpdAreas = {
+	0xc9a3e5c1,	/* "ItVA" */
+	sizeof( struct ItVpdAreas ),
+	0, 0,
+	26,		/* # VPD array entries */
+	10,		/* # DMA array entries */
+	maxProcessors*2, maxProcessors,	/* Max logical, physical procs */
+	offsetof(struct ItVpdAreas,xPlicDmaToks),/* offset to DMA toks */
+	offsetof(struct ItVpdAreas,xSlicVpdAdrs),/* offset to VPD addrs */
+	offsetof(struct ItVpdAreas,xPlicDmaLens),/* offset to DMA lens */
+	offsetof(struct ItVpdAreas,xSlicVpdLens),/* offset to VPD lens */
+	0,		/* max slot labels */
+	1,		/* max LP queues */
+	{0}, {0},	/* reserved */
+	{0},		/* DMA lengths */
+	{0},		/* DMA tokens */
+	{		/* VPD lengths */
+		0,0,0,0,		/*  0 -  3 */
+		sizeof(struct Paca),	/*       4 length of Paca  */
+		0,			/*       5 */
+		sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
+		26992,			/*	 7 length of MS VPD */
+		0,			/*       8 */
+		sizeof(struct ItLpNaca),/*       9 length of LP Naca */
+		0, 			/*	10 */
+		256,			/*	11 length of Recovery Log Buf */
+		sizeof(struct SpCommArea), /*   12 length of SP Comm Area */
+		0,0,0,			/* 13 - 15 */
+		sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
+		0,0,0,0,0,0,		/* 17 - 22  */
+		sizeof(struct ItLpQueue),/*     23 length of Lp Queue */
+		0,0			/* 24 - 25 */
+		},
+	{			/* VPD addresses */
+		0,0,0,0,		/*	 0 -  3 */
+		&xPaca[0],		/*       4 first Paca */
+		0,			/*       5 */
+		&xItIplParmsReal,	/*	 6 IPL parms */
+		&xMsVpd,		/*	 7 MS Vpd */
+		0,			/*       8 */
+		&itLpNaca,		/*       9 LpNaca */
+		0,			/*	10 */
+		&xRecoveryLogBuffer,	/*	11 Recovery Log Buffer */
+		&xSpCommArea,		/*	12 SP Comm Area */
+		0,0,0,			/* 13 - 15 */
+		&xIoHriProcessorVpd,	/*      16 Proc Vpd */
+		0,0,0,0,0,0,		/* 17 - 22 */
+		&xItLpQueue,		/*      23 Lp Queue */
+		0,0
+	}
+};
+
+
+/* Data area used in flush_hash_page  */
+long long flush_hash_page_hpte[2];
+
+struct msChunks msChunks = {0, 0, 0, 0, NULL};
+
+/* Depending on whether this is called from iSeries or pSeries setup
+ * code, the location of the msChunks struct may or may not have
+ * to be reloc'd, so we force the caller to do that for us by passing
+ * in a pointer to the structure.
+ */
+unsigned long
+msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size)
+{
+	unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+
+	_msChunks->num_chunks  = num_chunks;
+	_msChunks->chunk_size  = chunk_size;
+	_msChunks->chunk_shift = __ilog2(chunk_size);
+	_msChunks->chunk_mask  = (1UL<<_msChunks->chunk_shift)-1;
+
+	mem = _ALIGN(mem, sizeof(msChunks_entry));
+	_msChunks->abs = (msChunks_entry *)(mem + offset);
+	mem += num_chunks * sizeof(msChunks_entry);
+
+	return mem;
+}
+
+
+
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/Makefile linux-2.4.19-pre5/arch/ppc64/kernel/Makefile
--- linux-2.4.19-pre4/arch/ppc64/kernel/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/Makefile	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,77 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+USE_STANDARD_AS_RULE    := true
+
+EXTRA_CFLAGS = -mno-minimal-toc
+
+KHEAD := head.o
+
+all: $(KHEAD) kernel.o
+
+O_TARGET := kernel.o
+
+export-objs         := ppc_ksyms.o setup.o
+
+obj-y               :=	ppc_ksyms.o setup.o entry.o traps.o irq.o idle.o \
+			time.o process.o signal.o syscalls.o misc.o ptrace.o \
+			align.o semaphore.o bitops.o stab.o htab.o pacaData.o \
+			LparData.o udbg.o binfmt_elf32.o sys_ppc32.o sys32.o \
+			ioctl32.o ptrace32.o signal32.o open_pic.o xics.o \
+			pmc.o mf_proc.o proc_pmc.o proc_pcifr.o iSeries_setup.o \
+			ItLpQueue.o hvCall.o mf.o HvLpEvent.o ras.o \
+			iSeries_proc.o HvCall.o flight_recorder.o HvLpConfig.o \
+			rtc.o
+
+obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o
+obj-$(CONFIG_PPC_EEH) += eeh.o
+
+ifeq ($(CONFIG_PPC_ISERIES),y)
+obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o iSeries_IoMmTable.o iSeries_irq.o iSeries_VpdInfo.o XmPciLpEvent.o 
+endif
+ifeq ($(CONFIG_PPC_PSERIES),y)
+obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o
+
+obj-y += rtasd.o 
+endif
+
+obj-$(CONFIG_KGDB) += ppc-stub.o
+
+obj-$(CONFIG_SMP) += smp.o
+
+# tibit: for matrox_init2()
+ifeq ($(CONFIG_NVRAM),y)
+   obj-$(CONFIG_NVRAM) += pmac_nvram.o
+endif
+
+obj-y += prom.o lmb.o rtas.o rtas-proc.o chrp_setup.o i8259.o
+
+include $(TOPDIR)/Rules.make
+
+#
+# This is just to get the dependencies...
+#
+
+head.o: head.S ppc_defs.h
+
+ppc_defs.h: mk_defs.c ppc_defs.head \
+		$(TOPDIR)/include/asm/mmu.h \
+		$(TOPDIR)/include/asm/processor.h \
+		$(TOPDIR)/include/asm/pgtable.h \
+		$(TOPDIR)/include/asm/ptrace.h
+	$(CC) $(CFLAGS) -S mk_defs.c
+	cp ppc_defs.head ppc_defs.h
+# for bk, this way we can write to the file even if it's not checked out
+	chmod u+w ppc_defs.h
+	grep '^#define' mk_defs.s >> ppc_defs.h
+	rm mk_defs.s
+
+checks: checks.c
+	$(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c
+	./checks
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/XmPciLpEvent.c linux-2.4.19-pre5/arch/ppc64/kernel/XmPciLpEvent.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/XmPciLpEvent.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/XmPciLpEvent.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,157 @@
+/*
+   * File XmPciLpEvent.h created by Wayne Holm on Mon Jan 15 2001.
+   *
+   * This module handles PCI interrupt events sent by the iSeries Hypervisor.
+*/
+
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/blk.h>
+#include <linux/ide.h>
+
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvCallPci.h>
+#include <asm/iSeries/XmPciLpEvent.h>
+#include <asm/ppcdebug.h>
+
+long Pci_Interrupt_Count = 0;
+long Pci_Event_Count     = 0;
+
+enum XmPciLpEvent_Subtype {
+	XmPciLpEvent_BusCreated	   = 0,		// PHB has been created
+	XmPciLpEvent_BusFailed	   = 1,		// PHB has failed
+	XmPciLpEvent_BusRecovered  = 12,	// PHB has been recovered
+	XmPciLpEvent_NodeFailed	   = 4,		// Multi-adapter bridge has failed
+	XmPciLpEvent_NodeRecovered = 5,		// Multi-adapter bridge has recovered
+	XmPciLpEvent_SlotInterrupt = 22		// Slot interrupt
+};
+
+struct XmPciLpEvent_BusInterrupt {
+	HvBusNumber		busNumber;
+	HvSubBusNumber	subBusNumber;
+};
+
+struct XmPciLpEvent_NodeInterrupt {
+	HvBusNumber		busNumber;
+	HvSubBusNumber	subBusNumber;
+	HvAgentId		deviceId;
+};
+
+struct XmPciLpEvent {
+	struct HvLpEvent hvLpEvent;
+
+	union {
+		u64 alignData;			// Align on an 8-byte boundary
+
+		struct {
+			u32			fisr;
+			HvBusNumber	busNumber;
+			HvSubBusNumber	subBusNumber;
+			HvAgentId		deviceId;
+		} slotInterrupt;
+
+		struct XmPciLpEvent_BusInterrupt busFailed;
+		struct XmPciLpEvent_BusInterrupt busRecovered;
+		struct XmPciLpEvent_BusInterrupt busCreated;
+
+		struct XmPciLpEvent_NodeInterrupt nodeFailed;
+		struct XmPciLpEvent_NodeInterrupt nodeRecovered;
+
+	} eventData;
+
+};
+
+static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm);
+
+static void XmPciLpEvent_handler( struct HvLpEvent* eventParm, struct pt_regs* regsParm)
+{
+	//PPCDBG(PPCDBG_BUSWALK,"XmPciLpEvent_handler, type 0x%x\n",eventParm->xType );
+	++Pci_Event_Count;
+
+	if (eventParm && eventParm->xType == HvLpEvent_Type_PciIo) {
+		switch( eventParm->xFlags.xFunction ) {
+		case HvLpEvent_Function_Int:
+			intReceived( (struct XmPciLpEvent*)eventParm, regsParm );
+			break;
+		case HvLpEvent_Function_Ack:
+			printk(KERN_ERR "XmPciLpEvent.c: unexpected ack received\n");
+			break;
+		default:
+			printk(KERN_ERR "XmPciLpEvent.c: unexpected event function %d\n",(int)eventParm->xFlags.xFunction);
+			break;
+		}
+	}
+	else if (event) {
+		printk(KERN_ERR "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n",(int)eventParm->xType);
+	}
+	else {
+		printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n");
+	}
+}
+
+static void intReceived(struct XmPciLpEvent* eventParm, struct pt_regs* regsParm)
+{
+	int irq;
+
+	++Pci_Interrupt_Count;
+	//PPCDBG(PPCDBG_BUSWALK,"PCI: XmPciLpEvent.c: intReceived\n");
+
+	switch (eventParm->hvLpEvent.xSubtype) {
+	case XmPciLpEvent_SlotInterrupt:
+		irq = eventParm->hvLpEvent.xCorrelationToken;
+		/* Dispatch the interrupt handlers for this irq */
+		ppc_irq_dispatch_handler(regsParm, irq);
+		HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
+			      eventParm->eventData.slotInterrupt.subBusNumber,
+			      eventParm->eventData.slotInterrupt.deviceId);
+		break;
+		/* Ignore error recovery events for now */
+	case XmPciLpEvent_BusCreated:
+		printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", eventParm->eventData.busCreated.busNumber);
+		break;
+	case XmPciLpEvent_BusFailed:
+		printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", eventParm->eventData.busFailed.busNumber);
+		break;
+	case XmPciLpEvent_BusRecovered:
+		printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", eventParm->eventData.busRecovered.busNumber);
+		break;
+	case XmPciLpEvent_NodeFailed:
+		printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", eventParm->eventData.nodeFailed.busNumber, eventParm->eventData.nodeFailed.subBusNumber, eventParm->eventData.nodeFailed.deviceId);
+		break;
+	case XmPciLpEvent_NodeRecovered:
+		printk(KERN_INFO "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", eventParm->eventData.nodeRecovered.busNumber, eventParm->eventData.nodeRecovered.subBusNumber, eventParm->eventData.nodeRecovered.deviceId);
+		break;
+	default:
+		printk(KERN_ERR "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
+		       eventParm->hvLpEvent.xSubtype);
+		break;
+	};
+}
+
+
+/* This should be called sometime prior to buswalk (init_IRQ would be good) */
+int XmPciLpEvent_init()
+{
+	int xRc;
+	PPCDBG(PPCDBG_BUSWALK,"XmPciLpEvent_init, Register Event type 0x%04X\n",HvLpEvent_Type_PciIo);
+
+	xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, &XmPciLpEvent_handler);
+	if (xRc == 0) {
+		xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+		if (xRc != 0) {
+			printk(KERN_ERR "XmPciLpEvent.c: open event path failed with rc 0x%x\n", xRc);
+		}
+	}
+	else {
+		printk(KERN_ERR "XmPciLpEvent.c: register handler failed with rc 0x%x\n", xRc);
+    	}
+    return xRc;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/align.c linux-2.4.19-pre5/arch/ppc64/kernel/align.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/align.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/align.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,362 @@
+/*
+ * align.c - handle alignment exceptions for the Power PC.
+ *
+ * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ * Copyright (c) 1998-1999 TiVo, Inc.
+ *   PowerPC 403GCX modifications.
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *   PowerPC 403GCX/405GP modifications.
+ * Copyright (c) 2001 PPC64 team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/cache.h>
+
+struct aligninfo {
+	unsigned char len;
+	unsigned char flags;
+};
+
+#define	OPCD(inst)	(((inst) & 0xFC000000) >> 26)
+#define	RS(inst)	(((inst) & 0x03E00000) >> 21)
+#define	RA(inst)	(((inst) & 0x001F0000) >> 16)
+#define	IS_DFORM(code)	((code) >= 32 && (code) <= 47)
+
+#define INVALID	{ 0, 0 }
+
+#define LD	1	/* load */
+#define ST	2	/* store */
+#define	SE	4	/* sign-extend value */
+#define F	8	/* to/from fp regs */
+#define U	0x10	/* update index register */
+#define M	0x20	/* multiple load/store */
+#define S	0x40	/* single-precision fp, or byte-swap value */
+#define HARD	0x80	/* string, stwcx. */
+#define D	0x100	/* double-word load/store */
+
+#define DCBZ	0x5f	/* 8xx/82xx dcbz faults when cache not enabled */
+
+/*
+ * The PowerPC stores certain bits of the instruction that caused the
+ * alignment exception in the DSISR register.  This array maps those
+ * bits to information about the operand length and what the
+ * instruction would do.
+ */
+static struct aligninfo aligninfo[128] = {
+	{ 4, LD },		/* 00 0 0000: lwz / lwarx */
+	INVALID,		/* 00 0 0001 */
+	{ 4, ST },		/* 00 0 0010: stw */
+	INVALID,		/* 00 0 0011 */
+	{ 2, LD },		/* 00 0 0100: lhz */
+	{ 2, LD+SE },		/* 00 0 0101: lha */
+	{ 2, ST },		/* 00 0 0110: sth */
+	{ 4, LD+M },		/* 00 0 0111: lmw */
+	{ 4, LD+F+S },		/* 00 0 1000: lfs */
+	{ 8, LD+F },		/* 00 0 1001: lfd */
+	{ 4, ST+F+S },		/* 00 0 1010: stfs */
+	{ 8, ST+F },		/* 00 0 1011: stfd */
+	INVALID,		/* 00 0 1100 */
+	{ 8, LD },		/* 00 0 1101: ld */
+	INVALID,		/* 00 0 1110 */
+	{ 8, ST },		/* 00 0 1111: std */
+	{ 4, LD+U },		/* 00 1 0000: lwzu */
+	INVALID,		/* 00 1 0001 */
+	{ 4, ST+U },		/* 00 1 0010: stwu */
+	INVALID,		/* 00 1 0011 */
+	{ 2, LD+U },		/* 00 1 0100: lhzu */
+	{ 2, LD+SE+U },		/* 00 1 0101: lhau */
+	{ 2, ST+U },		/* 00 1 0110: sthu */
+	{ 4, ST+M },		/* 00 1 0111: stmw */
+	{ 4, LD+F+S+U },	/* 00 1 1000: lfsu */
+	{ 8, LD+F+U },		/* 00 1 1001: lfdu */
+	{ 4, ST+F+S+U },	/* 00 1 1010: stfsu */
+	{ 8, ST+F+U },		/* 00 1 1011: stfdu */
+	INVALID,		/* 00 1 1100 */
+	{ 8, ST },		/* 00 1 1101: std */
+	INVALID,		/* 00 1 1110 */
+	INVALID,		/* 00 1 1111 */
+	{ 8, LD },		/* 01 0 0000: ldx */
+	INVALID,		/* 01 0 0001 */
+	{ 8, ST },		/* 01 0 0010: stdx */
+	INVALID,		/* 01 0 0011 */
+	INVALID,		/* 01 0 0100 */
+	INVALID,		/* 01 0 0101: lwax?? */
+	INVALID,		/* 01 0 0110 */
+	INVALID,		/* 01 0 0111 */
+	{ 0, LD+HARD },		/* 01 0 1000: lswx */
+	{ 0, LD+HARD },		/* 01 0 1001: lswi */
+	{ 0, ST+HARD },		/* 01 0 1010: stswx */
+	{ 0, ST+HARD },		/* 01 0 1011: stswi */
+	INVALID,		/* 01 0 1100 */
+	{ 8, LD+U },		/* 01 0 1101: ldu */
+	INVALID,		/* 01 0 1110 */
+	{ 8, ST+U },		/* 01 0 1111: stdu */
+	{ 8, LD+U },		/* 01 1 0000: ldux */
+	INVALID,		/* 01 1 0001 */
+	{ 8, ST+U },		/* 01 1 0010: stdux */
+	INVALID,		/* 01 1 0011 */
+	INVALID,		/* 01 1 0100 */
+	INVALID,		/* 01 1 0101: lwaux?? */
+	INVALID,		/* 01 1 0110 */
+	INVALID,		/* 01 1 0111 */
+	INVALID,		/* 01 1 1000 */
+	INVALID,		/* 01 1 1001 */
+	INVALID,		/* 01 1 1010 */
+	INVALID,		/* 01 1 1011 */
+	INVALID,		/* 01 1 1100 */
+	INVALID,		/* 01 1 1101 */
+	INVALID,		/* 01 1 1110 */
+	INVALID,		/* 01 1 1111 */
+	INVALID,		/* 10 0 0000 */
+	INVALID,		/* 10 0 0001 */
+	{ 0, ST+HARD },		/* 10 0 0010: stwcx. */
+	INVALID,		/* 10 0 0011 */
+	INVALID,		/* 10 0 0100 */
+	INVALID,		/* 10 0 0101 */
+	INVALID,		/* 10 0 0110 */
+	INVALID,		/* 10 0 0111 */
+	{ 4, LD+S },		/* 10 0 1000: lwbrx */
+	INVALID,		/* 10 0 1001 */
+	{ 4, ST+S },		/* 10 0 1010: stwbrx */
+	INVALID,		/* 10 0 1011 */
+	{ 2, LD+S },		/* 10 0 1100: lhbrx */
+	INVALID,		/* 10 0 1101 */
+	{ 2, ST+S },		/* 10 0 1110: sthbrx */
+	INVALID,		/* 10 0 1111 */
+	INVALID,		/* 10 1 0000 */
+	INVALID,		/* 10 1 0001 */
+	INVALID,		/* 10 1 0010 */
+	INVALID,		/* 10 1 0011 */
+	INVALID,		/* 10 1 0100 */
+	INVALID,		/* 10 1 0101 */
+	INVALID,		/* 10 1 0110 */
+	INVALID,		/* 10 1 0111 */
+	INVALID,		/* 10 1 1000 */
+	INVALID,		/* 10 1 1001 */
+	INVALID,		/* 10 1 1010 */
+	INVALID,		/* 10 1 1011 */
+	INVALID,		/* 10 1 1100 */
+	INVALID,		/* 10 1 1101 */
+	INVALID,		/* 10 1 1110 */
+	{ 0, ST+HARD },		/* 10 1 1111: dcbz */
+	{ 4, LD },		/* 11 0 0000: lwzx */
+	INVALID,		/* 11 0 0001 */
+	{ 4, ST },		/* 11 0 0010: stwx */
+	INVALID,		/* 11 0 0011 */
+	{ 2, LD },		/* 11 0 0100: lhzx */
+	{ 2, LD+SE },		/* 11 0 0101: lhax */
+	{ 2, ST },		/* 11 0 0110: sthx */
+	INVALID,		/* 11 0 0111 */
+	{ 4, LD+F+S },		/* 11 0 1000: lfsx */
+	{ 8, LD+F },		/* 11 0 1001: lfdx */
+	{ 4, ST+F+S },		/* 11 0 1010: stfsx */
+	{ 8, ST+F },		/* 11 0 1011: stfdx */
+	INVALID,		/* 11 0 1100 */
+	INVALID,		/* 11 0 1101 */
+	INVALID,		/* 11 0 1110 */
+	INVALID,		/* 11 0 1111 */
+	{ 4, LD+U },		/* 11 1 0000: lwzux */
+	INVALID,		/* 11 1 0001 */
+	{ 4, ST+U },		/* 11 1 0010: stwux */
+	INVALID,		/* 11 1 0011 */
+	{ 2, LD+U },		/* 11 1 0100: lhzux */
+	{ 2, LD+SE+U },		/* 11 1 0101: lhaux */
+	{ 2, ST+U },		/* 11 1 0110: sthux */
+	INVALID,		/* 11 1 0111 */
+	{ 4, LD+F+S+U },	/* 11 1 1000: lfsux */
+	{ 8, LD+F+U },		/* 11 1 1001: lfdux */
+	{ 4, ST+F+S+U },	/* 11 1 1010: stfsux */
+	{ 8, ST+F+U },		/* 11 1 1011: stfdux */
+	INVALID,		/* 11 1 1100 */
+	INVALID,		/* 11 1 1101 */
+	INVALID,		/* 11 1 1110 */
+	INVALID,		/* 11 1 1111 */
+};
+
+#define SWAP(a, b)	(t = (a), (a) = (b), (b) = t)
+
+int
+fix_alignment(struct pt_regs *regs)
+{
+	int instr, nb, flags;
+	int opcode, f1, f2, f3;
+	int i, t;
+	int reg, areg;
+	unsigned char *addr;
+	union {
+		int l;
+		long ll;
+		float f;
+		double d;
+		unsigned char v[8];
+	} data;
+
+	if (__is_processor(PV_POWER4)) {
+		/* 
+		 * The POWER4 has a DSISR register but doesn't set it on
+		 * an alignment fault.  -- paulus
+		 */
+
+		instr = *((unsigned int *)regs->nip);
+		opcode = OPCD(instr);
+		reg = RS(instr);
+		areg = RA(instr);
+
+		if (IS_DFORM(opcode)) {
+			f1 = 0;
+			f2 = (instr & 0x04000000) >> 26;
+			f3 = (instr & 0x78000000) >> 27;
+		} else {
+			f1 = (instr & 0x00000006) >> 1;
+			f2 = (instr & 0x00000040) >> 6;
+			f3 = (instr & 0x00000780) >> 7;
+		}
+
+		instr = ((f1 << 5) | (f2 << 4) | f3);
+	} else {
+		reg = (regs->dsisr >> 5) & 0x1f;	/* source/dest register */
+		areg = regs->dsisr & 0x1f;		/* register to update */
+		instr = (regs->dsisr >> 10) & 0x7f;
+		instr |= (regs->dsisr >> 13) & 0x60;
+	}
+
+	nb = aligninfo[instr].len;
+	if (nb == 0) {
+		long *p;
+		int i;
+
+		if (instr != DCBZ)
+			return 0;	/* too hard or invalid instruction */
+		/*
+		 * The dcbz (data cache block zero) instruction
+		 * gives an alignment fault if used on non-cacheable
+		 * memory.  We handle the fault mainly for the
+		 * case when we are running with the cache disabled
+		 * for debugging.
+		 */
+		p = (long *) (regs->dar & -L1_CACHE_BYTES);
+		for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)
+			p[i] = 0;
+		return 1;
+	}
+
+	flags = aligninfo[instr].flags;
+	addr = (unsigned char *)regs->dar;
+
+	/* Verify the address of the operand */
+	if (user_mode(regs)) {
+		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+			return -EFAULT;	/* bad address */
+	}
+
+	if ((flags & F) && (regs->msr & MSR_FP))
+		giveup_fpu(current);
+	if (flags & M)
+		return 0;		/* too hard for now */
+
+	/* If we read the operand, copy it in */
+	if (flags & LD) {
+		if (nb == 2) {
+			data.v[0] = data.v[1] = 0;
+			if (__get_user(data.v[2], addr)
+			    || __get_user(data.v[3], addr+1))
+				return -EFAULT;
+		} else {
+			for (i = 0; i < nb; ++i)
+				if (__get_user(data.v[i], addr+i))
+					return -EFAULT;
+		}
+	}
+	/* Unfortunately D (== 0x100) doesn't fit in the aligninfo[n].flags
+	   field.  So synthesize it here. */
+	if ((flags & F) == 0 && nb == 8)
+		flags |= D;
+
+	switch (flags & ~U) {
+	case LD+SE:
+		if (data.v[2] >= 0x80)
+			data.v[0] = data.v[1] = -1;
+		/* fall through */
+	case LD:
+		regs->gpr[reg] = data.l;
+		break;
+	case LD+D:
+		regs->gpr[reg] = data.ll;
+		break;
+	case LD+S:
+		if (nb == 2) {
+			SWAP(data.v[2], data.v[3]);
+		} else {
+			SWAP(data.v[0], data.v[3]);
+			SWAP(data.v[1], data.v[2]);
+		}
+		regs->gpr[reg] = data.l;
+		break;
+	case ST:
+		data.l = regs->gpr[reg];
+		break;
+	case ST+D:
+		data.ll = regs->gpr[reg];
+		break;
+	case ST+S:
+		data.l = regs->gpr[reg];
+		if (nb == 2) {
+			SWAP(data.v[2], data.v[3]);
+		} else {
+			SWAP(data.v[0], data.v[3]);
+			SWAP(data.v[1], data.v[2]);
+		}
+		break;
+	case LD+F:
+		current->thread.fpr[reg] = data.d;
+		break;
+	case ST+F:
+		data.d = current->thread.fpr[reg];
+		break;
+	/* these require some floating point conversions... */
+	/* 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:
+		enable_kernel_fp();
+		cvt_fd(&data.f, &current->thread.fpr[reg], &current->thread.fpscr);
+		/* current->thread.fpr[reg] = data.f; */
+		break;
+	case ST+F+S:
+		enable_kernel_fp();
+		cvt_df(&current->thread.fpr[reg], &data.f, &current->thread.fpscr);
+		/* data.f = current->thread.fpr[reg]; */
+		break;
+	default:
+		printk("align: can't handle flags=%x\n", flags);
+		return 0;
+	}
+
+	if (flags & ST) {
+		if (nb == 2) {
+			if (__put_user(data.v[2], addr)
+			    || __put_user(data.v[3], addr+1))
+				return -EFAULT;
+		} else {
+			for (i = 0; i < nb; ++i)
+				if (__put_user(data.v[i], addr+i))
+					return -EFAULT;
+		}
+	}
+
+	if (flags & U) {
+		regs->gpr[areg] = regs->dar;
+	}
+
+	return 1;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/binfmt_elf32.c linux-2.4.19-pre5/arch/ppc64/kernel/binfmt_elf32.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/binfmt_elf32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/binfmt_elf32.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,79 @@
+/*
+ * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons.
+ * based on the SPARC64 version.
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller	(davem@redhat.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek	(jj@ultra.linux.cz)
+ *
+ * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp
+ * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define ELF_ARCH		EM_PPC
+#define ELF_CLASS		ELFCLASS32
+#define ELF_DATA		ELFDATA2MSB;
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+
+struct timeval32
+{
+	int tv_sec, tv_usec;
+};
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+	struct elf_siginfo pr_info;	/* Info associated with signal */
+	short	pr_cursig;		/* Current signal */
+	unsigned int pr_sigpend;	/* Set of pending signals */
+	unsigned int pr_sighold;	/* Set of held signals */
+	pid_t	pr_pid;
+	pid_t	pr_ppid;
+	pid_t	pr_pgrp;
+	pid_t	pr_sid;
+	struct timeval32 pr_utime;	/* User time */
+	struct timeval32 pr_stime;	/* System time */
+	struct timeval32 pr_cutime;	/* Cumulative user time */
+	struct timeval32 pr_cstime;	/* Cumulative system time */
+	elf_gregset_t pr_reg;		/* General purpose registers. */
+	int pr_fpvalid;		/* True if math co-processor being used. */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+	char	pr_state;	/* numeric process state */
+	char	pr_sname;	/* char for pr_state */
+	char	pr_zomb;	/* zombie */
+	char	pr_nice;	/* nice val */
+	unsigned int pr_flag;	/* flags */
+	u32	pr_uid;
+	u32	pr_gid;
+	pid_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	/* Lots missing */
+	char	pr_fname[16];	/* filename of executable */
+	char	pr_psargs[ELF_PRARGSZ];	/* initial part of arg list */
+};
+
+extern void start_thread32(struct pt_regs *, unsigned long, unsigned long);
+#undef start_thread
+#define start_thread start_thread32
+#define init_elf_binfmt init_elf32_binfmt
+
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
+#endif
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
+#endif
+
+#include "../../../fs/binfmt_elf.c"
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/bitops.c linux-2.4.19-pre5/arch/ppc64/kernel/bitops.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/bitops.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/bitops.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ * Adapted for ppc64 - Todd Inglett, Anton Blanchard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+#include <asm/ppcdebug.h>
+
+#undef DEBUG_BITOPS
+
+/*
+ * Bitops are weird when viewed on big-endian systems.  They were designed
+ * on little endian so the size of the bitset doesn't matter (low order bytes
+ * come first) as long as the bit in question is valid.
+ *
+ * Bits are "tested" often using the C expression (val & (1<<nr)) so we do
+ * our best to stay compatible with that.  The assumption is that val will
+ * be unsigned long for such tests.  As such, we assume the bits are stored
+ * as an array of unsigned long (the usual case is a single unsigned long,
+ * of course).  Here's an example bitset with bit numbering:
+ *
+ *   |63..........0|127........64|195.......128|255.......196|
+ *
+ * This leads to two problems.  First, if an int, short or char is passed as
+ * a bitset it will be a bad memory reference since we want to store in chunks
+ * of unsigned long (64 bits here) size.  Second, since these could be char
+ * arrays we might have an alignment problem.  We ease the alignment problem
+ * by actually doing the operation with 32 bit values yet preserving the
+ * 64 bit long layout as shown above.  Got that?  Good.
+ */
+
+unsigned long find_next_zero_bit(void * addr, unsigned long size,
+				 unsigned long offset)
+{
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long result = offset & ~63UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 63UL;
+
+	if (offset) {
+		tmp = *p++;
+		tmp |= ~0UL >> (64-offset);
+		if (size < 64)
+			goto found_first;
+		if (~tmp)
+			goto found_middle;
+		size -= 64;
+		result += 64;
+	}
+	while (size & ~63UL) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 64;
+		size -= 64;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp |= ~0UL << size;
+	if (tmp == ~0UL)
+		return result+size;
+found_middle:
+	return result + ffz(tmp);
+}
+
+void BUG_OUTLINE(char* file, unsigned line) 
+{
+	udbg_printf("BUG - kernel BUG at %s:%d! \n", __FILE__, __LINE__);
+	PPCDBG_ENTER_DEBUGGER();
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__);
+	__asm__ __volatile__(".long " BUG_ILLEGAL_INSTR);
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/checks.c linux-2.4.19-pre5/arch/ppc64/kernel/checks.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/checks.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/checks.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+/*
+ * Do various before compile checks of data structures
+ *
+ * This is invoked when you do a make checks 
+ * Is this enough or are there more things that we would like to do here?
+ * -- tgall
+ */
+int main(void)
+{
+	int ret = 0;
+#if 0
+	if ( sizeof(struct thread_struct) % 16 )
+	{
+		printf("Thread struct is not modulo 16 bytes: "
+			"%d bytes total, %d bytes off\n",
+			sizeof(struct thread_struct),
+			sizeof(struct thread_struct)%16);
+		ret = -1;
+	}
+#endif	
+
+	if ( sizeof(struct pt_regs) % 16 )
+	{
+		printf("pt_regs struct is not modulo 16 bytes: "
+			"%d bytes total, %d bytes off\n",
+			sizeof(struct pt_regs),
+			sizeof(struct pt_regs)%16);
+		ret = -1;
+		
+	}
+
+	printf("Task size        : %d bytes\n"
+	       "Tss size         : %d bytes\n"
+	       "pt_regs size     : %d bytes\n"
+	       "Kernel stack size: %d bytes\n",
+	       sizeof(struct task_struct), sizeof(struct thread_struct),
+	       sizeof(struct pt_regs),
+	       sizeof(union task_union) - sizeof(struct task_struct));
+	return ret;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/chrp_setup.c linux-2.4.19-pre5/arch/ppc64/kernel/chrp_setup.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/chrp_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/chrp_setup.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,389 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified by PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <linux/version.h>
+#include <linux/adb.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/pci-bridge.h>
+#include <asm/pci_dma.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/keyboard.h>
+#include <asm/init.h>
+#include <asm/Naca.h>
+#include <asm/time.h>
+
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
+#include "xics.h"
+#include <asm/ppcdebug.h>
+
+extern volatile unsigned char *chrp_int_ack_special;
+extern struct Naca *naca;
+
+void chrp_setup_pci_ptrs(void);
+void chrp_progress(char *, unsigned short);
+void chrp_request_regions(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 void openpic_init_IRQ(void);
+extern void init_ras_IRQ(void);
+
+extern void find_and_init_phbs(void);
+extern void pSeries_pcibios_fixup(void);
+extern void iSeries_pcibios_fixup(void);
+
+extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
+extern int  pSeries_set_rtc_time(struct rtc_time *rtc_time);
+void pSeries_calibrate_decr(void);
+
+kdev_t boot_dev;
+unsigned long  virtPython0Facilities = 0;  // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address.
+
+extern HPTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;	/* starting block # of image */
+#endif
+
+void 
+chrp_get_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	const char *model = "";
+
+	root = find_path_device("/");
+	if (root)
+		model = get_property(root, "model", NULL);
+	seq_printf(m, "machine\t\t: CHRP %s\n", model);
+}
+
+void __init chrp_request_regions(void) {
+	request_region(0x20,0x20,"pic1");
+	request_region(0xa0,0x20,"pic2");
+	request_region(0x00,0x20,"dma1");
+	request_region(0x40,0x20,"timer");
+	request_region(0x80,0x10,"dma page reg");
+	request_region(0xc0,0x20,"dma2");
+}
+
+void __init
+chrp_setup_arch(void)
+{
+	extern char cmd_line[];
+	struct device_node *root;
+	unsigned int *opprop;
+	
+	/* openpic global configuration register (64-bit format). */
+	/* openpic Interrupt Source Unit pointer (64-bit format). */
+	/* python0 facility area (mmio) (64-bit format) REAL address. */
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* this is fine for chrp */
+	initrd_below_start_ok = 1;
+	
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+	ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
+
+	printk("Boot arguments: %s\n", cmd_line);
+
+	/* Find and initialize PCI host bridges */
+	/* iSeries needs to be done much later. */
+ 	#ifndef CONFIG_PPC_ISERIES
+		find_and_init_phbs();
+ 	#endif
+
+	/* Find the Open PIC if present */
+	root = find_path_device("/");
+	opprop = (unsigned int *) get_property(root,
+				"platform-open-pic", NULL);
+	if (opprop != 0) {
+		int n = prom_n_addr_cells(root);
+		unsigned long openpic;
+
+		for (openpic = 0; n > 0; --n)
+			openpic = (openpic << 32) + *opprop++;
+		printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic);
+		udbg_printf("OpenPIC addr: %lx\n", openpic);
+		OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE);
+	}
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+}
+
+void __init
+chrp_init2(void)
+{
+	/*
+	 * It is sensitive, when this is called (not too earlu)
+	 * -- tibit
+	 */
+	chrp_request_regions();
+	ppc_md.progress(UTS_RELEASE, 0x7777);
+}
+
+
+/* Early initialization.  Relocation is on but do not reference unbolted pages */
+void __init pSeries_init_early(void)
+{
+#ifdef CONFIG_PPC_PSERIES	/* This ifdef should go away */
+	void *comport;
+
+	hpte_init_pSeries();
+	tce_init_pSeries();
+	pSeries_pcibios_init_early();
+
+#ifdef CONFIG_SMP
+	smp_init_pSeries();
+#endif
+
+	/* Map the uart for udbg. */
+	comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
+	udbg_init_uart(comport);
+
+	ppc_md.udbg_putc = udbg_putc;
+	ppc_md.udbg_getc = udbg_getc;
+	ppc_md.udbg_getc_poll = udbg_getc_poll;
+#endif
+}
+
+void __init
+chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
+{
+#if 0 /* PPPBBB remove this later... -Peter */
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r6 )
+	{
+		initrd_start = __va(r6);
+		initrd_end = __va(r6 + r7);
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+#endif
+
+	ppc_md.ppc_machine = _machine;
+
+	ppc_md.setup_arch     = chrp_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
+	if(naca->interrupt_controller == IC_OPEN_PIC) {
+		ppc_md.init_IRQ       = openpic_init_IRQ; 
+		ppc_md.get_irq        = openpic_get_irq;
+		ppc_md.post_irq	      = NULL;
+	} else {
+		ppc_md.init_IRQ       = xics_init_IRQ;
+		ppc_md.get_irq        = xics_get_irq;
+		ppc_md.post_irq	      = NULL;
+	}
+	ppc_md.init_ras_IRQ = init_ras_IRQ;
+
+ 	#ifndef CONFIG_PPC_ISERIES
+ 		ppc_md.pcibios_fixup = pSeries_pcibios_fixup;
+ 	#else 
+ 		ppc_md.pcibios_fixup = NULL;
+ 		// ppc_md.pcibios_fixup = iSeries_pcibios_fixup;
+ 	#endif
+
+
+	ppc_md.init           = chrp_init2;
+
+	ppc_md.restart        = rtas_restart;
+	ppc_md.power_off      = rtas_power_off;
+	ppc_md.halt           = rtas_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.get_boot_time  = pSeries_get_rtc_time;
+	ppc_md.get_rtc_time   = pSeries_get_rtc_time;
+	ppc_md.set_rtc_time   = pSeries_set_rtc_time;
+	ppc_md.calibrate_decr = pSeries_calibrate_decr;
+
+	ppc_md.progress = chrp_progress;
+
+#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.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x63;	/* Print Screen */
+#endif
+#endif
+	
+	ppc_md.progress("Linux ppc64\n", 0x0);
+}
+
+void __chrp
+chrp_progress(char *s, unsigned short hex)
+{
+	struct device_node *root;
+	int width, *p;
+	char *os;
+	static int display_character, set_indicator;
+	static int max_width;
+
+	if (hex)
+		udbg_printf("<chrp_progress> %s\n", s);
+
+	if (!rtas.base || (_machine != _MACH_pSeries))
+		return;
+
+	if (max_width == 0) {
+		if ( (root = find_path_device("/rtas")) &&
+		     (p = (unsigned int *)get_property(root,
+						       "ibm,display-line-length",
+						       NULL)) )
+			max_width = *p;
+		else
+			max_width = 0x10;
+		display_character = rtas_token("display-character");
+		set_indicator = rtas_token("set-indicator");
+	}
+	if (display_character == RTAS_UNKNOWN_SERVICE) {
+		/* use hex display */
+		if (set_indicator == RTAS_UNKNOWN_SERVICE)
+			return;
+		rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex);
+		return;
+	}
+
+	rtas_call(display_character, 1, 1, NULL, '\r');
+
+	width = max_width;
+	os = s;
+	while ( *os )
+	{
+		if ( (*os == '\n') || (*os == '\r') )
+			width = max_width;
+		else
+			width--;
+		rtas_call(display_character, 1, 1, NULL, *os++ );
+		/* if we overwrite the screen length */
+		if ( width == 0 )
+			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
+				os++;
+	}
+
+	/* Blank to end of line. */
+	while ( width-- > 0 )
+		rtas_call(display_character, 1, 1, NULL, ' ' );
+}
+
+extern void setup_default_decr(void);
+
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
+
+void __init pSeries_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	struct div_result divres;
+	int *fp;
+	unsigned long freq, processor_freq;
+
+	/*
+	 * The cpu node should have a timebase-frequency property
+	 * to tell us the rate at which the decrementer counts. 
+	 */
+	freq = 16666000;        /* hardcoded default */
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) { 
+		fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+		if (fp != 0)
+			freq = *fp;
+	}
+	ppc_tb_freq = freq;
+	processor_freq = freq;
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			processor_freq = *fp;
+	}
+	ppc_proc_freq = processor_freq;
+	
+        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", 
+	       freq/1000000, freq%1000000 );
+	printk("time_init: processor frequency   = %lu.%.6lu MHz\n",
+		processor_freq/1000000, processor_freq%1000000 );
+
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
+	tb_ticks_per_usec = freq / 1000000;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
+	tb_to_xs = divres.result_low;
+
+	setup_default_decr();
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/eeh.c linux-2.4.19-pre5/arch/ppc64/kernel/eeh.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/eeh.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/eeh.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,313 @@
+/*
+ * eeh.c
+ * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Change Activity:
+ * 2001/10/27 : engebret : Created.
+ * End Change Activity 
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/bootmem.h>
+#include <asm/Paca.h>
+#include <asm/processor.h>
+#include <asm/Naca.h>
+#include <asm/io.h>
+#include "pci.h"
+
+#define BUID_HI(buid) ((buid) >> 32)
+#define BUID_LO(buid) ((buid) & 0xffffffff)
+#define CONFIG_ADDR(busno, devfn) (((((busno) & 0xff) << 8) | ((devfn) & 0xf8)) << 8)
+
+unsigned long eeh_total_mmio_reads;
+unsigned long eeh_total_mmio_ffs;
+unsigned long eeh_false_positives;
+/* RTAS tokens */
+static int ibm_set_eeh_option;
+static int ibm_set_slot_reset;
+static int ibm_read_slot_reset_state;
+
+static int eeh_implemented;
+#define EEH_MAX_OPTS 4096
+static char *eeh_opts;
+static int eeh_opts_last;
+static int eeh_check_opts_config(struct pci_dev *dev);
+
+
+unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset)
+{
+	if (phb > 0xff)
+		panic("eeh_token: phb 0x%lx is too large\n", phb);
+	if (offset & 0x0fffffff00000000)
+		panic("eeh_token: offset 0x%lx is out of range\n", offset);
+	return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff));
+}
+
+
+
+int eeh_get_state(unsigned long ea) {
+	return 0;
+}
+
+
+/* Check for an eeh failure at the given token address.
+ * The given value has been read and it should be 1's (0xff, 0xffff or 0xffffffff).
+ *
+ * Probe to determine if an error actually occurred.  If not return val.
+ * Otherwise panic.
+ */
+unsigned long eeh_check_failure(void *token, unsigned long val)
+{
+	unsigned long config_addr = (unsigned long)token >> 24;	/* PPBBDDRR */
+	unsigned long phbidx = (config_addr >> 24) & 0xff;
+	struct pci_controller *phb;
+	unsigned long ret, rets[2];
+
+	config_addr &= 0xffff00;  /* 00BBDD00 */
+
+	if (phbidx >= global_phb_number) {
+		panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1);
+	}
+	phb = phbtab[phbidx];
+	eeh_false_positives++;
+
+	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+			config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid));
+	if (ret == 0 && rets[1] == 1 && rets[2] != 0) {
+		struct pci_dev *dev;
+		int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */
+		int devfn = (config_addr >> 8) & 0xff;
+
+		dev = pci_find_slot(bus, devfn);
+		if (dev)
+			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
+			      rets[2], dev->slot_name, dev->name);
+		else
+			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[2], phb->buid, config_addr);
+	}
+	return val;	/* good case */
+}
+
+void eeh_init(void) {
+	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
+	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
+	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
+	if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE) {
+		printk("PCI Enhanced I/O Error Handling Enabled\n");
+		eeh_implemented = 1;
+	}
+}
+
+
+/* Given a PCI device check if eeh should be configured or not.
+ * This may look at firmware properties and/or kernel cmdline options.
+ */
+int is_eeh_configured(struct pci_dev *dev)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
+	unsigned long ret, rets[2];
+
+	if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
+		return 0;
+
+	/* Hack: turn off eeh for display class devices.
+	 * This fixes matrox accel framebuffer.
+	 */
+	if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
+		return 0;
+
+	if (!eeh_check_opts_config(dev))
+		return 0;
+
+	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+			CONFIG_ADDR(dn->busno, dn->devfn),
+			BUID_HI(phb->buid), BUID_LO(phb->buid));
+	if (ret == 0 && rets[1] == 1) {
+		printk("EEH: %s %s is EEH capable.\n", dev->slot_name, dev->name);
+		return 1;
+	}
+	return 0;
+}
+
+int eeh_set_option(struct pci_dev *dev, int option)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
+
+	if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
+		return -2;
+
+	return rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+			 CONFIG_ADDR(dn->busno, dn->devfn),
+			 BUID_HI(phb->buid), BUID_LO(phb->buid), option);
+}
+
+
+static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
+			 int count, int *eof, void *data)
+{
+	int len;
+	len = sprintf(page, "eeh_false_positives=%ld\n"
+		      "eeh_total_mmio_ffs=%ld\n"
+		      "eeh_total_mmio_reads=%ld\n",
+		      eeh_false_positives, eeh_total_mmio_ffs, eeh_total_mmio_reads);
+	return len;
+}
+
+/* Implementation of /proc/ppc64/eeh
+ * For now it is one file showing false positives.
+ */
+void eeh_init_proc(struct proc_dir_entry *top)
+{
+	struct proc_dir_entry *ent = create_proc_entry("eeh", S_IRUGO, top);
+	if (ent) {
+		ent->nlink = 1;
+		ent->data = NULL;
+		ent->read_proc = (void *)eeh_proc_falsepositive_read;
+	}
+}
+
+/*
+ * Test if "dev" should be configured on or off.
+ * This processes the options literally from right to left.
+ * This lets the user specify stupid combinations of options,
+ * but at least the result should be very predictable.
+ */
+static int eeh_check_opts_config(struct pci_dev *dev)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
+	char devname[32], classname[32], phbname[32];
+	char *strs[8], *s;
+	int nstrs, i;
+	int ret = 0;
+
+	if (dn == NULL || phb == NULL || phb->buid == 0 || !eeh_implemented)
+		return 0;
+	/* Build list of strings to match */
+	nstrs = 0;
+	s = (char *)get_property(dn, "ibm,loc-code", 0);
+	if (s)
+		strs[nstrs++] = s;
+	sprintf(devname, "dev%04x:%04x", dev->vendor, dev->device);
+	strs[nstrs++] = devname;
+	sprintf(classname, "class%04x", dev->class);
+	strs[nstrs++] = classname;
+	sprintf(phbname, "pci@%lx", phb->buid);
+	strs[nstrs++] = phbname;
+	strs[nstrs++] = "";	/* yes, this matches the empty string */
+
+	/* Now see if any string matches the eeh_opts list.
+	 * The eeh_opts list entries start with + or -.
+	 */
+	for (s = eeh_opts; s && (s < (eeh_opts + eeh_opts_last)); s += strlen(s)+1) {
+		for (i = 0; i < nstrs; i++) {
+			if (strcasecmp(strs[i], s+1) == 0) {
+				ret = (strs[0] == '+') ? 1 : 0;
+			}
+		}
+	}
+	return ret;
+}
+
+/* Handle kernel eeh-on & eeh-off cmd line options for eeh.
+ *
+ * We support:
+ *	eeh-off=loc1,loc2,loc3...
+ *
+ * and this option can be repeated so
+ *      eeh-off=loc1,loc2 eeh=loc3
+ * is the same as eeh-off=loc1,loc2,loc3
+ *
+ * loc is an IBM location code that can be found in a manual or
+ * via openfirmware (or the Hardware Management Console).
+ *
+ * We also support these additional "loc" values:
+ *
+ *	dev#:#    vendor:device id in hex (e.g. dev1022:2000)
+ *	class#    class id in hex (e.g. class0200)
+ *	pci@buid  all devices under phb (e.g. pci@fef00000)
+ *
+ * If no location code is specified all devices are assumed
+ * so eeh-off means eeh by default is off.
+ */
+
+/* This is implemented as a null separated list of strings.
+ * Each string looks like this:  "+X" or "-X"
+ * where X is a loc code, dev, class or pci string (as shown above)
+ * or empty which is used to indicate all.
+ *
+ * We interpret this option string list during the buswalk
+ * so that it will literally behave left-to-right even if
+ * some combinations don't make sense.  Give the user exactly
+ * what they want! :)
+ */
+
+static int __init eeh_parm(char *str, int state)
+{
+	char *s, *cur, *curend;
+	if (!eeh_opts) {
+		eeh_opts = alloc_bootmem(EEH_MAX_OPTS);
+		eeh_opts[eeh_opts_last++] = '+'; /* default */
+		eeh_opts[eeh_opts_last++] = '\0';
+	}
+	if (*str == '\0') {
+		eeh_opts[eeh_opts_last++] = state ? '+' : '-';
+		eeh_opts[eeh_opts_last++] = '\0';
+		return 1;
+	}
+	if (*str == '=')
+		str++;
+	for (s = str; s && *s != '\0'; s = curend) {
+		cur = s;
+		while (*cur == ',')
+			cur++;	/* ignore empties.  Don't treat as "all-on" or "all-off" */
+		curend = strchr(cur, ',');
+		if (!curend)
+			curend = cur + strlen(cur);
+		if (*cur) {
+			int curlen = curend-cur;
+			char *sym = eeh_opts+eeh_opts_last;
+			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
+				printk("EEH: sorry...too many eeh cmd line options\n");
+				return 1;
+			}
+			eeh_opts[eeh_opts_last++] = state ? '+' : '-';
+			strncpy(eeh_opts+eeh_opts_last, cur, curlen);
+			eeh_opts_last += curlen;
+			eeh_opts[eeh_opts_last++] = '\0';
+		}
+	}
+	return 1;
+}
+
+static int __init eehoff_parm(char *str)
+{
+	return eeh_parm(str, 0);
+}
+static int __init eehon_parm(char *str)
+{
+	return eeh_parm(str, 1);
+}
+
+
+__setup("eeh-off", eehoff_parm);
+__setup("eeh-on", eehon_parm);
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/entry.S linux-2.4.19-pre5/arch/ppc64/kernel/entry.S
--- linux-2.4.19-pre4/arch/ppc64/kernel/entry.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/entry.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,616 @@
+/*
+ *  arch/ppc/kernel/entry.S
+ *
+ *  
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ *
+ *  This file contains the system call entry code, context switch
+ *  code, and exception/interrupt return code for PowerPC.
+ *
+ *  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 "ppc_asm.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <linux/errno.h>
+#include <linux/sys.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_PPC_ISERIES
+#define DO_SOFT_DISABLE
+#endif
+
+#undef SHOW_SYSCALLS
+#undef SHOW_SYSCALLS_TASK
+
+#ifdef SHOW_SYSCALLS_TASK
+	.data
+show_syscalls_task:
+	.long	-1
+#endif
+
+/*
+ * Handle a system call.
+ */
+	.text
+_GLOBAL(DoSyscall)
+	std	r0,THREAD+LAST_SYSCALL(r13)
+	ld	r11,_CCR(r1)	/* Clear SO bit in CR */
+	lis	r10,0x1000
+	andc	r11,r11,r10
+	std	r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+	LOADBASE(r31,show_syscalls_task)
+	ld	r31,show_syscalls_task@l(r31)
+	cmp	0,r13,r31
+	bne	1f
+#endif
+	LOADADDR(r3,7f)
+	ld	r4,GPR0(r1)
+	ld	r5,GPR3(r1)
+	ld	r6,GPR4(r1)
+	ld	r7,GPR5(r1)
+	ld	r8,GPR6(r1)
+	ld	r9,GPR7(r1)
+	bl	.printk
+	LOADADDR(r3,77f)
+	ld	r4,GPR8(r1)
+	ld	r5,GPR9(r1)
+	mr	r6,r13
+	bl	.printk
+	ld	r0,GPR0(r1)
+	ld	r3,GPR3(r1)
+	ld	r4,GPR4(r1)
+	ld	r5,GPR5(r1)
+	ld	r6,GPR6(r1)
+	ld	r7,GPR7(r1)
+	ld	r8,GPR8(r1)
+1:
+#endif /* SHOW_SYSCALLS */
+	ld	r10,TASK_PTRACE(r13)
+	andi.	r10,r10,PT_TRACESYS
+	bne-	50f
+	cmpli	0,r0,NR_syscalls
+	bge-	66f
+/* Ken Aaker: Need to vector to 32 Bit or default sys_call_table here,
+ *            based on caller's run-mode / personality.
+ *
+ */
+#ifdef CONFIG_BINFMT_ELF32
+	ld	r10,THREAD+THREAD_FLAGS(r13)
+	andi.	r10,r10,PPC_FLAG_32BIT
+	beq-	15f
+	LOADADDR(r10,.sys_call_table32)
+/* Now mung the first 4 parameters into shape, by making certain that
+ * the high bits (most significant 32 bits in 64 bit reg) are 0
+ * for the first 4 parameter regs(3-6).
+ */
+	clrldi	r3,r3,32
+	clrldi	r4,r4,32
+	clrldi	r5,r5,32
+	clrldi	r6,r6,32
+	b	17f
+15:
+#endif
+	LOADADDR(r10,.sys_call_table)
+17:
+	slwi	r0,r0,3
+	ldx	r10,r10,r0	/* Fetch system call handler [ptr] */
+	mtlr	r10
+	addi	r9,r1,STACK_FRAME_OVERHEAD
+	blrl			/* Call handler */
+_GLOBAL(ret_from_syscall_1)
+20:	std	r3,RESULT(r1)	/* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+	cmp	0,r13,r31
+	bne	91f
+#endif
+	mr	r4,r3
+	LOADADDR(r3,79f)
+	bl	.printk
+	ld	r3,RESULT(r1)
+91:
+#endif
+	li	r10,-_LAST_ERRNO
+	cmpl	0,r3,r10
+	blt	30f
+	neg	r3,r3
+	cmpi	0,r3,ERESTARTNOHAND
+	bne	22f
+	li	r3,EINTR
+22:	ld	r10,_CCR(r1)	/* Set SO bit in CR */
+	oris	r10,r10,0x1000
+	std	r10,_CCR(r1)
+30:	std	r3,GPR3(r1)	/* Update return value */
+	b	.ret_from_except
+66:	li	r3,ENOSYS
+	b	22b
+        
+/* Traced system call support */
+50:	bl	.syscall_trace
+	ld	r0,GPR0(r1)	/* Restore original registers */
+	ld	r3,GPR3(r1)
+	ld	r4,GPR4(r1)
+	ld	r5,GPR5(r1)
+	ld	r6,GPR6(r1)
+	ld	r7,GPR7(r1)
+	ld	r8,GPR8(r1)
+	ld	r9,GPR9(r1)
+	cmpli	0,r0,NR_syscalls
+	bge-	66f
+#ifdef CONFIG_BINFMT_ELF32
+	ld	r10,THREAD+THREAD_FLAGS(r13)
+	andi.	r10,r10,PPC_FLAG_32BIT
+	beq-	55f
+	LOADADDR(r10,.sys_call_table32)
+/* Now mung the first 4 parameters into shape, by making certain that
+ * the high bits (most significant 32 bits in 64 bit reg) are 0
+ * for the first 4 parameter regs(3-6).
+ */
+	clrldi	r3,r3,32
+	clrldi	r4,r4,32
+	clrldi	r5,r5,32
+	clrldi	r6,r6,32
+	b	57f
+55:
+#endif
+	LOADADDR(r10,.sys_call_table)
+57:
+	slwi	r0,r0,3
+	ldx	r10,r10,r0	/* Fetch system call handler [ptr] */
+	mtlr	r10
+	addi	r9,r1,STACK_FRAME_OVERHEAD
+	blrl			/* Call handler */
+_GLOBAL(ret_from_syscall_2)
+58:	std	r3,RESULT(r1)	/* Save result */	
+	std	r3,GPR0(r1)	/* temporary gross hack to make strace work */
+	li	r10,-_LAST_ERRNO
+	cmpl	0,r3,r10
+	blt	60f
+	neg	r3,r3
+	cmpi	0,r3,ERESTARTNOHAND
+	bne	57f
+	li	r3,EINTR
+57:	ld	r10,_CCR(r1)	/* Set SO bit in CR */
+	oris	r10,r10,0x1000
+	std	r10,_CCR(r1)
+60:	std	r3,GPR3(r1)	/* Update return value */
+	bl	.syscall_trace
+	b	.ret_from_except
+66:	li	r3,ENOSYS
+	b	57b
+#ifdef SHOW_SYSCALLS
+7:	.string	"syscall %d(%x, %x, %x, %x, %x, "
+77:	.string	"%x, %x), current=%p\n"
+79:	.string	" -> %x\n"
+	.align	2,0
+#endif
+
+_GLOBAL(ppc32_sigreturn)
+	bl	.sys32_sigreturn
+	b	80f
+
+_GLOBAL(ppc32_rt_sigreturn)
+	bl	.sys32_rt_sigreturn
+	b	80f
+
+_GLOBAL(ppc64_sigreturn)
+	bl	.sys_sigreturn
+	b	80f
+
+_GLOBAL(ppc64_rt_sigreturn)
+	bl	.sys_rt_sigreturn
+
+80:	ld	r10,TASK_PTRACE(r13)
+	andi.	r10,r10,PT_TRACESYS
+	bne-	81f
+	cmpi	0,r3,0
+	bge	.ret_from_except
+	b	20b
+81:	cmpi	0,r3,0
+	blt	58b
+	bl	.syscall_trace
+	b	.ret_from_except
+
+/*
+ * This routine switches between two different tasks.  The process
+ * state of one is saved on its kernel stack.  Then the state
+ * of the other is restored from its kernel stack.  The memory
+ * management hardware is updated to the second process's state.
+ * Finally, we can return to the second process, via ret_from_except.
+ * On entry, r3 points to the THREAD for the current task, r4
+ * points to the THREAD for the new task.
+ *
+ * Note: there are two ways to get to the "going out" portion
+ * of this code; either by coming in via the entry (_switch)
+ * or via "fork" which must set up an environment equivalent
+ * to the "_switch" path.  If you change this (or in particular, the
+ * SAVE_REGS macro), you'll have to change the fork code also.
+ *
+ * The code which creates the new task context is in 'copy_thread'
+ * in arch/ppc/kernel/process.c
+ */	
+_GLOBAL(_switch)
+	stdu	r1,-INT_FRAME_SIZE(r1)
+	ld	r6,0(r1)
+	std	r6,GPR1(r1)
+	/* r3-r13 are caller saved -- Cort */
+	SAVE_GPR(2, r1)
+	SAVE_8GPRS(14, r1)
+	SAVE_10GPRS(22, r1)
+	mflr	r20		/* Return to switch caller */
+	mfmsr	r22
+	li	r6,MSR_FP	/* Disable floating-point */
+	andc	r22,r22,r6
+	mtmsrd	r22
+	isync
+	std	r20,_NIP(r1)
+	std	r22,_MSR(r1)
+	std	r20,_LINK(r1)
+	mfcr	r20
+	std	r20,_CCR(r1)
+	li	r6,0x0ff0
+	std	r6,TRAP(r1)
+	std	r1,KSP(r3)	/* Set old stack pointer */
+
+	mfspr	r5,SPRG3	/* Get Paca */
+	addi	r3,r3,-THREAD	/* old 'current' for return value */
+	addi	r13,r4,-THREAD	/* Convert THREAD to 'current' */
+	std	r13,PACACURRENT(r5)	/* Set new 'current' */
+
+#ifdef CONFIG_PPC_ISERIES
+	ld	r7,THREAD_FLAGS(r4)	/* Get run light flag */
+	mfspr	r9,CTRLF
+	srdi	r7,r7,1		/* Align to run light bit in CTRL reg */
+	insrdi	r9,r7,1,63	/* Insert run light into CTRL */
+	mtspr	CTRLT,r9
+#endif
+	ld	r1,KSP(r4)	/* Load new stack pointer */
+	ld	r6,_CCR(r1)
+	mtcrf	0xFF,r6
+	/* r3-r13 are destroyed -- Cort */
+	REST_8GPRS(14, r1)
+	REST_10GPRS(22, r1)
+
+	ld	r7,_NIP(r1)	/* Return to _switch caller in new task */
+	ld	r1,GPR1(r1)
+	mtlr	r7
+	blr
+
+_GLOBAL(ret_from_fork)
+	bl	.schedule_tail
+	ld	r0,TASK_PTRACE(r13)
+	andi.	r0,r0,PT_TRACESYS
+	beq+	.ret_from_except
+	bl	.syscall_trace
+	b	.ret_from_except
+
+_GLOBAL(ret_from_except)
+#ifdef CONFIG_PPC_ISERIES
+	ld	r5,SOFTE(r1)
+	cmpdi	0,r5,0
+	beq	4f
+irq_recheck:
+	/*
+	 * Check for pending interrupts (iSeries)
+	 */
+	CHECKANYINT(r3,r4)
+	beq+	4f	/* skip do_IRQ if no interrupts */
+
+	mfspr	r5,SPRG3
+	li	r3,0
+	stb	r3,PACAPROCENABLED(r5)	/* ensure we are disabled */
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.do_IRQ
+	b	irq_recheck	/* loop back and handle more */
+4:
+#endif
+_GLOBAL(do_bottom_half_ret)
+	ld	r3,_MSR(r1)	/* Returning to user mode? */
+	andi.	r3,r3,MSR_PR
+	beq+	restore		/* if so, check need_resched and signals */
+_GLOBAL(ret_to_user_hook)
+	nop
+	/* NEED_RESCHED is a volatile long (64-bits) */ 
+	ld	r3,NEED_RESCHED(r13)
+	cmpi	0,r3,0		/* check need_resched flag */
+	beq+	7f
+	bl	.schedule
+	/* SIGPENDING is an int (32-bits) */
+7:	
+	lwz	r5,SIGPENDING(r13) /* Check for pending unblocked signals */
+	cmpwi	0,r5,0
+	beq+	restore
+	li	r3,0
+	addi	r4,r1,STACK_FRAME_OVERHEAD
+	bl	.do_signal
+_GLOBAL(do_signal_ret)
+restore:	
+	ld	r3,_CTR(r1)
+	ld	r0,_LINK(r1)
+	mtctr	r3
+	mtlr	r0
+	ld	r3,_XER(r1)
+	mtspr	XER,r3
+	REST_8GPRS(5, r1)
+	REST_10GPRS(14, r1)
+	REST_8GPRS(24, r1)
+	
+	/* make sure we hard disable here, even if rtl is active, to protect
+	 * SRR[01] and SPRG2 -- Cort 
+	 */
+	mfmsr	r0		/* Get current interrupt state */
+	li	r4,0
+	ori	r4,r4,MSR_EE|MSR_RI
+	andc	r0,r0,r4	/* clear MSR_EE and MSR_RI */
+	mtmsrd	r0		/* Update machine state */
+#ifdef CONFIG_PPC_ISERIES
+	ld	r0,SOFTE(r1)
+	cmpi	0,r0,0
+	beq+	1f
+
+	CHECKANYINT(r4,r3)
+	beq+	1f
+	mfmsr	r0
+	ori	r0,r0,MSR_EE|MSR_RI
+	mtmsrd	r0
+	b	irq_recheck
+	
+1:	
+#endif
+	stdcx.	r0,0,r1		/* to clear the reservation */
+
+	mfspr	r4,SPRG3	/* current task's PACA */
+#ifdef DO_SOFT_DISABLE
+	ld	r0,SOFTE(r1)
+	stb	r0,PACAPROCENABLED(r4)
+#endif
+	/* if returning to user mode, save kernel SP */
+	ld	r0,_MSR(r1)
+	andi.	r0,r0,MSR_PR
+	beq+	1f
+	addi	r0,r1,INT_FRAME_SIZE	/* size of frame */
+	std	r0,THREAD+KSP(r13)	/* save kernel stack pointer */
+	std	r1,PACAKSAVE(r4)	/* save exception stack pointer */
+1:
+	ld	r0,_MSR(r1)
+	mtspr	SRR1,r0
+	ld	r2,_CCR(r1)
+	mtcrf	0xFF,r2
+	ld	r2,_NIP(r1)
+	mtspr	SRR0,r2
+	REST_GPR(13,r1)
+	ld	r0,GPR0(r1)
+	ld	r2,GPR2(r1)
+	ld	r3,GPR3(r1)
+	ld	r4,GPR4(r1)
+	ld	r1,GPR1(r1)
+
+	rfid
+
+/*
+ * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
+ * called with the MMU off.
+ *
+ * In addition, we need to be in 32b mode, at least for now.
+ * 
+ * Note: r3 is an input parameter to rtas, so don't trash it...
+ */
+_GLOBAL(enter_rtas)
+	mflr	r0
+	std	r0,16(r1)
+        stdu	r1,-RTAS_FRAME_SIZE(r1)	/* Save SP and create stack space. */
+
+	/* Because RTAS is running in 32b mode, it clobbers the high order half
+	 * of all registers that it saves.  We therefore save those registers
+	 * RTAS might touch to the stack.  (r0, r3-r13 are caller saved)
+   	 */
+	SAVE_GPR(2, r1)			/* Save the TOC */
+	SAVE_GPR(13, r1)		/* Save current */
+	SAVE_8GPRS(14, r1)		/* Save the non-volatiles */
+	SAVE_10GPRS(22, r1)		/* ditto */
+
+	mfcr	r4
+	std	r4,_CCR(r1)
+	mfctr	r5
+	std	r5,_CTR(r1)
+	mfspr	r6,XER
+	std	r6,_XER(r1)
+	mfdar	r7
+	std	r7,_DAR(r1)
+	mfdsisr	r8
+	std	r8,_DSISR(r1)
+	mfsrr0	r9
+	std	r9,_SRR0(r1)
+	mfsrr1	r10
+	std	r10,_SRR1(r1)
+
+	/* Unfortunatly, the stack pointer and the MSR are also clobbered,
+	 * so they are saved in the PACA (SPRG3) which allows us to restore
+	 * our original state after RTAS returns.
+         */
+	mfspr	r4,SPRG3		/* Get PACA */
+	std	r1,PACAR1(r4)
+	mfmsr	r6
+        std	r6,PACASAVEDMSR(r4)
+
+	/* Setup our real return addr */	
+	SET_REG_TO_LABEL(r4,.rtas_return_loc)
+	SET_REG_TO_CONST(r9,KERNELBASE)
+	sub	r4,r4,r9
+       	mtlr	r4
+
+	li	r0,0
+	ori	r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_RI
+	andc	r0,r6,r0
+	
+        li      r9,1
+        rldicr  r9,r9,MSR_SF_LG,(63-MSR_SF_LG)
+	ori	r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP|MSR_RI
+	andc	r6,r0,r9
+	sync				/* disable interrupts so SRR0/1 */
+	mtmsrd	r0			/* don't get trashed */
+
+	SET_REG_TO_LABEL(r4,rtas)
+	ld	r5,RTASENTRY(r4)	/* get the rtas->entry value */
+	ld	r4,RTASBASE(r4)		/* get the rtas->base value */
+	
+	mtspr	SRR0,r5
+	mtspr	SRR1,r6
+	rfid
+
+_STATIC(rtas_return_loc)
+	/* relocation is off at this point */
+	mfspr	r4,SPRG3	        /* Get PACA */
+	SET_REG_TO_CONST(r5, KERNELBASE)
+        sub     r4,r4,r5                /* RELOC the PACA base pointer */
+        
+        ld	r1,PACAR1(r4)           /* Restore our SP */
+	LOADADDR(r3,.rtas_restore_regs)
+        ld	r4,PACASAVEDMSR(r4)     /* Restore our MSR */
+
+	mtspr	SRR0,r3
+	mtspr	SRR1,r4
+	rfid
+
+_STATIC(rtas_restore_regs)
+	/* relocation is on at this point */
+	REST_GPR(2, r1)			/* Restore the TOC */
+	REST_GPR(13, r1)		/* Restore current */
+	REST_8GPRS(14, r1)		/* Restore the non-volatiles */
+	REST_10GPRS(22, r1)		/* ditto */
+
+	/* put back current in r13 */
+        mfspr	r4,SPRG3
+	ld	r13,PACACURRENT(r4)
+
+	ld	r4,_CCR(r1)
+	mtcr	r4
+	ld	r5,_CTR(r1)
+	mtctr	r5
+	ld	r6,_XER(r1)
+	mtspr	XER,r6
+	ld	r7,_DAR(r1)
+	mtdar	r7
+	ld	r8,_DSISR(r1)
+	mtdsisr	r8
+	ld	r9,_SRR0(r1)
+	mtsrr0	r9
+	ld	r10,_SRR1(r1)
+	mtsrr1	r10
+
+        addi	r1,r1,RTAS_FRAME_SIZE	/* Unstack our frame */
+	ld	r0,16(r1)		/* get return address */
+
+	mtlr    r0
+        blr				/* return to caller */
+
+
+_GLOBAL(enter_prom)
+	mflr	r0
+	std	r0,16(r1)
+        stdu	r1,-PROM_FRAME_SIZE(r1)	/* Save SP and create stack space */
+
+	/* Because PROM is running in 32b mode, it clobbers the high order half
+	 * of all registers that it saves.  We therefore save those registers
+	 * PROM might touch to the stack.  (r0, r3-r13 are caller saved)
+   	 */
+	SAVE_8GPRS(2, r1)		/* Save the TOC & incoming param(s) */
+	SAVE_GPR(13, r1)		/* Save current */
+	SAVE_8GPRS(14, r1)		/* Save the non-volatiles */
+	SAVE_10GPRS(22, r1)		/* ditto */
+
+	mfcr	r4
+	std	r4,_CCR(r1)
+	mfctr	r5
+	std	r5,_CTR(r1)
+	mfspr	r6,XER
+	std	r6,_XER(r1)
+	mfdar	r7
+	std	r7,_DAR(r1)
+	mfdsisr	r8
+	std	r8,_DSISR(r1)
+	mfsrr0	r9
+	std	r9,_SRR0(r1)
+	mfsrr1	r10
+	std	r10,_SRR1(r1)
+	mfmsr	r11
+	std	r11,_MSR(r1)
+
+	/* Unfortunatly, the stack pointer is also clobbered, so it is saved
+	 * in the SPRG2 which allows us to restore our original state after
+	 * PROM returns.
+         */
+	mtspr	SPRG2,r1
+
+        /* put a relocation offset into r3 */
+        bl      .reloc_offset
+	LOADADDR(r12,prom)
+	sub	r12,r12,r3
+	ld	r12,PROMENTRY(r12)	/* get the prom->entry value */
+	mtlr	r12
+
+        mfmsr   r11			/* grab the current MSR */
+        li      r12,1
+        rldicr  r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
+        andc    r11,r11,r12
+        li      r12,1
+        rldicr  r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
+        andc    r11,r11,r12
+        mtmsrd  r11
+        isync
+
+	REST_8GPRS(2, r1)		/* Restore the TOC & param(s) */
+	REST_GPR(13, r1)		/* Restore current */
+	REST_8GPRS(14, r1)		/* Restore the non-volatiles */
+	REST_10GPRS(22, r1)		/* ditto */
+	blrl				/* Entering PROM here... */
+
+	mfspr	r1,SPRG2		/* Restore the stack pointer */
+	ld	r6,_MSR(r1)		/* Restore the MSR */
+	mtmsrd	r6
+        isync
+
+	REST_GPR(2, r1)			/* Restore the TOC */
+	REST_GPR(13, r1)		/* Restore current */
+	REST_8GPRS(14, r1)		/* Restore the non-volatiles */
+	REST_10GPRS(22, r1)		/* ditto */
+
+	ld	r4,_CCR(r1)
+	mtcr	r4
+	ld	r5,_CTR(r1)
+	mtctr	r5
+	ld	r6,_XER(r1)
+	mtspr	XER,r6
+	ld	r7,_DAR(r1)
+	mtdar	r7
+	ld	r8,_DSISR(r1)
+	mtdsisr	r8
+	ld	r9,_SRR0(r1)
+	mtsrr0	r9
+	ld	r10,_SRR1(r1)
+	mtsrr1	r10
+        addi	r1,r1,PROM_FRAME_SIZE
+	ld	r0,16(r1)		/* get return address */
+
+	mtlr    r0
+        blr				/* return to caller */
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/flight_recorder.c linux-2.4.19-pre5/arch/ppc64/kernel/flight_recorder.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/flight_recorder.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/flight_recorder.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,182 @@
+/************************************************************************
+ * flight_recorder.c
+ ************************************************************************
+ * This code supports the a generic flight recorder.                    *
+ * Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    * 
+ *                                                                      *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or    *
+ * (at your option) any later version.                                  *
+ *                                                                      *
+ * This program is distributed in the hope that it will be useful,      * 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
+ * GNU General Public License for more details.                         *
+ *                                                                      *
+ * You should have received a copy of the GNU General Public License    * 
+ * along with this program; if not, write to the:                       *
+ * Free Software Foundation, Inc.,                                      * 
+ * 59 Temple Place, Suite 330,                                          * 
+ * Boston, MA  02111-1307  USA                                          *
+ ************************************************************************
+ * This is a simple text based flight recorder.  Useful for logging 
+ * information the you may want to retreive at a latter time.  Errors or 
+ * debug inforamtion are good examples.   A good method to dump the 
+ * information is via the proc file system. 
+ *
+ * To use. 
+ * 1. Create the flight recorder object.  Passing a NULL pointer will 
+ *    kmalloc the space for you.  If it is too early for kmalloc, create 
+ *    space for the object.   Beware, don't lie about the size, you will
+ *    pay for that later. 
+ * 		FlightRecorder* TestFr = alloc_Flight_Recorder(NULL,"TestFr",4096);
+ *   
+ * 2. Log any notable events, initialzation, error conditions, etc. 
+ *		LOGFR(TestFr,"5. Stack Variable(10) %d",StackVariable);
+ * 
+ * 3. Dump the information to a buffer. 
+ *		fr_Dump(TestFr, proc_file_buffer, proc_file_buffer_size);
+ *
+ ************************************************************************/
+#include <stdarg.h>
+#include <linux/kernel.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <asm/string.h>
+#include <asm/time.h>
+#include <asm/flight_recorder.h>
+
+static  char       LogText[512];
+static  int        LogTextIndex;
+static  int        LogCount = 0;
+static  spinlock_t Fr_Lock;
+
+/************************************************************************
+ * Build the log time prefix based on Flags.
+ *  00 = No time prefix
+ *  01 = Date(mmddyy) Time(hhmmss) prefix
+ *  02 = Day(dd) Time(hhmmss) prefix
+ *  03 = Time(hhmmss) prefix
+ ************************************************************************/
+static void fr_Log_Time(FlightRecorder* Fr)
+{
+	struct  timeval  TimeClock;
+	struct  rtc_time LogTime;
+
+	do_gettimeofday(&TimeClock);
+	to_tm(TimeClock.tv_sec, &LogTime);
+
+	if (Fr->Flags == 1) {    
+		LogTextIndex = sprintf(LogText,"%02d%02d%02d %02d%02d%02d ",
+		                       LogTime.tm_mon, LogTime.tm_mday, LogTime.tm_year-2000,
+	     	                  LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec);
+	}
+	else if (Fr->Flags == 2) {    
+		LogTextIndex = sprintf(LogText,"%02d %02d%02d%02d ",
+		                       LogTime.tm_mday,
+	     	                  LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec);
+	}
+
+	else if (Fr->Flags == 3) {    
+		LogTextIndex = sprintf(LogText,"%02d%02d%02d ",
+	     	                  LogTime.tm_hour,LogTime.tm_min, LogTime.tm_sec);
+	}
+	else {
+		++LogCount;
+		LogTextIndex = sprintf(LogText,"%04d. ",LogCount);
+	}
+}
+
+/************************************************************************/
+/* Log entry into buffer,                                               */
+/* ->If entry is going to wrap, log "WRAP" and start at the top.        */
+/************************************************************************/
+static void fr_Log_Data(FlightRecorder* Fr)
+{
+	int 	TextLen  = strlen(LogText);
+	int 	Residual = ( Fr->EndPointer - Fr->NextPointer)-15;
+	if (TextLen > Residual) {
+		strcpy(Fr->NextPointer,"WRAP");
+		Fr->WrapPointer = Fr->NextPointer + 5;
+		Fr->NextPointer = Fr->StartPointer;
+	}
+	strcpy(Fr->NextPointer,LogText);
+	Fr->NextPointer += TextLen+1;
+	strcpy(Fr->NextPointer,"<=");
+}
+/************************************************************************
+ * Build the log text, support variable args.
+ ************************************************************************/
+void fr_Log_Entry(struct flightRecorder* LogFr, const char *fmt, ...)
+{
+	va_list arg_ptr;
+	spin_lock(&Fr_Lock);
+
+	fr_Log_Time(LogFr); 
+	va_start(arg_ptr, fmt);
+	vsprintf(LogText+LogTextIndex, fmt, arg_ptr);
+	va_end(arg_ptr);
+	fr_Log_Data(LogFr);
+
+	spin_unlock(&Fr_Lock);
+
+}
+/************************************************************************
+ * Dump Flight Recorder into buffer.
+ * -> Handles the buffer wrapping.
+ ************************************************************************/
+int fr_Dump(FlightRecorder* Fr, char *Buffer, int BufferLen)
+{
+	int   LineLen = 0;
+	char* StartEntry;
+	char* EndEntry;
+	spin_lock(&Fr_Lock);
+	/****************************************************************
+	 * If Buffer has wrapped, find last usable entry to start with.
+	 ****************************************************************/
+	if (Fr->WrapPointer != NULL) {
+		StartEntry  = Fr->NextPointer+3;
+		StartEntry += strlen(StartEntry)+1;
+		EndEntry    = Fr->WrapPointer;
+
+		while (EndEntry > StartEntry && LineLen < BufferLen) {
+			LineLen    += sprintf(Buffer+LineLen,"%s\n",StartEntry);
+			StartEntry += strlen(StartEntry) + 1;
+		}
+	}
+
+	/****************************************************************
+	 * Dump from the beginning to the last logged entry
+	 ****************************************************************/
+	StartEntry = Fr->StartPointer;
+	EndEntry   = Fr->NextPointer;
+	while (EndEntry > StartEntry && LineLen < BufferLen) {
+		LineLen    += sprintf(Buffer+LineLen,"%s\n",StartEntry);
+		StartEntry += strlen(StartEntry) + 1;
+	}
+	spin_unlock(&Fr_Lock);
+	return LineLen;
+}
+
+/************************************************************************
+ * Allocate and Initialized the Flight Recorder
+ * -> If no FlightRecorder pointer is passed, the space is kmalloc.
+ ************************************************************************/
+FlightRecorder* alloc_Flight_Recorder(FlightRecorder* FrPtr, char* Signature, int SizeOfFr)
+{
+	FlightRecorder* Fr     = FrPtr;				/* Pointer to Object */
+	int             FrSize = (SizeOfFr/16)*16;	/* Could be static   */
+	if (Fr == NULL)
+		Fr = (FlightRecorder*)kmalloc(SizeOfFr, GFP_KERNEL);
+	memset(Fr,0,SizeOfFr);
+	strcpy(Fr->Signature,Signature);
+	Fr->Size         = FrSize;
+	Fr->Flags        = 0;
+	Fr->StartPointer = (char*)&Fr->Buffer;
+	Fr->EndPointer   = (char*)Fr + Fr->Size;
+	Fr->NextPointer  = Fr->StartPointer;
+
+	fr_Log_Entry(Fr,"Initialized.");
+	return Fr;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/head.S linux-2.4.19-pre5/arch/ppc64/kernel/head.S
--- linux-2.4.19-pre4/arch/ppc64/kernel/head.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/head.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,1849 @@
+/*
+ *  arch/ppc64/kernel/head.S
+ *
+ *
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
+ *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
+ *
+ *  This file contains the low-level support and setup for the
+ *  PowerPC-64 platform, including trap and interrupt dispatch.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#define SECONDARY_PROCESSORS
+
+#include "ppc_asm.h"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <linux/config.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_PPC_ISERIES
+#define DO_SOFT_DISABLE
+#endif
+
+/*
+ * We layout physical memory as follows:
+ * 0x0000 - 0x00ff : Secondary processor spin code
+ * 0x0100 - 0x2fff : pSeries Interrupt prologs
+ * 0x3000 - 0x3fff : Interrupt support
+ * 0x4000 - 0x4fff : NACA
+ * 0x5000 - 0x5fff : Initial segment table
+ * 0x6000          : iSeries and common interrupt prologs
+ *
+ */
+
+/*
+ *   SPRG Usage
+ *
+ *   Register          Definition
+ *
+ *   SPRG0             reserved for hypervisor
+ *   SPRG1             temp - used to save gpr
+ *   SPRG2             temp - used to save gpr
+ *   SPRG3             virt addr of Paca
+ */
+
+/*
+ * Entering into this code we make the following assumptions:
+ *  For pSeries:
+ *   1. The MMU is off & open firmware is running in real mode.
+ *   2. The kernel is entered at __start
+ *
+ *  For iSeries:
+ *   1. The MMU is on (as it always is for iSeries)
+ *   2. The kernel is entered at SystemReset_Iseries
+ */
+
+	.text
+	.globl  _stext
+_stext:
+_STATIC(__start)
+	b .__start_initialization_pSeries
+
+	/* At offset 0x20, there is a pointer to iSeries LPAR data.
+	 * This is required by the hypervisor */
+	. = 0x20
+	.llong hvReleaseData-KERNELBASE
+
+	/* At offset 0x28 and 0x30 are offsets to the msChunks
+	 * array (used by the iSeries LPAR debugger to do translation
+	 * between physical addresses and absolute addresses) and
+	 * to the pidhash table (also used by the debugger) */
+	.llong msChunks-KERNELBASE
+	.llong pidhash-KERNELBASE
+
+	/* Offset 0x38 - Pointer to start of embedded System.map */
+	.globl	embedded_sysmap_start
+embedded_sysmap_start:
+	.llong	0
+	/* Offset 0x40 - Pointer to end of embedded System.map */
+	.globl	embedded_sysmap_end
+embedded_sysmap_end:
+	.llong	0
+
+	/* Secondary processors spin on this value until it goes to 1. */
+	.globl  __secondary_hold_spinloop
+__secondary_hold_spinloop:
+	.llong  0x0
+
+	/* Secondary processors write this value with their cpu # */
+	/* after they enter the spin loop immediatly below.       */
+	.globl  __secondary_hold_acknowledge
+__secondary_hold_acknowledge:
+	.llong  0x0
+
+	. = 0x60
+/*
+ * The following code is used on pSeries to hold secondary processors
+ * in a spin loop after they have been freed from OpenFirmware, but
+ * before the bulk of the kernel has been relocated.  This code
+ * is relocated to physical address 0x60 before prom_init is run.
+ * All of it must fit below the first exception vector at 0x100.
+ */
+_GLOBAL(__secondary_hold)
+	/* Grab our linux cpu number */
+	mr      r24,r3
+
+	/* Tell the master cpu we're here */
+	/* Relocation is off & we are located at an address less */
+	/* than 0x100, so only need to grab low order offset.    */
+	std     r24,__secondary_hold_acknowledge@l(0)
+
+	/* All secondary cpu's wait here until told to start. */
+100:    ld      r4,__secondary_hold_spinloop@l(0)
+	cmpdi   0,r4,1
+	bne     100b
+
+#ifdef CONFIG_HMT
+	b	.hmt_init
+#else
+#ifdef CONFIG_SMP
+	mr      r3,r24
+	b       .pseries_secondary_smp_init
+#else
+	BUG_OPCODE
+#endif
+#endif
+
+/*
+ * The following macros define the code that appears as
+ * the prologue to each of the exception handlers.  They
+ * are split into two parts to allow a single kernel binary
+ * to be used for pSeries, and iSeries.
+ */
+
+/*
+ * We make as much of the exception code common between native Pseries
+ * and Iseries LPAR implementations as possible.
+ */
+
+/*
+ * This is the start of the interrupt handlers for Pseries
+ * This code runs with relocation off.
+ */
+#define EX_SRR0		0
+#define EX_SRR1		8
+#define EX_R20		16
+#define EX_R21		24
+#define EX_R22		32
+#define EX_R23		40
+#define EX_DAR		48
+#define EX_DSISR	56
+
+#define EXCEPTION_PROLOG_PSERIES(label)                                  \
+	mtspr   SPRG2,r20;              /* use SPRG2 as scratch reg   */ \
+	mtspr   SPRG1,r21;              /* save r21                   */ \
+	mfspr   r20,SPRG3;              /* get Paca virt addr         */ \
+	ld      r21,PACAEXCSP(r20);     /* get exception stack ptr    */ \
+	addi    r21,r21,EXC_FRAME_SIZE; /* make exception frame       */ \
+	std	r22,EX_R22(r21);	/* Save r22 in exc. frame     */ \
+	std	r23,EX_R23(r21);	/* Save r23 in exc. frame     */ \
+	mfspr   r22,SRR0;               /* EA of interrupted instr    */ \
+	std	r22,EX_SRR0(r21);	/* Save SRR0 in exc. frame    */ \
+	mfspr   r23,SRR1;               /* machine state at interrupt */ \
+	std	r23,EX_SRR1(r21);	/* Save SRR1 in exc. frame    */ \
+	clrrdi  r22,r20,60;             /* Get 0xc part of the vaddr  */ \
+	ori	r22,r22,(label)@l;      /* add in the vaddr offset    */ \
+		                        /*   assumes *_common < 16b   */ \
+	mfmsr   r23;                                                     \
+	rotldi  r23,r23,4;                                               \
+	ori     r23,r23,0x30B;          /* Set IR, DR, SF, ISF, HV    */ \
+	rotldi  r23,r23,60;             /* for generic handlers       */ \
+	mtspr   SRR0,r22;                                                \
+	mtspr   SRR1,r23;                                                \
+	mfcr    r23;                    /* save CR in r23             */ \
+	rfid
+
+/*
+ * This is the start of the interrupt handlers for i_series
+ * This code runs with relocation on.
+ */
+#define EXCEPTION_PROLOG_ISERIES	\
+	mtspr	SPRG2,r20;		    /* use SPRG2 as scratch reg */\
+	mtspr   SPRG1,r21;                  /* save r21 */\
+	mfspr	r20,SPRG3;		    /* get Paca */\
+	ld      r21,PACAEXCSP(r20);         /* get exception stack ptr */\
+	addi    r21,r21,EXC_FRAME_SIZE;     /* make exception frame */\
+	std	r22,EX_R22(r21);	    /* save r22 on exception frame */\
+	std	r23,EX_R23(r21);	    /* Save r23 in exc. frame */\
+	ld      r22,LPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\
+	std	r22,EX_SRR0(r21);	    /* save SRR0 in exc. frame */\
+	ld      r23,LPPACA+LPPACASRR1(r20); /* Get SRR1 from ItLpPaca */\
+	std	r23,EX_SRR1(r21);	    /* save SRR1 in exc. frame */\
+	mfcr    r23;                        /* save CR in r23 */
+
+/*
+ * The common exception prolog is used for all except a few exceptions
+ * such as a segment miss on a kernel address.  We have to be prepared
+ * to take another exception from the point where we first touch the
+ * kernel stack onwards.
+ *
+ * On entry r20 points to the paca and r21 points to the exception
+ * frame on entry, r23 contains the saved CR, and relocation is on.
+ */
+#define EXCEPTION_PROLOG_COMMON                                             \
+	mfspr	r22,SPRG2;		/* Save r20 in exc. frame */ \
+	std	r22,EX_R20(r21);	\
+	mfspr	r22,SPRG1;		/* Save r21 in exc. frame */ \
+	std	r22,EX_R21(r21);	\
+	mfspr   r22,DAR;                /* Save DAR in exc. frame        */ \
+	std	r22,EX_DAR(r21);	\
+	std     r21,PACAEXCSP(r20);     /* update exception stack ptr    */ \
+		                        /*   iff no protection flt       */ \
+	mfspr	r22,DSISR;		/* Save DSISR in exc. frame */ \
+	std	r22,EX_DSISR(r21);	\
+	ld	r22,EX_SRR1(r21);	/* Get SRR1 from exc. frame */ \
+	andi.   r22,r22,MSR_PR;         /* Set CR for later branch       */ \
+	mr      r22,r1;                 /* Save r1                       */ \
+	subi    r1,r1,INT_FRAME_SIZE;    /* alloc frame on kernel stack  */ \
+	beq-    1f;                     \
+	ld      r1,PACAKSAVE(r20);      /* kernel stack to use */ \
+1:      std     r22,GPR1(r1);           /* save r1 in stackframe */ \
+	std     r22,0(r1);              /* make stack chain pointer */ \
+	std     r23,_CCR(r1);           /* save CR in stackframe */ \
+	ld	r22,EX_R20(r21);	/* move r20 to stackframe */ \
+	std	r22,GPR20(r1);		\
+	ld	r23,EX_R21(r21);	/* move r21 to stackframe */ \
+	std	r23,GPR21(r1);		\
+	ld	r22,EX_R22(r21);	/* move r22 to stackframe */ \
+	std	r22,GPR22(r1);		\
+	ld	r23,EX_R23(r21);	/* move r23 to stackframe */ \
+	std	r23,GPR23(r1);		\
+	mflr    r22;                    /* save LR in stackframe */ \
+	std     r22,_LINK(r1);          \
+	mfctr   r23;                    /* save CTR in stackframe */ \
+	std     r23,_CTR(r1);           \
+	mfspr   r22,XER;                /* save XER in stackframe */ \
+	std     r22,_XER(r1);           \
+	ld	r23,EX_DAR(r21);	/* move DAR to stackframe */ \
+	std	r23,_DAR(r1);		\
+	ld	r22,EX_DSISR(r21);	/* move DSISR to stackframe */ \
+	std	r22,_DSISR(r1);		\
+	lbz	r22,PACAPROCENABLED(r20); \
+	std	r22,SOFTE(r1);		\
+	ld	r22,EX_SRR0(r21);	/* get SRR0 from exc. frame */ \
+	ld	r23,EX_SRR1(r21);	/* get SRR1 from exc. frame */ \
+	addi    r21,r21,-EXC_FRAME_SIZE;/* pop off exception frame */ \
+	std     r21,PACAEXCSP(r20);     \
+	SAVE_GPR(0, r1);                /* save r0 in stackframe */ \
+	SAVE_8GPRS(2, r1);              /* save r2 - r13 in stackframe */ \
+	SAVE_4GPRS(10, r1);             \
+	ld      r2,PACATOC(r20);	\
+	ld      r13,PACACURRENT(r20)
+
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r1, r22 (SRR0), and r23 (SRR1).
+ */
+
+/*
+ * Exception vectors.
+ */
+#define STD_EXCEPTION_PSERIES(n, label )	\
+	. = n;					\
+	.globl label##_Pseries;			\
+label##_Pseries:				\
+	EXCEPTION_PROLOG_PSERIES( label##_common )
+
+#define STD_EXCEPTION_ISERIES( label )		\
+	.globl label##_Iseries;			\
+label##_Iseries:				\
+	EXCEPTION_PROLOG_ISERIES;		\
+	b	label##_common
+
+#define MASKABLE_EXCEPTION_ISERIES( label )	\
+	.globl label##_Iseries;			\
+label##_Iseries:				\
+	EXCEPTION_PROLOG_ISERIES;		\
+	lbz	r22,PACAPROFENABLED(r20);	\
+	cmpi	0,r22,0;			\
+	bne-	label##_Iseries_profile;	\
+label##_Iseries_prof_ret:			\
+	lbz	r22,PACAPROCENABLED(r20);	\
+	cmpi	0,r22,0;			\
+	beq-	label##_Iseries_masked;		\
+	b	label##_common;			\
+label##_Iseries_profile:			\
+	std	r24,48(r21);			\
+	std	r25,56(r21);			\
+	mflr	r24;				\
+	bl	do_profile;			\
+	mtlr	r24;				\
+	ld	r24,48(r21);			\
+	ld	r25,56(r21);			\
+	b	label##_Iseries_prof_ret
+
+#define STD_EXCEPTION_COMMON( trap, label, hdlr )	\
+	.globl label##_common;			\
+label##_common:					\
+	EXCEPTION_PROLOG_COMMON;		\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;	\
+	li	r20,0;				\
+	li	r6,trap;			\
+	bl      .save_remaining_regs;           \
+	bl      hdlr;                           \
+	b       .ret_from_except
+
+/*
+ * Start of pSeries system interrupt routines
+ */
+	. = 0x100
+	.globl __start_interupts
+__start_interupts:
+
+	STD_EXCEPTION_PSERIES( 0x100, SystemReset )
+	STD_EXCEPTION_PSERIES( 0x200, MachineCheck )
+	STD_EXCEPTION_PSERIES( 0x300, DataAccess )
+	STD_EXCEPTION_PSERIES( 0x380, DataAccessSLB )
+	STD_EXCEPTION_PSERIES( 0x400, InstructionAccess )
+	STD_EXCEPTION_PSERIES( 0x480, InstructionAccessSLB )
+	STD_EXCEPTION_PSERIES( 0x500, HardwareInterrupt )
+	STD_EXCEPTION_PSERIES( 0x600, Alignment )
+	STD_EXCEPTION_PSERIES( 0x700, ProgramCheck )
+	STD_EXCEPTION_PSERIES( 0x800, FPUnavailable )
+	STD_EXCEPTION_PSERIES( 0x900, Decrementer )
+	STD_EXCEPTION_PSERIES( 0xa00, Trap_0a )
+	STD_EXCEPTION_PSERIES( 0xb00, Trap_0b )
+	STD_EXCEPTION_PSERIES( 0xc00, SystemCall )
+	STD_EXCEPTION_PSERIES( 0xd00, SingleStep )
+	STD_EXCEPTION_PSERIES( 0xe00, Trap_0e )
+	STD_EXCEPTION_PSERIES( 0xf00, PerformanceMonitor )
+	STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint )
+
+	. = 0x4000
+	.globl __end_interupts
+	.globl __start_naca
+__end_interupts:
+__start_naca:
+	/* Save space for naca.
+	 * The first dword of the Naca is required by iSeries LPAR to
+	 * point to itVpdAreas.  On pSeries native, this value is not used.
+	 */
+	.llong itVpdAreas
+	.llong 0x0
+	.llong 0x0
+	.llong xPaca
+
+	/*
+	 * Space for the initial segment table
+	 * For LPAR, the hypervisor must fill in at least one entry
+	 * before we get control (with relocate on)
+	 */
+
+	. = 0x5000
+	.globl __end_naca
+	.globl __start_stab
+__end_naca:
+__start_stab:
+
+
+	. = 0x6000
+	.globl __end_stab
+__end_stab:
+
+	/*
+	 * The iSeries LPAR map is at this fixed address
+	 * so that the HvReleaseData structure can address
+	 * it with a 32-bit offset.
+	 *
+	 * The VSID values below are dependent on the
+	 * VSID generation algorithm.  See include/asm/mmu_context.h.
+	 */
+
+	.llong	1		/* # ESIDs to be mapped by hypervisor         */
+	.llong	1		/* # memory ranges to be mapped by hypervisor */
+	.llong	5		/* Page # of segment table within load area   */
+	.llong	0		/* Reserved */
+	.llong  0		/* Reserved */
+	.llong  0		/* Reserved */
+	.llong	0		/* Reserved */
+	.llong	0		/* Reserved */
+	.llong	0x0c00000000	/* ESID to map (Kernel at EA = 0xC000000000000000) */
+	.llong	0x06a99b4b14    /* VSID to map (Kernel at VA = 0x6a99b4b140000000) */
+	.llong	8192		/* # pages to map (32 MB) */
+	.llong	0		/* Offset from start of loadarea to start of map */
+	.llong	0x0006a99b4b140000	/* VPN of first page to map */
+
+	. = 0x6100
+
+/***  ISeries-LPAR interrupt handlers ***/
+
+	STD_EXCEPTION_ISERIES( MachineCheck )
+	STD_EXCEPTION_ISERIES( DataAccess )
+	STD_EXCEPTION_ISERIES( DataAccessSLB )
+	STD_EXCEPTION_ISERIES( InstructionAccess )
+	STD_EXCEPTION_ISERIES( InstructionAccessSLB )
+	MASKABLE_EXCEPTION_ISERIES( HardwareInterrupt )
+	STD_EXCEPTION_ISERIES( Alignment )
+	STD_EXCEPTION_ISERIES( ProgramCheck )
+	STD_EXCEPTION_ISERIES( FPUnavailable )
+	MASKABLE_EXCEPTION_ISERIES( Decrementer )
+	STD_EXCEPTION_ISERIES( Trap_0a )
+	STD_EXCEPTION_ISERIES( Trap_0b )
+	STD_EXCEPTION_ISERIES( SystemCall )
+	STD_EXCEPTION_ISERIES( SingleStep )
+	STD_EXCEPTION_ISERIES( Trap_0e )
+	STD_EXCEPTION_ISERIES( PerformanceMonitor )
+
+	.globl SystemReset_Iseries
+SystemReset_Iseries:
+	mfspr	25,SPRG3		/* Get Paca address */
+	lhz	r24,PACAPACAINDEX(r25)	/* Get processor # */
+	cmpi	0,r24,0			/* Are we processor 0? */
+	beq	.__start_initialization_iSeries	/* Start up the first processor */
+	mfspr	r4,CTRLF
+	li	r5,RUNLATCH		/* Turn off the run light */
+	andc	r4,r4,r5
+	mtspr	CTRLT,r4
+
+1:
+	HMT_LOW
+#ifdef CONFIG_SMP
+	lbz	r23,PACAPROCSTART(r25)	/* Test if this processor
+					 * should start */
+	sync
+	LOADADDR(r3,current_set)
+	sldi	r28,r24,4		/* get current_set[cpu#] */
+	ldx	r3,r3,r28
+	addi	r1,r3,TASK_UNION_SIZE
+	subi	r1,r1,STACK_FRAME_OVERHEAD
+
+	cmpi	0,r23,0
+	beq	iseries_secondary_smp_loop	/* Loop until told to go */
+#ifdef SECONDARY_PROCESSORS
+	bne	.__secondary_start		/* Loop until told to go */
+#endif
+iseries_secondary_smp_loop:
+	/* Let the Hypervisor know we are alive */
+	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
+	lis	r3,0x8002
+	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
+#else /* CONFIG_SMP */
+	/* Yield the processor.  This is required for non-SMP kernels
+	   which are running on multi-threaded machines. */
+	lis	r3,0x8000
+	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */
+	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */
+	li	r4,0			/* "yield timed" */
+	li	r5,-1			/* "yield forever" */
+#endif /* CONFIG_SMP */
+	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
+	sc				/* Invoke the hypervisor via a system call */
+	mfspr	r25,SPRG3		/* Put r25 back ???? */
+	b	1b			/* If SMP not configured, secondaries
+					 * loop forever */
+
+	.globl HardwareInterrupt_Iseries_masked
+HardwareInterrupt_Iseries_masked:
+	b	maskable_exception_exit
+
+	.globl Decrementer_Iseries_masked
+Decrementer_Iseries_masked:
+	li	r22,1
+	stb	r22,PACALPPACA+LPPACADECRINT(r20)
+	lwz	r22,PACADEFAULTDECR(r20)
+	mtspr	DEC,r22
+maskable_exception_exit:
+	mtcrf	0xff,r23		/* Restore regs and free exception frame */
+	ld	r22,EX_SRR0(r21)
+	ld	r23,EX_SRR1(r21)
+	mtspr	SRR0,r22
+	mtspr	SRR1,r23
+	ld	r22,EX_R22(r21)
+	ld	r23,EX_R23(r21)
+	mfspr	r21,SPRG1
+	mfspr	r20,SPRG2
+	rfid
+
+/*** Common interrupt handlers ***/
+
+	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
+	STD_EXCEPTION_COMMON( 0x200, MachineCheck, .MachineCheckException )
+	STD_EXCEPTION_COMMON( 0x900, Decrementer, .timer_interrupt )
+	STD_EXCEPTION_COMMON( 0xa00, Trap_0a, .UnknownException )
+	STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException )
+	STD_EXCEPTION_COMMON( 0xd00, SingleStep, .SingleStepException )
+	STD_EXCEPTION_COMMON( 0xe00, Trap_0e, .UnknownException )
+	STD_EXCEPTION_COMMON( 0xf00, PerformanceMonitor, .PerformanceMonitorException )
+	STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException )
+
+/*
+ * Return from an exception which is handled without calling
+ * save_remaining_regs.  The caller is assumed to have done
+ * EXCEPTION_PROLOG_COMMON.
+ */
+fast_exception_return:
+	ld      r3,_CCR(r1)
+	ld      r4,_LINK(r1)
+	ld      r5,_CTR(r1)
+	ld      r6,_XER(r1)
+	mtcr    r3
+	mtlr    r4
+	mtctr   r5
+	mtspr   XER,r6
+	REST_GPR(0, r1)
+	REST_8GPRS(2, r1)
+	REST_4GPRS(10, r1)
+	mtspr   SRR1,r23
+	mtspr   SRR0,r22
+	REST_4GPRS(20, r1)
+	ld      r1,GPR1(r1)
+	rfid
+
+
+/*
+ * Here r20 points to the PACA, r21 to the exception frame,
+ * r23 contains the saved CR.
+ * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
+ */
+	.globl DataAccess_common
+DataAccess_common:
+	mfspr   r22,DAR
+	srdi    r22,r22,60
+	cmpi    0,r22,0xc
+
+	/* Segment fault on a bolted segment. Go off and map that segment. */
+	beq     .do_stab_bolted
+stab_bolted_user_return:
+	EXCEPTION_PROLOG_COMMON
+	ld      r3,_DSISR(r1)
+	andis.	r0,r3,0xa450		/* weird error? */
+	bne	1f			/* if not, try to put a PTE */
+	andis.	r0,r3,0x0020		/* Is it a page table fault? */
+	rlwinm	r4,r3,32-23,29,29	/* DSISR_STORE -> _PAGE_RW */
+	ld      r3,_DAR(r1)             /* into the hash table */
+
+	beq	2f			/* If so handle it */
+	li	r4,0x300                /* Trap number */
+	bl	.do_stab_SI
+	b	1f
+
+2:	bl	.do_hash_page_DSI 	/* Try to handle as hpte fault */
+1:
+	ld      r4,_DAR(r1)
+	ld      r5,_DSISR(r1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)		/* Copy saved SOFTE bit */
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0x300
+	bl      .save_remaining_regs
+	bl      .do_page_fault
+	b       .ret_from_except
+
+	.globl DataAccessSLB_common
+DataAccessSLB_common:
+	mfspr   r22,DAR
+	srdi    r22,r22,60
+	cmpi    0,r22,0xc
+
+	/* Segment fault on a bolted segment. Go off and map that segment. */
+	beq     .do_slb_bolted
+
+	EXCEPTION_PROLOG_COMMON
+	ld      r3,_DAR(r1)
+	li      r4,0x380                /* Exception vector  */
+	bl	.ste_allocate
+	or.	r3,r3,r3		/* Check return code */
+	beq     fast_exception_return   /* Return if we succeeded */
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0x380
+	bl      .save_remaining_regs
+	bl      .do_page_fault
+	b       .ret_from_except
+
+	.globl InstructionAccess_common
+InstructionAccess_common:
+	EXCEPTION_PROLOG_COMMON
+
+	andis.	r0,r23,0x0020		/* no ste found? */
+	beq	2f
+	mr	r3,r22			/* SRR0 at interrupt */
+	li	r4,0x400		/* Trap number       */
+	bl	.do_stab_SI
+	b	1f
+
+2:	andis.	r0,r23,0x4000		/* no pte found? */
+	beq	1f			/* if so, try to put a PTE */
+	mr	r3,r22			/* into the hash table */
+	bl	.do_hash_page_ISI	/* Try to handle as hpte fault */
+1:
+	mr	r4,r22
+	mr	r5,r23
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0x400
+	bl      .save_remaining_regs
+	bl      .do_page_fault
+	b       .ret_from_except
+
+	.globl InstructionAccessSLB_common
+InstructionAccessSLB_common:
+	EXCEPTION_PROLOG_COMMON
+	mr      r3,r22                  /* SRR0 = NIA        */
+	li	r4,0x480                /* Exception vector  */
+	bl	.ste_allocate
+	or.	r3,r3,r3		/* Check return code */
+	beq     fast_exception_return   /* Return if we succeeded */
+
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0x380
+	bl      .save_remaining_regs
+	bl      .do_page_fault
+	b       .ret_from_except
+
+	.globl HardwareInterrupt_common
+HardwareInterrupt_common:
+	EXCEPTION_PROLOG_COMMON
+HardwareInterrupt_entry:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,0
+	li	r6,0x500
+	bl      .save_remaining_regs
+	/* Determine if need to run do_irq on a hardware interrupt stack  */
+	/*   The first invocation of do_irq will occur on the kernel      */
+	/*   stack in the current stack                                   */
+	/*   All other invocations of do_irq will run on the hardware     */
+	/*   interrupt stack associated with the PACA of the current      */
+	/*   processor.                                                   */
+	/*                                                                */
+	/*  The call to do_irq will preserve the value of r14 - r31       */
+	/*                                                                */
+	mfspr	r20,SPRG3 		    /* get Paca                   */
+	lbz     r21,PACAHRDWINTCOUNT(r20)    /* get hardware interrupt cnt */
+	cmpi    0,r21,1                     /*                            */
+	addi    r21,r21,1                   /* incr hardware interrupt cnt*/
+	stb     r21,PACAHRDWINTCOUNT(r20)   /*                            */
+	bne     2f                          /*                            */
+
+	mr      r14,r1                      /* preserve current r1        */
+	ld      r1,PACAHRDWINTSTACK(r20)    /*                            */
+	std     r14,0(r1)                   /* set the back chain         */
+	bl      .do_IRQ
+	lbz     r22,PACAHRDWINTCOUNT(r20)   /* get hardware interrupt cnt */
+	cmp     0,r22,r21                   /* debug test                 */
+	bne     3f
+	subi    r21,r21,1
+	stb     r21,PACAHRDWINTCOUNT(r20)   /*                            */
+	mr      r1,r14                      /*                            */
+	b       .ret_from_except
+
+2:
+	bl      .do_IRQ
+
+	lbz     r22,PACAHRDWINTCOUNT(r20)   /* get hardware interrupt cnt */
+	cmp     0,r22,r21                   /* debug test                 */
+	bne     3f                          /*                            */
+	subi    r21,r21,1                   /* decr hardware interrupt cnt*/
+	stb     r21,PACAHRDWINTCOUNT(r20)   /*                            */
+
+	b       .ret_from_except
+
+3:
+	/* error - counts out of sync                                      */
+#ifdef CONFIG_XMON
+	bl	.xmon
+#endif
+4:	b	4b
+
+
+	.globl Alignment_common
+Alignment_common:
+	EXCEPTION_PROLOG_COMMON
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0x600
+	bl      .save_remaining_regs
+	bl      .AlignmentException
+	b       .ret_from_except
+
+	.globl ProgramCheck_common
+ProgramCheck_common:
+	EXCEPTION_PROLOG_COMMON
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0x700
+	bl      .save_remaining_regs
+	bl      .ProgramCheckException
+	b       .ret_from_except
+
+	.globl FPUnavailable_common
+FPUnavailable_common:
+	EXCEPTION_PROLOG_COMMON
+	bne	.load_up_fpu		/* if from user, just load it up */
+	li	r20,0
+	li	r6,0x800
+	bl      .save_remaining_regs    /* if from kernel, take a trap */
+	bl      .KernelFP
+	b       .ret_from_except
+
+	.globl SystemCall_common
+SystemCall_common:
+	EXCEPTION_PROLOG_COMMON
+#ifdef CONFIG_PPC_ISERIES
+	cmpi	0,r0,0x5555		/* Special syscall to handle pending */
+	bne+	1f			/* interrupts */
+	andi.	r6,r23,MSR_PR		/* Only allowed from kernel */
+	beq+	HardwareInterrupt_entry
+1:
+#endif
+	std	r3,ORIG_GPR3(r1)
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
+	li	r6,0xC00
+	bl      .save_remaining_regs
+	bl      .DoSyscall
+	b       .ret_from_except
+
+_GLOBAL(do_hash_page_ISI)
+	li	r4,0
+_GLOBAL(do_hash_page_DSI)
+	rlwimi	r4,r23,32-13,30,30	/* Insert MSR_PR as _PAGE_USER */
+	ori	r4,r4,1			/* add _PAGE_PRESENT */
+
+	mflr	r21			/* Save LR in r21 */
+
+#ifdef DO_SOFT_DISABLE
+	/*
+	 * We hard enable here (but first soft disable) so that the hash_page
+	 * code can spin on the hash_table_lock with problem on a shared
+	 * processor.
+	 */
+	li	r0,0
+	stb	r0,PACAPROCENABLED(r20)	/* Soft Disabled */
+
+	mfmsr	r0
+	ori	r0,r0,MSR_EE+MSR_RI
+	mtmsrd	r0			/* Hard Enable, RI on */
+#endif
+
+	/*
+	 * r3 contains the faulting address
+	 * r4 contains the required access permissions
+	 *
+	 * at return r3 = 0 for success
+	 */
+
+	bl	.hash_page		/* build HPTE if possible */
+
+#ifdef DO_SOFT_DISABLE
+	/*
+	 * Now go back to hard disabled.
+	 */
+	mfmsr	r0
+	li	r4,0
+	ori	r4,r4,MSR_EE+MSR_RI
+	andc	r0,r0,r4
+	mtmsrd	r0			/* Hard Disable, RI off */
+
+	ld	r0,SOFTE(r1)
+	cmpdi	0,r0,0			/* See if we will soft enable in */
+					/* save_remaining_regs */
+	beq	5f
+	CHECKANYINT(r4,r5)
+	bne-	HardwareInterrupt_entry	/* Convert this DSI into an External */
+					/* to process interrupts which occurred */
+					/* during hash_page */
+5:
+	stb	r0,PACAPROCENABLED(r20)	/* Restore soft enable/disable status */
+#endif
+	or.	r3,r3,r3		/* Check return code */
+	beq     fast_exception_return   /* Return from exception on success */
+
+	mtlr    r21                     /* restore LR */
+	blr                             /* Return to DSI or ISI on failure */
+
+/*
+ * r20 points to the PACA, r21 to the exception frame,
+ * r23 contains the saved CR.
+ * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
+ * We assume we aren't going to take any exceptions during this procedure.
+ */
+_GLOBAL(do_stab_bolted)
+	std	r23,EX_DAR(r21)	/* save CR in exc. frame */
+
+	mfspr   r22,DSISR
+	andis.  r22,r22,0x0020
+	bne+    2f
+	ld	r22,8(r21)	/* get SRR1 */
+	andi.	r22,r22,MSR_PR	/* check if from user */
+	bne+	stab_bolted_user_return  /* from user, send the error on up */
+	li	r3,0
+#ifdef CONFIG_XMON
+	bl	.xmon
+#endif
+1:	b	1b
+2:
+	/* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
+	mfspr	r21,DAR
+	rldicl  r20,r21,36,32   /* Permits a full 32b of ESID */
+	rldicr  r20,r20,15,48
+	rldicl  r21,r21,4,60
+	or      r20,r20,r21
+
+	li      r21,9           /* VSID_RANDOMIZER */
+	sldi    r21,r21,32
+	oris    r21,r21,58231
+	ori     r21,r21,39831
+
+	mulld   r20,r20,r21
+	clrldi  r20,r20,28      /* r20 = vsid */
+
+	mfsprg  r21,3
+	ld      r21,PACASTABVIRT(r21)
+
+	/* Hash to the primary group */
+	mfspr	r22,DAR
+	rldicl  r22,r22,36,59
+	rldicr  r22,r22,7,56
+	or      r21,r21,r22     /* r21 = first ste of the group */
+
+	/* Search the primary group for a free entry */
+	li      r22,0
+1:
+	ld      r23,0(r21)      /* Test valid bit of the current ste   */
+	rldicl  r23,r23,57,63
+	cmpwi   r23,0
+	bne     2f
+	ld      r23,8(r21)      /* Get the current vsid part of the ste */
+	rldimi  r23,r20,12,0    /* Insert the new vsid value            */
+	std     r23,8(r21)      /* Put new entry back into the stab     */
+	eieio                  /* Order vsid update                    */
+	ld      r23,0(r21)      /* Get the esid part of the ste         */
+	mfspr	r20,DAR        /* Get the new esid                     */
+	rldicl  r20,r20,36,28  /* Permits a full 36b of ESID           */
+	rldimi  r23,r20,28,0    /* Insert the new esid value            */
+	ori     r23,r23,144      /* Turn on valid and kp                 */
+	std     r23,0(r21)      /* Put new entry back into the stab     */
+	sync                   /* Order the update                     */
+	b       3f
+2:
+	addi    r22,r22,1
+	addi    r21,r21,16
+	cmpldi  r22,7
+	ble     1b
+
+	/* Stick for only searching the primary group for now.          */
+	/* At least for now, we use a very simple random castout scheme */
+	/* Use the TB as a random number ;  OR in 1 to avoid entry 0    */
+	mftb    r22
+	andi.   r22,r22,7
+	ori	r22,r22,1
+	sldi	r22,r22,4
+
+	/* r21 currently points to and ste one past the group of interest */
+	/* make it point to the randomly selected entry                   */
+	subi	r21,r21,128
+	or 	r21,r21,r22      /* r21 is the entry to invalidate        */
+
+	isync                    /* mark the entry invalid                */
+	ld      r23,0(r21)
+	li      r22,-129
+	and     r23,r23,r22
+	std     r23,0(r21)
+	sync
+
+	ld      r23,8(r21)
+	rldimi  r23,r20,12,0
+	std     r23,8(r21)
+	eieio
+
+	ld      r23,0(r21)      /* Get the esid part of the ste         */
+	mr      r22,r23
+	mfspr	r20,DAR         /* Get the new esid                     */
+	rldicl  r20,r20,36,28   /* Permits a full 32b of ESID           */
+	rldimi  r23,r20,28,0    /* Insert the new esid value            */
+	ori     r23,r23,144     /* Turn on valid and kp                 */
+	std     r23,0(r21)      /* Put new entry back into the stab     */
+
+	rldicl  r22,r22,36,28
+	rldicr  r22,r22,28,35
+	slbie   r22
+	sync
+
+3:
+	/* All done -- return from exception. */
+	mfsprg  r20,3                   /* Load the PACA pointer  */
+	ld      r21,PACAEXCSP(r20)      /* Get the exception frame pointer */
+	addi    r21,r21,EXC_FRAME_SIZE
+	ld	r23,EX_DAR(r21)		/* get saved CR */
+	/* note that this is almost identical to maskable_exception_exit */
+	mtcr    r23                     /* restore CR */
+	ld	r22,EX_SRR0(r21)	/* Get SRR0 from exc. frame */
+	ld	r23,EX_SRR1(r21)	/* Get SRR1 from exc. frame */
+	mtspr	SRR0,r22
+	mtspr   SRR1,r23
+	ld	r22,EX_R22(r21)		/* restore r22 and r23 */
+	ld	r23,EX_R23(r21)
+	mfspr	r20,SPRG2
+	mfspr	r21,SPRG1
+	rfid
+_TRACEBACK(do_stab_bolted)
+
+/*
+ * r20 points to the PACA, r21 to the exception frame,
+ * r23 contains the saved CR.
+ * r20 - r23, SRR0 and SRR1 are saved in the exception frame.
+ * We assume we aren't going to take any exceptions during this procedure.
+ */
+_GLOBAL(do_slb_bolted)
+	std     r23,48(r21)     /* save CR in exc. frame */
+
+	/* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
+	mfspr	r21,DAR
+	rldicl  r20,r21,36,32   /* Permits a full 32b of ESID */
+	rldicr  r20,r20,15,48
+	rldicl  r21,r21,4,60
+	or      r20,r20,r21
+
+	li      r21,9           /* VSID_RANDOMIZER */
+	sldi    r21,r21,32
+	oris    r21,r21,58231
+	ori     r21,r21,39831
+
+	mulld   r20,r20,r21
+	clrldi  r20,r20,28      /* r20 = vsid */
+
+	/* Search the SLB for a free entry */
+	li      r22,1
+1:
+	slbmfee	r23,r22
+	rldicl  r23,r23,37,63
+	cmpwi   r23,0
+	beq     3f              /* Found an invalid entry              */
+
+	addi	r22,r22,1
+	cmpldi	r22,64
+	blt	1b
+
+	/* No free entry - just take the next entry, round-robin */
+	/* XXX we should get the number of SLB entries from the naca */
+SLB_NUM_ENTRIES = 64
+	mfspr	r21,SPRG3
+	ld	r22,PACASTABRR(r21)
+	addi	r23,r22,1
+	cmpdi	r23,SLB_NUM_ENTRIES
+	blt	2f
+	li	r23,1
+2:	std	r23,PACASTABRR(r21)
+
+	/* r20 = vsid, r22 = entry */
+3:
+	/* Put together the vsid portion of the entry. */
+	li      r21,0
+	rldimi  r21,r20,12,0
+	ori     r20,r21,1024
+#ifndef CONFIG_PPC_ISERIES
+	ori	r20,r20,256    /* map kernel region with large ptes */
+#endif
+	
+	/* Put together the esid portion of the entry. */
+	mfspr	r21,DAR        /* Get the new esid                     */
+	rldicl  r21,r21,36,28  /* Permits a full 36b of ESID           */
+	li      r23,0
+	rldimi  r23,r21,28,0   /* Insert esid  */
+	oris    r21,r23,2048   /* valid bit    */
+	rldimi  r21,r22,0,52   /* Insert entry */
+
+	isync
+	slbmte  r20,r21
+	isync
+
+	/* All done -- return from exception. */
+	mfsprg  r20,3                   /* Load the PACA pointer  */
+	ld      r21,PACAEXCSP(r20)      /* Get the exception frame pointer */
+	addi    r21,r21,EXC_FRAME_SIZE
+	ld	r23,EX_DAR(r21)		/* get saved CR */
+	/* note that this is almost identical to maskable_exception_exit */
+	mtcr    r23                     /* restore CR */
+	ld	r22,EX_SRR0(r21)	/* Get SRR0 from exc. frame */
+	ld	r23,EX_SRR1(r21)	/* Get SRR1 from exc. frame */
+	mtspr	SRR0,r22
+	mtspr   SRR1,r23
+	ld	r22,EX_R22(r21)		/* restore r22 and r23 */
+	ld	r23,EX_R23(r21)
+	mfspr	r20,SPRG2
+	mfspr	r21,SPRG1
+	rfid
+_TRACEBACK(do_slb_bolted)
+
+_GLOBAL(do_stab_SI)
+	mflr	r21			/* Save LR in r21 */
+
+	/*
+	 * r3 contains the faulting address
+	 * r4 contains the required access permissions
+	 *
+	 * at return r3 = 0 for success
+	 */
+
+	bl	.ste_allocate		/* build STE if possible */
+	or.	r3,r3,r3		/* Check return code */
+	beq     fast_exception_return   /* Return from exception on success */
+	mtlr    r21                     /* restore LR */
+	blr                             /* Return to DSI or ISI on failure */
+
+/*
+ * This code finishes saving the registers to the exception frame.
+ * Address translation is already on.
+ */
+_GLOBAL(save_remaining_regs)
+	/*
+	 * Save the rest of the registers into the pt_regs structure
+	 */
+	std     r22,_NIP(r1)
+	std     r23,_MSR(r1)
+	std     r6,TRAP(r1)
+	ld      r6,GPR6(r1)
+	SAVE_2GPRS(14, r1)
+	SAVE_4GPRS(16, r1)
+	SAVE_8GPRS(24, r1)
+
+	/*
+	 * Clear the RESULT field
+	 */
+	li	r22,0
+	std	r22,RESULT(r1)
+
+	/*
+	 * Test if from user state; result will be tested later
+	 */
+	andi.	r23,r23,MSR_PR		/* Set CR for later branch */
+
+	/*
+	 * Indicate that r1 contains the kernel stack and
+	 * get the Kernel TOC and CURRENT pointers from the Paca
+	 */
+	mfspr	r23,SPRG3		/* Get PACA */
+	std	r22,PACAKSAVE(r23)	/* r1 is now kernel sp */
+	ld	r2,PACATOC(r23)		/* Get Kernel TOC pointer */
+
+	/*
+	 * If from user state, update THREAD.regs
+	 */
+	beq	2f			/* Modify THREAD.regs if from user */
+	addi	r24,r1,STACK_FRAME_OVERHEAD
+	std	r24,THREAD+PT_REGS(r13)
+2:
+	SET_REG_TO_CONST(r22, MSR_KERNEL)
+
+#ifdef DO_SOFT_DISABLE
+	stb	r20,PACAPROCENABLED(r23) /* possibly soft enable */
+	ori	r22,r22,MSR_EE		/* always hard enable */
+#else
+	rldimi	r22,r20,15,48		/* Insert desired EE value */
+#endif
+
+	mtmsrd  r22
+	blr
+
+
+do_profile:
+	ld	r22,8(r21)		/* Get SRR1 */
+	andi.	r22,r22,MSR_PR		/* Test if in kernel */
+	bnelr				/* return if not in kernel */
+	ld	r22,0(r21)		/* Get SRR0 */
+	ld	r25,PACAPROFSTEXT(r20)	/* _stext */
+	subf	r22,r25,r22		/* offset into kernel */
+	lwz	r25,PACAPROFSHIFT(r20)
+	srd	r22,r22,r25
+	lwz	r25,PACAPROFLEN(r20)	/* length of profile table (-1) */
+	cmp	0,r22,r25		/* off end? */
+	ble	1f
+	mr	r22,r25			/* force into last entry */
+1:	sldi	r22,r22,2		/* convert to offset into buffer */
+	ld	r25,PACAPROFBUFFER(r20)	/* profile buffer */
+	add	r25,r25,r22
+2:	lwarx	r22,0,r25		/* atomically increment */
+	addi	r22,r22,1
+	stwcx.	r22,0,r25
+	bne-	2b
+	blr
+
+
+/*
+ * On pSeries, secondary processors spin in the following code.
+ * At entry, r3 = this processor's number (in Linux terms, not hardware).
+ */
+_GLOBAL(pseries_secondary_smp_init)
+
+	/* turn on 64-bit mode */
+	bl	.enable_64b_mode
+	isync
+
+	/* Set up a Paca value for this processor. */
+	LOADADDR(r24, xPaca) 		 /* Get base vaddr of Paca array  */
+	mulli	r25,r3,PACA_SIZE	 /* Calculate vaddr of right Paca */
+	add	r25,r25,r24              /* for this processor.           */
+
+	mtspr	SPRG3,r25		 /* Save vaddr of Paca in SPRG3   */
+	mr	r24,r3			 /* __secondary_start needs cpu#  */
+
+1:
+	HMT_LOW
+	lbz	r23,PACAPROCSTART(r25)	 /* Test if this processor should */
+					 /* start.                        */
+	sync
+
+        /* Create a temp kernel stack for use before relocation is on.    */
+        mr      r1,r25
+        addi    r1,r1,PACAGUARD
+        addi    r1,r1,0x1000
+        subi    r1,r1,STACK_FRAME_OVERHEAD
+
+	cmpi	0,r23,0
+#ifdef CONFIG_SMP
+#ifdef SECONDARY_PROCESSORS
+	bne	.__secondary_start
+#endif
+#endif
+	b 	1b			 /* Loop until told to go         */
+
+_GLOBAL(__start_initialization_iSeries)
+
+	LOADADDR(r1,init_task_union)
+	addi	r1,r1,TASK_UNION_SIZE
+	li	r0,0
+	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
+
+	LOADADDR(r2,__toc_start)
+	addi	r2,r2,0x4000
+	addi	r2,r2,0x4000
+
+	LOADADDR(r9,naca)
+	SET_REG_TO_CONST(r4, KERNELBASE)
+	addi	r4,r4,0x4000
+	std	r4,0(r9)		/* set the naca pointer */
+
+	/* Get the pointer to the segment table */
+	ld	r6,PACA(r4)             /* Get the base Paca pointer       */
+	ld	r4,PACASTABVIRT(r6)
+
+	bl      .iSeries_fixup_klimit
+
+	b	.start_here_common
+
+_GLOBAL(__start_initialization_pSeries)
+	mr	r31,r3			/* save parameters */
+	mr	r30,r4
+	mr	r29,r5
+	mr	r28,r6
+	mr	r27,r7
+	mr	r26,r8                  /* YABOOT: debug_print() routine */
+	mr	r25,r9                  /* YABOOT: debug_delay() routine */
+	mr	r24,r10                 /* YABOOT: debug_prom() routine */
+
+	bl	.enable_64b_mode
+
+	/* put a relocation offset into r3 */
+	bl	.reloc_offset
+
+	LOADADDR(r2,__toc_start)
+	addi    r2,r2,0x4000
+	addi    r2,r2,0x4000
+
+	/* Relocate the TOC from a virt addr to a real addr */
+	sub	r2,r2,r3
+
+	/* setup the naca pointer which is needed by prom_init            */
+	LOADADDR(r9,naca)
+	sub	r9,r9,r3                /* addr of the variable naca      */
+
+	SET_REG_TO_CONST(r4, KERNELBASE)
+	sub	r4,r4,r3
+	addi	r4,r4,0x4000
+	std	r4,0(r9)		/* set the value of naca          */
+
+	/* DRENG / PPPBBB Fix the following comment!!! -Peter */
+	/* The following copies the first 0x100 bytes of code from the    */
+	/* load addr to physical addr 0x0.  This code causes secondary    */
+	/* processors to spin until a flag in the PACA is set.  This      */
+	/* is done at this time rather than with the entire kernel        */
+	/* relocation which is done below because we need to cause the    */
+	/* processors to spin on code that is not going to move while OF  */
+	/* is still alive. Although the spin code is not actually run on  */
+	/* a uniprocessor, we always do this copy.                        */
+	SET_REG_TO_CONST(r4, KERNELBASE)/* Src addr                       */
+	sub	r4,r4,r3  		/* current address of __start     */
+			                /*        the source addr         */
+	li	r3,0                    /* Dest addr                      */
+	li	r5,0x100 		/* # bytes of memory to copy      */
+	li	r6,0			/* Destination offset             */
+	bl	.copy_and_flush		/* copy the first 0x100 bytes     */
+
+	mr	r3,r31
+	mr	r4,r30
+	mr	r5,r29
+	mr	r6,r28
+	mr	r7,r27
+	mr	r8,r26
+	mr	r9,r25
+	mr	r10,r24
+
+	bl	.prom_init
+
+	li	r24,0			/* cpu # */
+
+/*
+ * At this point, r3 contains the physical address we are running at,
+ * returned by prom_init()
+ */
+_STATIC(__after_prom_start)
+
+/*
+ * We need to run with __start at physical address 0.
+ * This will leave some code in the first 256B of
+ * real memory, which are reserved for software use.
+ * The remainder of the first page is loaded with the fixed
+ * interrupt vectors.  The next two pages are filled with
+ * unknown exception placeholders.
+ *
+ * Note: This process overwrites the OF exception vectors.
+ *       r26 == relocation offset
+ *       r27 == KERNELBASE
+ */
+	bl	.reloc_offset
+	mr	r26,r3
+	SET_REG_TO_CONST(r27,KERNELBASE)
+
+	li	r3,0                    /* target addr */
+
+	sub	r4,r27,r26 		/* source addr */
+					/* current address of _start   */
+			                /*   i.e. where we are running */
+			                /*        the source addr      */
+
+	LOADADDR(r5,copy_to_here)	/* # bytes of memory to copy      */
+	sub	r5,r5,r27
+
+	li	r6,0x100		/* Start offset, the first 0x100  */
+					/* bytes were copied earlier.	  */
+
+	bl	.copy_and_flush		/* copy the first n bytes         */
+					/* this includes the code being   */
+					/* executed here.                 */
+
+	li	r0,4f@l			/* Jump to the copy of this code  */
+	mtctr	r0			/* that we just made              */
+	bctr
+
+4:	LOADADDR(r9,rtas)
+	sub	r9,r9,r26
+	ld	r5,RTASBASE(r9)		/* get the value of rtas->base */
+	ld	r9,RTASSIZE(r9)		/* get the value of rtas->size */
+	bl	.copy_and_flush		/* copy upto rtas->base */
+	add     r6,r6,r9		/* then skip over rtas->size bytes */
+
+	LOADADDR(r5,klimit)
+	sub	r5,r5,r26
+	ld	r5,0(r5)		/* get the value of klimit */
+	sub	r5,r5,r27
+	bl	.copy_and_flush		/* copy the rest */
+	b	.start_here_pSeries
+
+/*
+ * Copy routine used to copy the kernel to start at physical address 0
+ * and flush and invalidate the caches as needed.
+ * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
+ * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
+ *
+ * Note: this routine *only* clobbers r0, r6 and lr
+ */
+_STATIC(copy_and_flush)
+	addi	r5,r5,-8
+	addi	r6,r6,-8
+4:	li	r0,16                   /* Use the least common      */
+					/* denominator cache line    */
+			                /* size.  This results in    */
+					/* extra cache line flushes  */
+					/* but operation is correct. */
+					/* Can't get cache line size */
+					/* from NACA as it is being  */
+					/* moved too.                */
+
+	mtctr	r0			/* put # words/line in ctr */
+3:	addi	r6,r6,8			/* copy a cache line */
+	ldx	r0,r6,r4
+	stdx	r0,r6,r3
+	bdnz	3b
+	dcbst	r6,r3			/* write it to memory */
+	sync
+	icbi	r6,r3			/* flush the icache line */
+	cmpld	0,r6,r5
+	blt	4b
+	sync
+	addi	r5,r5,8
+	addi	r6,r6,8
+	blr
+
+.align 8
+copy_to_here:
+
+/*
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * On SMP we know the fpu is free, since we give it up every
+ * switch.  -- Cort
+ */
+_STATIC(load_up_fpu)
+	mfmsr	r5                      /* grab the current MSR */
+	ori	r5,r5,MSR_FP
+	mtmsrd  r5			/* enable use of fpu now */
+	isync
+/*
+ * 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 CONFIG_SMP
+	LOADBASE(r3,last_task_used_math)
+	ld	r4,last_task_used_math@l(r3)
+	cmpi	0,r4,0
+	beq	1f
+	addi	r4,r4,THREAD	       /* want THREAD of last_task_used_math */
+	SAVE_32FPRS(0, r4)
+	mffs	fr0
+	stfd	fr0,THREAD_FPSCR-4(r4)
+	ld	r5,PT_REGS(r4)
+	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r20,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r20		/* disable FP for previous task */
+	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+	/* enable use of FP after return */
+	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
+	addi	r5,r13,THREAD		/* Get THREAD */
+	lfd	fr0,THREAD_FPSCR-4(r5)
+	mtfsf	0xff,fr0
+	REST_32FPRS(0, r5)
+#ifndef CONFIG_SMP
+	subi	r4,r5,THREAD		/* Back to 'current' */
+	std	r4,last_task_used_math@l(r3)
+#endif /* CONFIG_SMP */
+	/* restore registers and return */
+	b	fast_exception_return
+
+/*
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
+ */
+_GLOBAL(KernelFP)
+	ld	r3,_MSR(r1)
+	ori	r3,r3,MSR_FP
+	std	r3,_MSR(r1)		/* enable use of FP after return */
+	LOADADDR(r3,86f)
+	mfspr	r4,SPRG3		/* Get PACA */
+	ld	r4,PACACURRENT(r4)	/* current */
+	ld	r5,_NIP(r1)
+	b	.ret_from_except
+86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
+	.align	4
+
+/*
+ * 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.
+ */
+_GLOBAL(giveup_fpu)
+	mfmsr	r5
+	ori	r5,r5,MSR_FP
+	mtmsrd	r5			/* enable use of fpu now */
+	isync
+	cmpi	0,r3,0
+	beqlr-				/* if no previous owner, done */
+	addi	r3,r3,THREAD		/* want THREAD of task */
+	ld	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32FPRS(0, r3)
+	mffs	fr0
+	stfd	fr0,THREAD_FPSCR-4(r3)
+	beq	1f
+	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r3,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r3		/* disable FP for previous task */
+	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+	li	r5,0
+	LOADBASE(r4,last_task_used_math)
+	std	r5,last_task_used_math@l(r4)
+#endif /* CONFIG_SMP */
+	blr
+
+
+
+#ifdef CONFIG_SMP
+/*
+ * This function is called after the master CPU has released the
+ * secondary processors.  The execution environment is relocation off.
+ * The Paca for this processor has the following fields initialized at
+ * this point:
+ *   1. Processor number
+ *   2. Segment table pointer (virtual address)
+ * On entry the following are set:
+ *   r1    = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
+ *   r24   = cpu# (in Linux terms)
+ *   r25   = Paca virtual address
+ *   SPRG3 = Paca virtual address
+ */
+_GLOBAL(__secondary_start)
+
+	HMT_MEDIUM			/* Set thread priority to MEDIUM */
+
+	/* set up the TOC (virtual address) */
+	LOADADDR(r2,__toc_start)
+	addi    r2,r2,0x4000
+	addi    r2,r2,0x4000
+
+	std	r2,PACATOC(r25)
+	li	r6,0
+	std	r6,PACAKSAVE(r25)
+	stb	r6,PACAPROCENABLED(r25)
+
+#ifndef CONFIG_PPC_ISERIES
+	/* Initialize the page table pointer register. */
+	LOADADDR(r6,_SDR1)
+	ld	r6,0(r6)		/* get the value of _SDR1 */
+	mtspr	SDR1,r6			/* set the htab location  */
+#endif
+	/* Initialize the first segment table (or SLB) entry                */
+	ld	r3,PACASTABVIRT(r25)    /* get addr of segment table        */
+	bl	.stab_initialize
+
+	/* Initialize the kernel stack.  Just a repeat for iSeries.         */
+	LOADADDR(r3,current_set)
+	sldi	r28,r24,4		/* get current_set[cpu#] */
+	ldx	r13,r3,r28
+	std	r13,PACACURRENT(r25)
+	addi	r1,r13,TASK_UNION_SIZE
+	subi	r1,r1,STACK_FRAME_OVERHEAD
+
+	ld	r3,PACASTABREAL(r25)    /* get raddr of segment table       */
+	ori	r4,r3,1			/* turn on valid bit                */
+
+#ifdef CONFIG_PPC_ISERIES
+	li	r0,-1			/* hypervisor call */
+	li	r3,1
+	sldi	r3,r3,63		/* 0x8000000000000000 */
+	ori	r3,r3,4			/* 0x8000000000000004 */
+	sc				/* HvCall_setASR */
+#else
+	mtasr	r4			/* set the stab location            */
+#endif
+	li	r7,0
+	mtlr	r7
+
+	/* enable MMU and jump to start_secondary */
+	LOADADDR(r3,.start_secondary_prolog)
+	SET_REG_TO_CONST(r4, MSR_KERNEL)
+#ifdef DO_SOFT_DISABLE
+	ori	r4,r4,MSR_EE
+#endif
+	mtspr	SRR0,r3
+	mtspr	SRR1,r4
+	rfid
+#endif /* CONFIG_SMP */
+
+/* 
+ * Running with relocation on at this point.  All we want to do is
+ * zero the stack back-chain pointer before going into C code.
+ */
+_GLOBAL(start_secondary_prolog)
+	li	r3,0
+	std	r3,0(r1)                /* Zero the stack frame pointer     */
+	bl	.start_secondary
+
+/*
+ * This subroutine clobbers r11, r12 and the LR
+ */
+_GLOBAL(enable_64b_mode)
+	mfmsr   r11                      /* grab the current MSR */
+	li      r12,1
+	rldicr  r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
+	or      r11,r11,r12
+	li      r12,1
+	rldicr  r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
+	or      r11,r11,r12
+	mtmsrd  r11
+	isync
+	blr
+
+/*
+ * This subroutine clobbers r11, r12 and the LR
+ */
+_GLOBAL(enable_32b_mode)
+	mfmsr   r11                      /* grab the current MSR */
+	li      r12,1
+	rldicr  r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
+	andc	r11,r11,r12
+	li      r12,1
+	rldicr  r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
+	andc	r11,r11,r12
+	mtmsrd  r11
+	isync
+	blr
+
+
+/*
+ * This is where the main kernel code starts.
+ */
+_STATIC(start_here_pSeries)
+	/* get a new offset, now that the kernel has moved. */
+	bl	.reloc_offset
+	mr	r26,r3
+
+	/* setup the naca pointer which is needed by *tab_initialize       */
+	LOADADDR(r6,naca)
+	sub	r6,r6,r26                /* addr of the variable naca      */
+	li	r27,0x4000
+	std	r27,0(r6)	 	 /* set the value of naca          */
+
+#ifdef CONFIG_HMT
+	/* Start up the second thread on cpu 0 */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpwi	r3,0x34                 /* Pulsar  */
+	beq	90f
+	cmpwi	r3,0x36                 /* Icestar */
+	beq	90f
+	cmpwi	r3,0x37                 /* SStar   */
+	beq	90f
+	b	91f                     /* HMT not supported */
+90:	li      r3,0
+	bl	.hmt_start_secondary
+91:
+#endif
+
+#ifdef CONFIG_SMP
+	/* All secondary cpus are now spinning on a common
+	 * spinloop, release them all now so they can start
+	 * to spin on their individual Paca spinloops.
+	 * For non SMP kernels, the secondary cpus never
+	 * get out of the common spinloop.
+	 */
+	li	r3,1
+	LOADADDR(r5,__secondary_hold_spinloop)
+	tophys(r4,r5)
+	std     r3,0(r4)
+#endif
+
+	/* The following gets the stack and TOC set up with the regs */
+	/* pointing to the real addr of the kernel stack.  This is   */
+	/* all done to support the C function call below which sets  */
+	/* up the htab.  This is done because we have relocated the  */
+	/* kernel but are still running in real mode. */
+
+	/* real ptr to current */
+	LOADADDR(r3,init_task_union)
+	sub	r3,r3,r26
+
+	/* set up a stack pointer (physical address) */
+	addi	r1,r3,TASK_UNION_SIZE
+	li	r0,0
+	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
+
+	/* set up the TOC (physical address) */
+	LOADADDR(r2,__toc_start)
+	addi    r2,r2,0x4000
+	addi    r2,r2,0x4000
+	sub	r2,r2,r26
+
+	/* Init naca->debug_switch so it can be used in stab & htab init.  */
+	bl	.ppcdbg_initialize
+
+	/* Get the pointer to the segment table which is used by           */
+	/* stab_initialize                                                 */
+	li	r27,0x4000
+	ld	r6,PACA(r27)            /* Get the base Paca pointer       */
+	sub	r6,r6,r26		/* convert to physical addr         */
+	mtspr	SPRG3,r6		/* PPPBBB: Temp... -Peter */
+	ld	r3,PACASTABREAL(r6)
+	ori	r4,r3,1			/* turn on valid bit                */
+	mtasr	r4			/* set the stab location            */
+
+	/* Initialize an initial memory mapping and turn on relocation.   */
+	bl	.stab_initialize
+	bl	.htab_initialize
+
+	LOADADDR(r6,_SDR1)
+	sub	r6,r6,r26
+	ld	r6,0(r6)		/* get the value of _SDR1 */
+	mtspr	SDR1,r6			/* set the htab location  */
+
+	LOADADDR(r3,.start_here_common)
+	SET_REG_TO_CONST(r4, MSR_KERNEL)
+	mtspr	SRR0,r3
+	mtspr	SRR1,r4
+	rfid
+
+	/* This is where all platforms converge execution */
+_STATIC(start_here_common)
+	/* relocation is on at this point */
+
+	/* Clear out the BSS */
+	LOADADDR(r11,_end)
+
+	LOADADDR(r8,__bss_start)
+
+	sub	r11,r11,r8        /* bss size                        */
+	addi	r11,r11,7         /* round up to an even double word */
+	rldicl. r11,r11,61,3      /* shift right by 3                */
+	beq	4f
+	addi	r8,r8,-8
+	li	r0,0
+	mtctr	r11		  /* zero this many doublewords      */
+3:	stdu	r0,8(r8)
+	bdnz	3b
+4:
+
+	/* The following code sets up the SP and TOC now that we are */
+	/* running with translation enabled. */
+
+	/* ptr to current */
+	LOADADDR(r3,init_task_union)
+
+	/* set up the stack */
+	addi	r1,r3,TASK_UNION_SIZE
+	li	r0,0
+	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
+
+	/* set up the TOC */
+	LOADADDR(r2,__toc_start)
+	addi    r2,r2,0x4000
+	addi    r2,r2,0x4000
+
+	/* setup the naca pointer                                         */
+	LOADADDR(r9,naca)
+
+	SET_REG_TO_CONST(r8, KERNELBASE)
+	addi	r8,r8,0x4000
+	std	r8,0(r9)		/* set the value of the naca ptr  */
+
+	LOADADDR(r4,naca)               /* Get Naca ptr address           */
+	ld	r4,0(r4)                /* Get the location of the naca   */
+	ld	r4,PACA(r4)             /* Get the base Paca pointer      */
+	mtspr	SPRG3,r4
+
+	/* ptr to current */
+	LOADADDR(r13,init_task_union)
+	std	r13,PACACURRENT(r4)
+
+	std	r2,PACATOC(r4)
+	li	r5,0
+	std	r0,PACAKSAVE(r4)
+
+	/* ptr to hardware interrupt stack for processor 0                */
+	LOADADDR(r3, hardware_int_paca0)
+	li      r5,0x1000
+	sldi    r5,r5,3
+	subi    r5,r5,STACK_FRAME_OVERHEAD
+
+	add     r3,r3,r5
+	std     r3,PACAHRDWINTSTACK(r4)
+
+	li      r3,0
+	stb     r3,PACAHRDWINTCOUNT(r4)
+
+
+	/*
+	 * Restore the parms passed in from the bootloader.
+	 */
+	mr	r3,r31
+	mr	r4,r30
+	mr	r5,r29
+	mr	r6,r28
+	mr	r7,r27
+
+	bl	.setup_system
+
+	/* Load up the kernel context */
+5:
+#ifdef DO_SOFT_DISABLE
+	mfspr	r4,SPRG3
+	li	r5,0
+	stb	r5,PACAPROCENABLED(r4)	/* Soft Disabled */
+	mfmsr	r5
+	ori	r5,r5,MSR_EE		/* Hard Enabled */
+	mtmsrd	r5
+#endif
+
+	bl .start_kernel
+
+_GLOBAL(hmt_init)
+#ifdef CONFIG_HMT
+	LOADADDR(r5, hmt_thread_data)
+	mfspr	r7,PVR
+	srwi	r7,r7,16
+	cmpwi	r7,0x34                 /* Pulsar  */
+	beq	90f
+	cmpwi	r7,0x36                 /* Icestar */
+	beq	91f
+	cmpwi	r7,0x37                 /* SStar   */
+	beq	91f
+	b	101f
+90:	mfspr	r6,PIR
+	andi.	r6,r6,0x1f
+	b	92f
+91:	mfspr	r6,PIR
+	andi.	r6,r6,0x3ff
+92:	sldi	r4,r24,3
+	stwx	r6,r5,r4
+	bl	.hmt_start_secondary
+	b	101f
+
+__hmt_secondary_hold:
+	LOADADDR(r5, hmt_thread_data)
+	clrldi	r5,r5,4
+	li	r7,0
+	mfspr	r6,PIR
+	mfspr	r8,PVR
+	srwi	r8,r8,16
+	cmpwi	r8,0x34
+	bne	93f
+	andi.	r6,r6,0x1f
+	b	103f
+93:	andi.	r6,r6,0x3f
+
+103:	lwzx	r8,r5,r7
+	cmpw	r8,r6
+	beq	104f
+	addi	r7,r7,8
+	b	103b
+
+104:	addi	r7,r7,4
+	lwzx	r9,r5,r7
+	mr      r24,r9
+101:
+#endif
+	mr      r3,r24
+	b       .pseries_secondary_smp_init
+
+#ifdef CONFIG_HMT
+_GLOBAL(hmt_start_secondary)
+	LOADADDR(r4,__hmt_secondary_hold)
+	clrldi	r4,r4,4
+	mtspr   NIADORM, r4
+	mfspr   r4, MSRDORM
+	li      r5, -65
+	and     r4, r4, r5
+	mtspr   MSRDORM, r4
+	lis	r4,0xffef
+	ori	r4,r4,0x7403
+	mtspr	TSC, r4
+	li	r4,0x1f4
+	mtspr	TST, r4
+	mfspr   r4, HID0
+	ori     r4, r4, 0x1
+	mtspr   HID0, r4
+	mfspr   r4, CTRLF
+	oris    r4, r4, 0x40
+	mtspr   CTRLT, r4
+	blr
+#endif
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
+	.data
+	.align  12
+	.globl	sdata
+sdata:
+	.globl	empty_zero_page
+empty_zero_page:
+	.space	4096
+
+	.globl	swapper_pg_dir
+swapper_pg_dir:
+	.space	4096
+
+	.globl	ioremap_dir
+ioremap_dir:
+	.space	4096
+
+	.globl  hardware_int_paca0
+hardware_int_paca0:
+	.space	8*4096
+
+
+/* 4096 * 31 bytes of storage */
+	.globl	stab_array
+stab_array:
+	.space	131072
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * Used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+	.globl	cmd_line
+cmd_line:
+	.space	512
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/htab.c linux-2.4.19-pre5/arch/ppc64/kernel/htab.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/htab.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/htab.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,1230 @@
+/*
+ * 
+ *
+ * PowerPC64 port by Mike Corrigan and Dave Engebretsen
+ *   {mikejc|engebret}@us.ibm.com
+ *
+ *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
+ * 
+ *    Module name: htab.c
+ *
+ *    Description:
+ *      PowerPC Hashed Page Table functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/init.h>
+#include <asm/system.h>
+#include <asm/iSeries/LparData.h>
+#include <linux/spinlock.h>
+#include <asm/ppcdebug.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/sysctl.h>
+#include <linux/ctype.h>
+#include <linux/cache.h>
+#include <asm/uaccess.h>
+#include <asm/Naca.h>
+#include <asm/system.h>
+#include <asm/pmc.h>
+#include <asm/machdep.h>
+#include <asm/lmb.h>
+#ifdef CONFIG_PPC_EEH
+#include <asm/eeh.h>
+#endif
+
+/* For iSeries */
+#include <asm/iSeries/HvCallHpt.h>
+
+/* Note:  pte   --> Linux PTE
+ *        HPTE  --> PowerPC Hashed Page Table Entry
+ */
+
+HTAB htab_data = {NULL, 0, 0, 0, 0};
+
+int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
+		   void *buffer, size_t *lenp);
+
+void htab_initialize(void);
+void make_pte_LPAR(HPTE *htab,
+	      unsigned long va, unsigned long pa, int mode,
+	      unsigned long hash_mask, int large);
+
+extern unsigned long reloc_offset(void);
+extern unsigned long get_kernel_vsid( unsigned long ea );
+extern void cacheable_memzero( void *, unsigned int );
+
+extern unsigned long _SDR1;
+extern unsigned long klimit;
+extern struct Naca *naca;
+
+extern unsigned long _ASR;
+extern inline void make_ste(unsigned long stab,
+			    unsigned long esid, unsigned long vsid);
+
+extern char _stext[], _etext[], __start_naca[], __end_stab[];
+
+static spinlock_t hash_table_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) - offset))
+#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
+#define RELOC(x)	(*PTRRELOC(&(x)))
+
+extern unsigned long htab_size( unsigned long );
+unsigned long hpte_getword0_iSeries( unsigned long slot );
+
+#define KB (1024)
+#define MB (1024*KB)
+static inline void
+create_pte_mapping(unsigned long start, unsigned long end,
+		   unsigned long mode, unsigned long mask, int large)
+{
+	unsigned long addr, offset = reloc_offset();
+	HTAB *_htab_data = PTRRELOC(&htab_data);
+	HPTE  *htab  = (HPTE *)__v2a(_htab_data->htab);
+	unsigned int step;
+
+	if (large)
+		step = 16*MB;
+	else
+		step = 4*KB;
+
+	for (addr = start; addr < end; addr += step) {
+		unsigned long vsid = get_kernel_vsid(addr);
+		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
+		make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask,
+				large);
+	}
+}
+
+void
+htab_initialize(void)
+{
+	unsigned long table, htab_size_bytes;
+	unsigned long pteg_count;
+	unsigned long mode_ro, mode_rw, mask;
+	unsigned long offset = reloc_offset();
+	struct Naca *_naca = RELOC(naca);
+	HTAB *_htab_data = PTRRELOC(&htab_data);
+
+	/*
+	 * Calculate the required size of the htab.  We want the number of
+	 * PTEGs to equal one half the number of real pages.
+	 */ 
+	htab_size_bytes = 1UL << _naca->pftSize;
+	pteg_count = htab_size_bytes >> 7;
+
+	/* For debug, make the HTAB 1/8 as big as it normally would be. */
+	ifppcdebug(PPCDBG_HTABSIZE) {
+		pteg_count >>= 3;
+		htab_size_bytes = pteg_count << 7;
+	}
+
+	_htab_data->htab_num_ptegs = pteg_count;
+	_htab_data->htab_hash_mask = pteg_count - 1;
+
+	if(_machine == _MACH_pSeries) {
+		/* Find storage for the HPT.  Must be contiguous in
+		 * the absolute address space.
+		 */
+		table = lmb_alloc(htab_size_bytes, htab_size_bytes);
+		if ( !table )
+			panic("ERROR, cannot find space for HPTE\n");
+		_htab_data->htab = (HPTE *)__a2v(table);
+
+		/* htab absolute addr + encoded htabsize */
+		RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
+
+		/* Initialize the HPT with no entries */
+		cacheable_memzero((void *)table, htab_size_bytes);
+	} else {
+		_htab_data->htab = NULL;
+		RELOC(_SDR1) = 0; 
+	}
+
+	mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX;
+	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
+	mask = pteg_count-1;
+
+	/* Create PTE's for the kernel text and data sections plus
+	 * the HPT and HPTX arrays.  Make the assumption that
+	 * (addr & KERNELBASE) == 0 (ie they are disjoint).
+	 * We also assume that the va is <= 64 bits.
+	 */
+#if 0
+	create_pte_mapping((unsigned long)_stext,       (unsigned long)__start_naca,                 mode_ro, mask);
+	create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab,                   mode_rw, mask);
+	create_pte_mapping((unsigned long)__end_stab,   (unsigned long)_etext,                       mode_ro, mask);
+	create_pte_mapping((unsigned long)_etext,       RELOC(klimit),                               mode_rw, mask);
+	create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask);
+#else
+#ifndef CONFIG_PPC_ISERIES
+	if (__is_processor(PV_POWER4) && _naca->physicalMemorySize > 256*MB) {
+		create_pte_mapping((unsigned long)KERNELBASE, 
+				   KERNELBASE + 256*MB, mode_rw, mask, 0);
+		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
+				   KERNELBASE + (_naca->physicalMemorySize), 
+				   mode_rw, mask, 1);
+		return;
+	}
+#endif
+	create_pte_mapping((unsigned long)KERNELBASE, 
+			   KERNELBASE+(_naca->physicalMemorySize), 
+			   mode_rw, mask, 0);
+#endif
+}
+#undef KB
+#undef MB
+
+/*
+ * Create a pte.  Used during initialization only.
+ * We assume the PTE will fit in the primary PTEG.
+ */
+void make_pte(HPTE *htab,
+	      unsigned long va, unsigned long pa, int mode,
+	      unsigned long hash_mask, int large)
+{
+	HPTE  *hptep;
+	unsigned long hash, i;
+	volatile unsigned long x = 1;
+	unsigned long vpn;
+
+#ifdef CONFIG_PPC_PSERIES
+	if(_machine == _MACH_pSeriesLP) {
+		make_pte_LPAR(htab, va, pa, mode, hash_mask, large); 
+		return;
+	}
+#endif
+
+	if (large)
+		vpn = va >> 24;
+	else
+		vpn = va >> 12;
+
+	hash = hpt_hash(vpn, large);
+
+	hptep  = htab +  ((hash & hash_mask)*HPTES_PER_GROUP);
+
+	for (i = 0; i < 8; ++i, ++hptep) {
+		if ( hptep->dw0.dw0.v == 0 ) {		/* !valid */
+			hptep->dw1.dword1 = pa | mode;
+			hptep->dw0.dword0 = 0;
+			hptep->dw0.dw0.avpn = va >> 23;
+			hptep->dw0.dw0.bolted = 1;	/* bolted */
+			hptep->dw0.dw0.v = 1;		/* make valid */
+			return;
+		}
+	}
+
+	/* We should _never_ get here and too early to call xmon. */
+	for(;x;x|=1);
+}
+
+/* Functions to invalidate a HPTE */
+static void hpte_invalidate_iSeries( unsigned long slot )
+{
+	HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );
+}
+
+static void hpte_invalidate_pSeries( unsigned long slot )
+{
+	/* Local copy of the first doubleword of the HPTE */
+	union {
+		unsigned long d;
+		Hpte_dword0   h;
+	} hpte_dw0;
+
+	/* Locate the HPTE */
+	HPTE  * hptep  = htab_data.htab  + slot;
+
+	/* Get the first doubleword of the HPTE */
+	hpte_dw0.d = hptep->dw0.dword0;
+
+	/* Invalidate the hpte */
+	hptep->dw0.dword0 = 0;
+
+	/* Invalidate the tlb   */
+	{
+		unsigned long vsid, group, pi, pi_high;
+
+		vsid = hpte_dw0.h.avpn >> 5;
+		group = slot >> 3;
+		if(hpte_dw0.h.h) {
+			group = ~group;
+		} 
+		pi = (vsid ^ group) & 0x7ff;
+		pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;
+		pi |= pi_high;
+		_tlbie(pi << 12);
+	}
+}
+
+
+/* Select an available HPT slot for a new HPTE
+ *   return slot index (if in primary group)
+ *   return -slot index (if in secondary group) 
+ */
+static long hpte_selectslot_iSeries( unsigned long vpn )
+{
+	HPTE hpte;
+	long ret_slot, orig_slot;
+	unsigned long primary_hash;
+	unsigned long hpteg_slot;
+	unsigned long slot;
+	unsigned i, k;
+	union {
+		unsigned long	d;
+		Hpte_dword0	h;
+	} hpte_dw0;
+
+	ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );
+	if ( hpte.dw0.dw0.v ) {		/* If valid ...what do we do now? */
+		udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );
+		udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );
+
+		return (0x8000000000000000); 
+		/*			panic("select_hpte_slot found entry already valid\n"); */
+	}
+	if ( ret_slot == -1 ) {		/* -1 indicates no available slots */
+
+		/* No available entry found in secondary group */
+
+		PMC_SW_SYSTEM(htab_capacity_castouts);
+
+		primary_hash = hpt_hash(vpn, 0);
+		hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+		k = htab_data.next_round_robin++ & 0x7;
+
+		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
+			if ( k == HPTES_PER_GROUP )
+				k = 0;
+			slot = hpteg_slot + k;
+			hpte_dw0.d = hpte_getword0_iSeries( slot );
+			if ( !hpte_dw0.h.bolted ) {
+				hpte_invalidate_iSeries( slot );
+				ret_slot = slot;
+			}
+			++k;
+		}
+	} else {
+		if ( ret_slot < 0 ) {
+			PMC_SW_SYSTEM(htab_primary_overflows);
+			ret_slot &= 0x7fffffffffffffff;
+			ret_slot = -ret_slot;
+		}
+	}
+	if ( ret_slot == -1 ) {
+		/* No non-bolted entry found in primary group - time to panic */
+        	udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
+        	panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+	}
+	PPCDBG(PPCDBG_MM, "hpte_selectslot_iSeries: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",
+	       vpn, orig_slot, ret_slot );	
+	return ret_slot;
+}
+
+static long hpte_selectslot_pSeries(unsigned long vpn)
+{
+	HPTE * hptep;
+	unsigned long primary_hash;
+	unsigned long hpteg_slot;
+	unsigned i, k;
+
+	/* Search the primary group for an available slot */
+
+	primary_hash = hpt_hash(vpn, 0);
+	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+	hptep = htab_data.htab + hpteg_slot;
+	
+	for (i=0; i<HPTES_PER_GROUP; ++i) {
+		if ( hptep->dw0.dw0.v == 0 ) {
+			/* If an available slot found, return it */
+			return hpteg_slot + i;
+		}
+		hptep++;
+	}
+
+	/* No available entry found in primary group */
+
+	PMC_SW_SYSTEM(htab_primary_overflows);
+
+	/* Search the secondary group */
+
+	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+	hptep = htab_data.htab + hpteg_slot;
+
+	for (i=0; i<HPTES_PER_GROUP; ++i) {
+		if ( hptep->dw0.dw0.v == 0 ) {
+			/* If an available slot found, return it */
+			return -(hpteg_slot + i);
+		}
+		hptep++;
+	}
+
+	/* No available entry found in secondary group */
+
+	PMC_SW_SYSTEM(htab_capacity_castouts);
+
+	/* Select an entry in the primary group to replace */
+
+	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+	hptep = htab_data.htab + hpteg_slot;
+	k = htab_data.next_round_robin++ & 0x7;
+
+	for (i=0; i<HPTES_PER_GROUP; ++i) {
+		if (k == HPTES_PER_GROUP)
+			k = 0;
+
+		if (!hptep[k].dw0.dw0.bolted) {
+			hpteg_slot += k;
+			/* Invalidate the current entry */
+			ppc_md.hpte_invalidate(hpteg_slot); 
+			return hpteg_slot;
+		}
+		++k;
+	}
+
+	/* No non-bolted entry found in primary group - time to panic */
+        udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
+	/*      xmon(0); */
+        panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+
+	/* keep the compiler happy */
+	return 0;
+}
+
+unsigned long hpte_getword0_iSeries( unsigned long slot )
+{
+	unsigned long dword0;
+
+	HPTE hpte;
+	HvCallHpt_get( &hpte, slot );
+	dword0 = hpte.dw0.dword0;
+
+	return dword0;
+}
+
+unsigned long hpte_getword0_pSeries( unsigned long slot )
+{
+	unsigned long dword0;
+	HPTE * hptep = htab_data.htab + slot;
+
+	dword0 = hptep->dw0.dword0;
+	return dword0;
+}
+
+static long hpte_find_iSeries(unsigned long vpn)
+{
+	HPTE hpte;
+	long slot;
+
+	slot = HvCallHpt_findValid( &hpte, vpn );
+	if ( hpte.dw0.dw0.v ) {
+		if ( slot < 0 ) {
+			slot &= 0x7fffffffffffffff;
+			slot = -slot;
+		}
+	} else
+		slot = -1;
+	return slot;
+}
+
+static long hpte_find_pSeries(unsigned long vpn)
+{
+	union {
+		unsigned long d;
+		Hpte_dword0   h;
+	} hpte_dw0;
+	long slot;
+	unsigned long hash;
+	unsigned long i,j;
+
+	hash = hpt_hash(vpn, 0);
+	for ( j=0; j<2; ++j ) {
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
+			hpte_dw0.d = hpte_getword0_pSeries( slot );
+			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
+			     ( hpte_dw0.h.v ) &&
+			     ( hpte_dw0.h.h == j ) ) {
+				/* HPTE matches */
+				if ( j )
+					slot = -slot;
+				return slot;
+			}
+			++slot;
+		}
+		hash = ~hash;
+	}
+	return -1;
+} 
+
+/* This function is called by iSeries setup when initializing the hpt */
+void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
+		       pte_t * ptep, unsigned hpteflags, unsigned bolted )
+{
+	unsigned long vpn, flags;
+	long hpte_slot;
+	unsigned hash;
+	pte_t pte;
+
+	vpn = ((vsid << 28) | ( ea & 0xffff000 )) >> 12;
+
+	spin_lock_irqsave( &hash_table_lock, flags );
+
+	hpte_slot = ppc_md.hpte_selectslot( vpn );
+	hash = 0;
+	if ( hpte_slot < 0 ) {
+		if ( hpte_slot == 0x8000000000000000 ) {
+			udbg_printf("hash_page: ptep    = 0x%016lx\n", 
+				    (unsigned long)ptep );
+			udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
+			udbg_printf("hash_page: vpn     = 0x%016lx\n", vpn );
+               
+			panic("hash_page: hpte already exists\n");
+		}
+		hash = 1;
+		hpte_slot = -hpte_slot;
+	}
+	ppc_md.hpte_create_valid( hpte_slot, vpn, pa >> 12, hash, ptep,
+				  hpteflags, bolted );
+
+	if ( ptep ) {
+		/* Get existing pte flags */
+		pte = *ptep;
+		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
+
+		/* Add in the has hpte flag */
+		pte_val(pte) |= _PAGE_HASHPTE;
+
+		/* Add in the _PAGE_SECONDARY flag */
+		pte_val(pte) |= hash << 15;
+
+		/* Add in the hpte slot */
+		pte_val(pte) |= (hpte_slot << 12) & _PAGE_GROUP_IX;
+               
+		/* Save the new pte.  */
+		*ptep = pte;
+               
+	}
+	spin_unlock_irqrestore( &hash_table_lock, flags );
+}
+
+
+/* Create an HPTE and validate it
+ *   It is assumed that the HPT slot currently is invalid.
+ *   The HPTE is set with the vpn, rpn (converted to absolute)
+ *   and flags
+ */
+static void hpte_create_valid_iSeries(unsigned long slot, unsigned long vpn,
+				      unsigned long prpn, unsigned hash, 
+				      void * ptep, unsigned hpteflags, 
+				      unsigned bolted )
+{
+	/* Local copy of HPTE */
+	struct {
+		/* Local copy of first doubleword of HPTE */
+		union {
+			unsigned long d;
+			Hpte_dword0   h;
+		} dw0;
+		/* Local copy of second doubleword of HPTE */
+		union {
+			unsigned long     d;
+			Hpte_dword1       h;
+			Hpte_dword1_flags f;
+		} dw1;
+	} lhpte;
+	
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn( prpn );
+
+	/* Fill in the local HPTE with absolute rpn, avpn and flags */
+	lhpte.dw1.d        = 0;
+	lhpte.dw1.h.rpn    = arpn;
+	lhpte.dw1.f.flags  = hpteflags;
+
+	lhpte.dw0.d        = 0;
+	lhpte.dw0.h.avpn   = avpn;
+	lhpte.dw0.h.h      = hash;
+	lhpte.dw0.h.bolted = bolted;
+	lhpte.dw0.h.v      = 1;
+
+	/* Now fill in the actual HPTE */
+	HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte );
+}
+
+static void hpte_create_valid_pSeries(unsigned long slot, unsigned long vpn,
+				      unsigned long prpn, unsigned hash, 
+				      void * ptep, unsigned hpteflags, 
+				      unsigned bolted)
+{
+	/* Local copy of HPTE */
+	struct {
+		/* Local copy of first doubleword of HPTE */
+		union {
+			unsigned long d;
+			Hpte_dword0   h;
+		} dw0;
+		/* Local copy of second doubleword of HPTE */
+		union {
+			unsigned long     d;
+			Hpte_dword1       h;
+			Hpte_dword1_flags f;
+		} dw1;
+	} lhpte;
+	
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn( prpn );
+
+	HPTE *hptep;
+
+	/* Fill in the local HPTE with absolute rpn, avpn and flags */
+	lhpte.dw1.d        = 0;
+	lhpte.dw1.h.rpn    = arpn;
+	lhpte.dw1.f.flags  = hpteflags;
+
+	lhpte.dw0.d        = 0;
+	lhpte.dw0.h.avpn   = avpn;
+	lhpte.dw0.h.h      = hash;
+	lhpte.dw0.h.bolted = bolted;
+	lhpte.dw0.h.v      = 1;
+
+	/* Now fill in the actual HPTE */
+	hptep  = htab_data.htab  + slot;
+
+	/* Set the second dword first so that the valid bit
+	 * is the last thing set
+	 */
+	
+	hptep->dw1.dword1 = lhpte.dw1.d;
+
+	/* Guarantee the second dword is visible before
+	 * the valid bit
+	 */
+	
+	__asm__ __volatile__ ("eieio" : : : "memory");
+
+	/* Now set the first dword including the valid bit */
+	hptep->dw0.dword0 = lhpte.dw0.d;
+
+	__asm__ __volatile__ ("ptesync" : : : "memory");
+}
+
+/* find_linux_pte returns the address of a linux pte for a given 
+ * effective address and directory.  If not found, it returns zero.
+ */
+
+pte_t  * find_linux_pte( pgd_t * pgdir, unsigned long ea )
+{
+	pgd_t *pg;
+	pmd_t *pm;
+	pte_t *pt = NULL;
+	pte_t pte;
+	pg = pgdir + pgd_index( ea );
+	if ( ! pgd_none( *pg ) ) {
+
+		pm = pmd_offset( pg, ea );
+		if ( ! pmd_none( *pm ) ) { 
+			pt = pte_offset( pm, ea );
+			pte = *pt;
+			if ( ! pte_present( pte ) )
+				pt = NULL;
+		}
+	}
+
+	return pt;
+
+}
+
+static inline unsigned long computeHptePP( unsigned long pte )
+{
+	return (     pte & _PAGE_USER )           |
+		( ( ( pte & _PAGE_USER )    >> 1 ) &
+		  ( ( ~( ( pte >> 2 ) &		/* _PAGE_RW */
+		         ( pte >> 7 ) ) ) &     /* _PAGE_DIRTY */
+			 1 ) );
+}
+
+static void hpte_updatepp_iSeries(long slot, unsigned long newpp, unsigned long va)
+{
+	HvCallHpt_setPp( slot, newpp );
+}
+
+static void hpte_updatepp_pSeries(long slot, unsigned long newpp, unsigned long va)
+{
+	/* Local copy of first doubleword of HPTE */
+	union {
+		unsigned long d;
+		Hpte_dword0   h;
+	} hpte_dw0;
+	
+	/* Local copy of second doubleword of HPTE */
+	union {
+		unsigned long     d;
+		Hpte_dword1       h;
+		Hpte_dword1_flags f;
+	} hpte_dw1;	
+
+	HPTE *  hptep  = htab_data.htab  + slot;
+
+	/* Turn off valid bit in HPTE */
+	hpte_dw0.d = hptep->dw0.dword0;
+	hpte_dw0.h.v = 0;
+	hptep->dw0.dword0 = hpte_dw0.d;
+
+	/* Ensure it is out of the tlb too */
+	_tlbie( va );
+
+	/* Insert the new pp bits into the HPTE */
+	hpte_dw1.d = hptep->dw1.dword1;
+	hpte_dw1.h.pp = newpp;
+	hptep->dw1.dword1 = hpte_dw1.d;
+
+	/* Ensure it is visible before validating */
+	__asm__ __volatile__ ("eieio" : : : "memory");
+
+	/* Turn the valid bit back on in HPTE */
+	hpte_dw0.h.v = 1;
+	hptep->dw0.dword0 = hpte_dw0.d;
+
+	__asm__ __volatile__ ("ptesync" : : : "memory");
+}
+
+/*
+ * Update the page protection bits.  Intended to be used to create
+ * guard pages for kernel data structures on pages which are bolted
+ * in the HPT.  Assumes pages being operated on will not be stolen. 
+ */
+void hpte_updateboltedpp_iSeries(unsigned long newpp, unsigned long ea )
+{
+	unsigned long vsid,va,vpn;
+	long slot;
+
+	vsid = get_kernel_vsid( ea );
+	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+	vpn = va >> PAGE_SHIFT;
+
+	slot = ppc_md.hpte_find( vpn );
+	HvCallHpt_setPp( slot, newpp );
+}
+
+
+static __inline__ void set_pp_bit(unsigned long  pp, HPTE *addr)
+{
+	unsigned long old;
+	unsigned long *p = (unsigned long *)(&(addr->dw1));
+
+	__asm__ __volatile__(
+        "1:	ldarx	%0,0,%3\n\
+                rldimi  %0,%2,0,62\n\
+                stdcx.	%0,0,%3\n\
+            	bne	1b"
+        : "=&r" (old), "=m" (*p)
+        : "r" (pp), "r" (p), "m" (*p)
+        : "cc");
+}
+
+/*
+ * Update the page protection bits.  Intended to be used to create
+ * guard pages for kernel data structures on pages which are bolted
+ * in the HPT.  Assumes pages being operated on will not be stolen. 
+ */
+void hpte_updateboltedpp_pSeries(unsigned long newpp, unsigned long ea)
+{
+	unsigned long vsid,va,vpn,flags;
+	long slot;
+	HPTE *hptep;
+
+	vsid = get_kernel_vsid( ea );
+	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+	vpn = va >> PAGE_SHIFT;
+
+	slot = ppc_md.hpte_find( vpn );
+	hptep = htab_data.htab  + slot;
+
+	set_pp_bit(newpp , hptep);
+
+	/* Ensure it is out of the tlb too */
+	spin_lock_irqsave( &hash_table_lock, flags );
+	_tlbie( va );
+	spin_unlock_irqrestore( &hash_table_lock, flags );
+}
+
+
+
+/* This is called very early. */
+void hpte_init_iSeries(void)
+{
+	ppc_md.hpte_invalidate   = hpte_invalidate_iSeries;
+	ppc_md.hpte_updatepp     = hpte_updatepp_iSeries;
+	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_iSeries;
+	ppc_md.hpte_getword0     = hpte_getword0_iSeries;
+	ppc_md.hpte_selectslot   = hpte_selectslot_iSeries;
+	ppc_md.hpte_create_valid = hpte_create_valid_iSeries;
+	ppc_md.hpte_find	 = hpte_find_iSeries;
+}
+void hpte_init_pSeries(void)
+{
+	ppc_md.hpte_invalidate   = hpte_invalidate_pSeries;
+	ppc_md.hpte_updatepp     = hpte_updatepp_pSeries;
+	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeries;
+	ppc_md.hpte_getword0     = hpte_getword0_pSeries;
+	ppc_md.hpte_selectslot   = hpte_selectslot_pSeries;
+	ppc_md.hpte_create_valid = hpte_create_valid_pSeries;
+	ppc_md.hpte_find	 = hpte_find_pSeries;
+}
+
+/* Handle a fault by adding an HPTE 
+ * If the address can't be determined to be valid
+ * via Linux page tables, return 1.  If handled
+ * return 0
+ */
+int hash_page( unsigned long ea, unsigned long access )
+{
+	int rc = 1;
+	void * pgdir = NULL;
+	unsigned long va, vsid, vpn;
+	unsigned long newpp, hash_ind, prpn;
+	unsigned long hpteflags, regionid;
+	long slot;
+	struct mm_struct * mm;
+	pte_t old_pte, new_pte, *ptep;
+
+	/* Check for invalid addresses. */
+	if (!IS_VALID_EA(ea)) {
+		return 1;
+	}
+
+	regionid =  REGION_ID(ea);
+	switch ( regionid ) {
+	case USER_REGION_ID:
+		mm = current->mm;
+		if ( mm == NULL ) {
+			PPCDBG(PPCDBG_MM, "hash_page returning; mm = 0\n"); 
+			return 1;
+		}
+		vsid = get_vsid(mm->context, ea );
+		break;
+	case IO_REGION_ID:
+		mm = &ioremap_mm;
+		vsid = get_kernel_vsid( ea );
+		break;
+	case VMALLOC_REGION_ID:
+		mm = &init_mm;
+		vsid = get_kernel_vsid( ea );
+		break;
+#ifdef CONFIG_PPC_EEH
+	case IO_UNMAPPED_REGION_ID:
+		udbg_printf("EEH Error ea = 0x%lx\n", ea);
+ 		PPCDBG_ENTER_DEBUGGER();
+		panic("EEH Error ea = 0x%lx\n", ea);
+		break;
+#endif
+	case KERNEL_REGION_ID:
+		/* As htab_initialize is now, we shouldn't ever get here since
+		 * we're bolting the entire 0xC0... region.
+		 */
+		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
+ 		PPCDBG_ENTER_DEBUGGER();
+		panic("Little faulted on kernel address 0x%lx\n", ea);
+		break;
+	default:
+		/* Not a valid range, send the problem up to do_page_fault */
+		return 1;
+		break;
+	}
+
+	/* Search the Linux page table for a match with va */
+        va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+	vpn = va >> PAGE_SHIFT;
+	pgdir = mm->pgd;
+	PPCDBG(PPCDBG_MM, "hash_page ea = 0x%16.16lx, va = 0x%16.16lx\n          current = 0x%16.16lx, access = %lx\n", ea, va, current, access); 
+                if ( pgdir == NULL ) {
+                return 1;
+	}
+	
+	/* Lock the Linux page table to prevent mmap and kswapd
+	 * from modifying entries while we search and update
+	 */
+	
+	spin_lock( &mm->page_table_lock );
+	
+	ptep = find_linux_pte( pgdir, ea );
+	/* If no pte found, send the problem up to do_page_fault */
+	if ( ! ptep ) {
+	  spin_unlock( &mm->page_table_lock );
+	  return 1;
+	}
+	
+	/* Acquire the hash table lock to guarantee that the linux
+	 * pte we fetch will not change
+	 */
+	spin_lock( &hash_table_lock );
+	
+	old_pte = *ptep;
+	
+	/* If the pte is not "present" (valid), send the problem
+	 * up to do_page_fault.
+	 */
+	if ( ! pte_present( old_pte ) ) {
+	  spin_unlock( &hash_table_lock );
+	  spin_unlock( &mm->page_table_lock );
+	  return 1;
+	}
+	
+	/* At this point we have found a pte (which was present).
+	 * The spinlocks prevent this status from changing
+	 * The hash_table_lock prevents the _PAGE_HASHPTE status
+	 * from changing (RPN, DIRTY and ACCESSED too)
+	 * The page_table_lock prevents the pte from being 
+	 * invalidated or modified
+	 */
+
+/* At this point, we have a pte (old_pte) which can be used to build or update
+ * an HPTE.   There are 5 cases:
+ *
+ * 1. There is a valid (present) pte with no associated HPTE (this is 
+ *	the most common case)
+ * 2. There is a valid (present) pte with an associated HPTE.  The
+ *	current values of the pp bits in the HPTE prevent access because the
+ *	user doesn't have appropriate access rights.
+ * 3. There is a valid (present) pte with an associated HPTE.  The
+ *	current values of the pp bits in the HPTE prevent access because we are
+ *	doing software DIRTY bit management and the page is currently not DIRTY. 
+ * 4. This is a Kernel address (0xC---) for which there is no page directory.
+ *	There is an HPTE for this page, but the pp bits prevent access.
+ *      Since we always set up kernel pages with R/W access for the kernel
+ *	this case only comes about for users trying to access the kernel.
+ *	This case is always an error and is not dealt with further here.
+ * 5. This is a Kernel address (0xC---) for which there is no page directory.
+ *	There is no HPTE for this page.
+
+ * Check the user's access rights to the page.  If access should be prevented
+ * then send the problem up to do_page_fault.
+ */
+
+	access |= _PAGE_PRESENT;
+	if ( 0 == ( access & ~(pte_val(old_pte)) ) ) {
+		/*
+		 * Check if pte might have an hpte, but we have
+		 * no slot information
+		 */
+		if ( pte_val(old_pte) & _PAGE_HPTENOIX ) {
+			unsigned long slot;	
+			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
+			slot = ppc_md.hpte_find( vpn );
+			if ( slot != -1 ) {
+				if ( slot < 0 ) {
+					pte_val(old_pte) |= _PAGE_SECONDARY;
+					slot = -slot;
+				}
+				pte_val(old_pte) |= ((slot << 12) & _PAGE_GROUP_IX) | _PAGE_HASHPTE;
+				
+			}
+		}
+
+		/* User has appropriate access rights. */
+		new_pte = old_pte;
+		/* If the attempted access was a store */
+		if ( access & _PAGE_RW )
+			pte_val(new_pte) |= _PAGE_ACCESSED |
+				_PAGE_DIRTY;
+		else
+			pte_val(new_pte) |= _PAGE_ACCESSED;
+
+		/* Only cases 1, 3 and 5 still in play */
+
+		newpp = computeHptePP( pte_val(new_pte) );
+
+		/* Check if pte already has an hpte (case 3) */
+		if ( pte_val(old_pte) & _PAGE_HASHPTE ) {
+			/* There MIGHT be an HPTE for this pte */
+			unsigned long hash, slot, secondary;
+			/* Local copy of first doubleword of HPTE */
+			union {
+				unsigned long d;
+				Hpte_dword0   h;
+			} hpte_dw0;
+			hash = hpt_hash(vpn, 0);
+			secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
+			if ( secondary )
+				hash = ~hash;
+			slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+			slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
+			/* If there is an HPTE for this page it is indexed by slot */
+			hpte_dw0.d = ppc_md.hpte_getword0( slot );
+			if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
+			     (hpte_dw0.h.v) && 
+			     (hpte_dw0.h.h == secondary ) ){
+				/* HPTE matches */
+				ppc_md.hpte_updatepp( slot, newpp, va );
+				if ( !pte_same( old_pte, new_pte ) )
+					*ptep = new_pte;
+			}
+			else {
+				/* HPTE is not for this pte */
+				pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
+			}
+		}
+		if ( !( pte_val(old_pte) & _PAGE_HASHPTE ) ) {
+			/* Cases 1 and 5 */
+			/* For these cases we need to create a new
+			 * HPTE and update the linux pte (for
+			 * case 1).  For case 5 there is no linux pte.
+			 *
+			 * Find an available HPTE slot
+ 			 */
+			slot = ppc_md.hpte_selectslot( vpn );
+
+			/* Debug code */
+			if ( slot == 0x8000000000000000 ) {
+				unsigned long xold_pte = pte_val(old_pte);
+				unsigned long xnew_pte = pte_val(new_pte);
+				
+				udbg_printf("hash_page: ptep    = 0x%016lx\n", (unsigned long)ptep );
+				udbg_printf("hash_page: old_pte = 0x%016lx\n", xold_pte );
+				udbg_printf("hash_page: new_pte = 0x%016lx\n", xnew_pte );
+				udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
+				udbg_printf("hash_page: va      = 0x%016lx\n", va );
+				udbg_printf("hash_page: access  = 0x%016lx\n", access );
+			
+				panic("hash_page: hpte already exists\n");
+			}
+
+			hash_ind = 0;
+			if ( slot < 0 ) {
+				slot = -slot;
+				hash_ind = 1;
+			}
+
+			/* Set the physical address */
+			prpn = pte_val(old_pte) >> PTE_SHIFT;
+			
+			if ( ptep ) {
+				/* Update the linux pte with the HPTE slot */
+				pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
+				pte_val(new_pte) |= hash_ind << 15;
+				pte_val(new_pte) |= (slot<<12) & _PAGE_GROUP_IX;
+				pte_val(new_pte) |= _PAGE_HASHPTE;
+				/* No need to use ldarx/stdcx here because all
+				 * who might be updating the pte will hold the page_table_lock
+				 * or the hash_table_lock (we hold both)
+				 */
+				*ptep = new_pte;
+			}
+
+			/* copy appropriate flags from linux pte */
+			hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
+
+			/* Create the HPTE */
+			ppc_md.hpte_create_valid( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 ); 
+
+		}
+
+		/* Indicate success */
+		rc = 0;
+	}		
+	
+	spin_unlock( &hash_table_lock );
+	if (ptep)
+		spin_unlock( &mm->page_table_lock );
+
+	return rc;
+}
+
+void flush_hash_page( unsigned long context, unsigned long ea, pte_t pte )
+{
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
+	/* Local copy of first doubleword of HPTE */
+	union {
+		unsigned long d;
+		Hpte_dword0   h;
+	} hpte_dw0;
+
+	if ( (ea >= USER_START ) && ( ea <= USER_END ) )
+		vsid = get_vsid( context, ea );
+	else
+		vsid = get_kernel_vsid( ea );
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
+	hash = hpt_hash(vpn, 0);
+	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
+	if ( secondary )
+		hash = ~hash;
+	slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+	slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12;
+	/* If there is an HPTE for this page it is indexed by slot */
+
+	spin_lock_irqsave( &hash_table_lock, flags);
+	hpte_dw0.d = ppc_md.hpte_getword0( slot );
+	if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
+	     (hpte_dw0.h.v) && 
+	     (hpte_dw0.h.h == secondary ) ){
+		/* HPTE matches */
+		ppc_md.hpte_invalidate( slot );	
+	}
+	else {
+		unsigned k;
+		/* Temporarily lets check for the hpte in all possible slots */
+		for ( secondary = 0; secondary < 2; ++secondary ) {
+			hash = hpt_hash(vpn, 0);
+			if ( secondary )
+				hash = ~hash;
+			slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+			for ( k=0; k<8; ++k ) {
+				hpte_dw0.d = ppc_md.hpte_getword0( slot+k );
+				if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) &&
+				     ( hpte_dw0.h.v ) &&
+				     ( hpte_dw0.h.h == secondary ) ) {
+					while (1) ;
+				}
+			}
+		}
+		
+	}
+	spin_unlock_irqrestore( &hash_table_lock, flags );
+}
+
+int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
+		   void *buffer, size_t *lenp)
+{
+	int vleft, first=1, len, left, val;
+#define TMPBUFLEN 256
+	char buf[TMPBUFLEN], *p;
+	static const char *sizestrings[4] = {
+		"2MB", "256KB", "512KB", "1MB"
+	};
+	static const char *clockstrings[8] = {
+		"clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
+		"+2 clock", "+2.5 clock", "+3 clock", "reserved(7)"
+	};
+	static const char *typestrings[4] = {
+		"flow-through burst SRAM", "reserved SRAM",
+		"pipelined burst SRAM", "pipelined late-write SRAM"
+	};
+	static const char *holdstrings[4] = {
+		"0.5", "1.0", "(reserved2)", "(reserved3)"
+	};
+
+	if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
+		return -EFAULT;
+	
+	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
+		*lenp = 0;
+		return 0;
+	}
+	
+	vleft = table->maxlen / sizeof(int);
+	left = *lenp;
+	
+	for (; left /*&& vleft--*/; first=0) {
+		if (write) {
+			while (left) {
+				char c;
+				if(get_user(c,(char *) buffer))
+					return -EFAULT;
+				if (!isspace(c))
+					break;
+				left--;
+				((char *) buffer)++;
+			}
+			if (!left)
+				break;
+			len = left;
+			if (len > TMPBUFLEN-1)
+				len = TMPBUFLEN-1;
+			if(copy_from_user(buf, buffer, len))
+				return -EFAULT;
+			buf[len] = 0;
+			p = buf;
+			if (*p < '0' || *p > '9')
+				break;
+			val = simple_strtoul(p, &p, 0);
+			len = p-buf;
+			if ((len < left) && *p && !isspace(*p))
+				break;
+			buffer += len;
+			left -= len;
+#if 0
+			/* DRENG need a def */
+			_set_L2CR(0);
+			_set_L2CR(val);
+			while ( _get_L2CR() & 0x1 )
+				/* wait for invalidate to finish */;
+#endif
+			  
+		} else {
+			p = buf;
+			if (!first)
+				*p++ = '\t';
+#if 0
+			/* DRENG need a def */
+			val = _get_L2CR();
+#endif
+			p += sprintf(p, "0x%08x: ", val);
+			p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" :
+				     "disabled");
+			p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no ");
+			p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]);
+			p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]);
+			p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]);
+			p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : "");
+			p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": "");
+			p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" :
+				     "copy-back");
+			p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : "");
+			p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]);
+			p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : "");
+			p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :"");
+			p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :"");
+			
+			p += sprintf(p,"\n");
+			
+			len = strlen(buf);
+			if (len > left)
+				len = left;
+			if(copy_to_user(buffer, buf, len))
+				return -EFAULT;
+			left -= len;
+			buffer += len;
+			break;
+		}
+	}
+
+	if (!write && !first && left) {
+		if(put_user('\n', (char *) buffer))
+			return -EFAULT;
+		left--, buffer++;
+	}
+	if (write) {
+		p = (char *) buffer;
+		while (left) {
+			char c;
+			if(get_user(c, p++))
+				return -EFAULT;
+			if (!isspace(c))
+				break;
+			left--;
+		}
+	}
+	if (write && first)
+		return -EINVAL;
+	*lenp -= left;
+	filp->f_pos += *lenp;
+	return 0;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/hvCall.S linux-2.4.19-pre5/arch/ppc64/kernel/hvCall.S
--- linux-2.4.19-pre4/arch/ppc64/kernel/hvCall.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/hvCall.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,99 @@
+/*
+ * arch/ppc64/kernel/hvCall.S
+ *
+ *
+ * This file contains the code to perform calls to the
+ * iSeries LPAR hypervisor
+ *
+ * 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 "ppc_asm.h"
+#include <asm/processor.h>
+#include <linux/config.h>
+
+	.text
+
+/* 
+ * Hypervisor call
+ * 
+ * Invoke the iSeries hypervisor via the System Call instruction
+ * Parameters are passed to this routine in registers r3 - r10
+ * 
+ * r3 contains the HV function to be called
+ * r4-r10 contain the operands to the hypervisor function
+ *
+ */
+
+_GLOBAL(HvCall)
+_GLOBAL(HvCall0)
+_GLOBAL(HvCall1)
+_GLOBAL(HvCall2)
+_GLOBAL(HvCall3)
+_GLOBAL(HvCall4)
+_GLOBAL(HvCall5)
+_GLOBAL(HvCall6)
+_GLOBAL(HvCall7)
+
+
+	mfcr	r0
+	std	r0,-8(r1)
+	stdu	r1,-(STACK_FRAME_OVERHEAD+16)(r1)
+	
+	/* r0 = 0xffffffffffffffff indicates a hypervisor call */
+	
+	li	r0,-1
+	
+	/* Invoke the hypervisor */
+
+	sc
+
+	ld	r1,0(r1)
+	ld	r0,-8(r1)
+	mtcrf	0xff,r0
+
+	/*  return to caller, return value in r3 */
+	
+	blr
+
+_GLOBAL(HvCall0Ret16)
+_GLOBAL(HvCall1Ret16)
+_GLOBAL(HvCall2Ret16)
+_GLOBAL(HvCall3Ret16)
+_GLOBAL(HvCall4Ret16)
+_GLOBAL(HvCall5Ret16)
+_GLOBAL(HvCall6Ret16)
+_GLOBAL(HvCall7Ret16)
+
+	mfcr	r0
+	std	r0,-8(r1)
+	std	r31,-16(r1)
+	stdu	r1,-(STACK_FRAME_OVERHEAD+32)(r1)
+
+	mr	r31,r4
+	li	r0,-1
+	mr	r4,r5
+	mr	r5,r6
+	mr	r6,r7
+	mr	r7,r8
+	mr	r8,r9
+	mr	r9,r10
+
+	sc
+
+	std	r3,0(r31)
+	std	r4,8(r31)
+
+	mr	r3,r5
+
+	ld	r1,0(r1)
+	ld	r0,-8(r1)
+	mtcrf	0xff,r0
+	ld	r31,-16(r1)
+	
+	blr
+
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/i8259.c linux-2.4.19-pre5/arch/ppc64/kernel/i8259.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/i8259.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/i8259.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,164 @@
+/*
+ * c 2001 PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/cache.h>
+#include <asm/io.h>
+#include "i8259.h"
+#include <linux/irq.h>
+#include <asm/ppcdebug.h>
+
+unsigned char cached_8259[2] = { 0xff, 0xff };
+#define cached_A1 (cached_8259[0])
+#define cached_21 (cached_8259[1])
+
+static spinlock_t i8259_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+int i8259_pic_irq_offset;
+
+int i8259_irq(int cpu)
+{
+	int irq;
+	
+	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
+        /*
+         * 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) {
+			spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
+			return -1;
+		}
+	}
+	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
+	return irq;
+}
+
+static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&i8259_lock, flags);
+        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 */                 
+        }                                                                
+	spin_unlock_irqrestore(&i8259_lock, flags);
+}
+
+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)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259_lock, flags);
+        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);
+	spin_unlock_irqrestore(&i8259_lock, flags);
+}
+
+static void i8259_unmask_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259_lock, flags);
+        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);
+	spin_unlock_irqrestore(&i8259_lock, flags);
+}
+
+static void i8259_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		i8259_unmask_irq(irq);
+}
+
+struct hw_interrupt_type i8259_pic = {
+        " i8259    ",
+        NULL,
+        NULL,
+        i8259_unmask_irq,
+        i8259_mask_irq,
+        i8259_mask_and_ack_irq,
+        i8259_end_irq,
+        NULL
+};
+
+void __init i8259_init(void)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&i8259_lock, flags);
+        /* 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);
+	spin_unlock_irqrestore(&i8259_lock, flags);
+        request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
+                     "82c59 secondary cascade", NULL );
+        
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/i8259.h linux-2.4.19-pre5/arch/ppc64/kernel/i8259.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/i8259.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/i8259.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,19 @@
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#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);
+int i8259_irq(int);
+
+#endif /* _PPC_KERNEL_i8259_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_IoMmTable.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_IoMmTable.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,163 @@
+/************************************************************************/
+/* This module supports the iSeries I/O Address translation mapping     */
+/* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, December 14, 2000                                         */
+/*   Added Bar table for IoMm performance.                              */
+/*   Ported to ppc64                                                    */
+/*   Added dynamic table allocation                                     */
+/* End Change Activity                                                  */
+/************************************************************************/
+#include <asm/types.h>
+#include <asm/resource.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <asm/ppcdebug.h>
+#include <asm/flight_recorder.h>
+#include <asm/iSeries/HvCallPci.h>
+#include <asm/iSeries/iSeries_pci.h>
+
+#include "iSeries_IoMmTable.h"
+#include "pci.h"
+
+/*******************************************************************/
+/* Table defines                                                   */
+/* Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. */
+/*******************************************************************/
+#define Max_Entries 1024
+unsigned long iSeries_IoMmTable_Entry_Size = 0x0000000000400000; 
+unsigned long iSeries_Base_Io_Memory       = 0xE000000000000000;
+unsigned long iSeries_Max_Io_Memory        = 0xE000000000000000;
+static   long iSeries_CurrentIndex         = 0;
+
+/*******************************************************************/
+/* Lookup Tables.                                                  */
+/*******************************************************************/
+struct iSeries_Device_Node** iSeries_IoMmTable;
+u8*                          iSeries_IoBarTable;
+
+/*******************************************************************/
+/* Static and Global variables                                     */
+/*******************************************************************/
+static char*      iSeriesPciIoText     = "iSeries PCI I/O";
+static spinlock_t iSeriesIoMmTableLock = SPIN_LOCK_UNLOCKED;
+
+/*******************************************************************/
+/* iSeries_IoMmTable_Initialize                                    */
+/*******************************************************************/
+/* Allocates and initalizes the Address Translation Table and Bar  */
+/* Tables to get them ready for use.  Must be called before any    */
+/* I/O space is handed out to the device BARs.                     */
+/* A follow up method,iSeries_IoMmTable_Status can be called to    */
+/* adjust the table after the device BARs have been assiged to     */
+/* resize the table.                                               */
+/*******************************************************************/
+void iSeries_IoMmTable_Initialize(void)
+{
+	spin_lock(&iSeriesIoMmTableLock);
+	iSeries_IoMmTable  = kmalloc(sizeof(void*)*Max_Entries,GFP_KERNEL);
+	iSeries_IoBarTable = kmalloc(sizeof(u8)*Max_Entries,   GFP_KERNEL);
+	spin_unlock(&iSeriesIoMmTableLock);
+	PCIFR("IoMmTable Initialized 0x%p",  iSeries_IoMmTable);
+	if(iSeries_IoMmTable == NULL || iSeries_IoBarTable == NULL) {
+		panic("PCI: I/O tables allocation failed.\n");
+	}
+}
+
+/*******************************************************************/
+/* iSeries_IoMmTable_AllocateEntry                                 */
+/*******************************************************************/
+/* Adds pci_dev entry in address translation table                 */
+/*******************************************************************/
+/* - Allocates the number of entries required in table base on BAR */
+/*   size.                                                         */
+/* - Allocates starting at iSeries_Base_Io_Memory and increases.   */
+/* - The size is round up to be a multiple of entry size.          */
+/* - CurrentIndex is incremented to keep track of the last entry.  */
+/* - Builds the resource entry for allocated BARs.                 */
+/*******************************************************************/
+static void iSeries_IoMmTable_AllocateEntry(struct pci_dev* PciDev, int BarNumber)
+{
+	struct resource* BarResource = &PciDev->resource[BarNumber];
+	long             BarSize     = pci_resource_len(PciDev,BarNumber);
+	/***********************************************************/
+	/* No space to allocate, quick exit, skip Allocation.      */
+	/***********************************************************/
+	if(BarSize == 0) return;
+	/***********************************************************/
+	/* Set Resource values.                                    */
+	/***********************************************************/
+	spin_lock(&iSeriesIoMmTableLock);
+	BarResource->name  = iSeriesPciIoText;
+	BarResource->start = iSeries_IoMmTable_Entry_Size*iSeries_CurrentIndex;
+	BarResource->start+= iSeries_Base_Io_Memory;
+	BarResource->end   = BarResource->start+BarSize-1;
+	/***********************************************************/
+	/* Allocate the number of table entries needed for BAR.    */
+	/***********************************************************/
+	while (BarSize > 0 ) {
+		*(iSeries_IoMmTable +iSeries_CurrentIndex) = (struct iSeries_Device_Node*)PciDev->sysdata;
+		*(iSeries_IoBarTable+iSeries_CurrentIndex) = BarNumber;
+		BarSize -= iSeries_IoMmTable_Entry_Size;
+		++iSeries_CurrentIndex;
+	}
+	iSeries_Max_Io_Memory = (iSeries_IoMmTable_Entry_Size*iSeries_CurrentIndex)+iSeries_Base_Io_Memory;
+	spin_unlock(&iSeriesIoMmTableLock);
+}
+
+/*******************************************************************/
+/* iSeries_allocateDeviceBars                                      */
+/*******************************************************************/
+/* - Allocates ALL pci_dev BAR's and updates the resources with the*/
+/*   BAR value.  BARS with zero length will have the resources     */
+/*   The HvCallPci_getBarParms is used to get the size of the BAR  */
+/*   space.  It calls iSeries_IoMmTable_AllocateEntry to allocate  */
+/*   each entry.                                                   */
+/* - Loops through The Bar resourses(0 - 5) including the the ROM  */
+/*   is resource(6).                                               */
+/*******************************************************************/
+void iSeries_allocateDeviceBars(struct pci_dev* PciDev)
+{
+	struct resource* BarResource;
+	int              BarNumber;
+	for(BarNumber = 0; BarNumber <= PCI_ROM_RESOURCE; ++BarNumber) {
+		BarResource = &PciDev->resource[BarNumber];
+		iSeries_IoMmTable_AllocateEntry(PciDev, BarNumber);
+    	}
+}
+
+/************************************************************************/
+/* Translates the IoAddress to the device that is mapped to IoSpace.    */
+/* This code is inlined, see the iSeries_pci.c file for the replacement.*/
+/************************************************************************/
+struct iSeries_Device_Node* iSeries_xlateIoMmAddress(void* IoAddress)
+{
+	return NULL;	   
+}
+
+/************************************************************************
+ * Status hook for IoMmTable
+ ************************************************************************/
+void     iSeries_IoMmTable_Status(void)
+{
+	PCIFR("IoMmTable......: 0x%p",iSeries_IoMmTable);
+	PCIFR("IoMmTable Range: 0x%p to 0x%p",iSeries_Base_Io_Memory,iSeries_Max_Io_Memory);
+	return;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_IoMmTable.h linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_IoMmTable.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_IoMmTable.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,85 @@
+#ifndef _ISERIES_IOMMTABLE_H
+#define _ISERIES_IOMMTABLE_H
+/************************************************************************/
+/* File iSeries_IoMmTable.h created by Allan Trautman on Dec 12 2001.   */
+/************************************************************************/
+/* Interfaces for the write/read Io address translation table.          */
+/* Copyright (C) 20yy  Allan H Trautman, IBM Corporation                */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created December 12, 2000                                          */
+/*   Ported to ppc64, August 30, 2001                                   */
+/* End Change Activity                                                  */
+/************************************************************************/
+
+struct pci_dev;
+struct iSeries_Device_Node;
+
+extern struct iSeries_Device_Node** iSeries_IoMmTable;
+extern u8*                          iSeries_IoBarTable;
+extern unsigned long iSeries_Base_Io_Memory;
+extern unsigned long iSeries_Max_Io_Memory;
+extern unsigned long iSeries_Base_Io_Memory;
+extern unsigned long iSeries_IoMmTable_Entry_Size;
+/************************************************************************/
+/* iSeries_IoMmTable_Initialize                                         */
+/************************************************************************/
+/* - Initalizes the Address Translation Table and get it ready for use. */
+/*   Must be called before any client calls any of the other methods.   */
+/*                                                                      */
+/* Parameters: None.                                                    */
+/*                                                                      */
+/* Return: None.                                                        */  
+/************************************************************************/
+extern  void iSeries_IoMmTable_Initialize(void);
+extern  void iSeries_IoMmTable_Status(void);
+
+/************************************************************************/
+/* iSeries_allocateDeviceBars                                           */
+/************************************************************************/
+/* - Allocates ALL pci_dev BAR's and updates the resources with the BAR */
+/*   value.  BARS with zero length will not have the resources.  The    */
+/*   HvCallPci_getBarParms is used to get the size of the BAR space.    */
+/*   It calls iSeries_IoMmTable_AllocateEntry to allocate each entry.   */
+/*                                                                      */
+/* Parameters:                                                          */
+/* pci_dev = Pointer to pci_dev structure that will be mapped to pseudo */
+/*           I/O Address.                                               */
+/*                                                                      */
+/* Return:                                                              */
+/*   The pci_dev I/O resources updated with pseudo I/O Addresses.       */
+/************************************************************************/
+extern  void iSeries_allocateDeviceBars(struct pci_dev* );
+
+/************************************************************************/
+/* iSeries_xlateIoMmAddress                                             */
+/************************************************************************/
+/* - Translates an I/O Memory address to Device Node that has been the  */
+/*   allocated the psuedo I/O Address.                                  */
+/*                                                                      */
+/* Parameters:                                                          */
+/* IoAddress = I/O Memory Address.                                      */
+/*                                                                      */
+/* Return:                                                              */
+/*   An iSeries_Device_Node to the device mapped to the I/O address. The*/
+/*   BarNumber and BarOffset are valid if the Device Node is returned.  */
+/************************************************************************/
+extern struct iSeries_Device_Node* iSeries_xlateIoMmAddress(void* IoAddress);
+
+#endif /* _ISERIES_IOMMTABLE_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_VpdInfo.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_VpdInfo.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_VpdInfo.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_VpdInfo.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,317 @@
+/************************************************************************/
+/* File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb  2 2001. */
+/************************************************************************/
+/* This code gets the card location of the hardware                     */
+/* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, Feb 2, 2001                                               */
+/*   Ported to ppc64, August 20, 2001                                   */
+/* End Change Activity                                                  */
+/************************************************************************/
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/types.h>
+#include <asm/resource.h>
+
+#include <asm/iSeries/HvCallPci.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/mf.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/HvCallPci.h>
+//#include <asm/iSeries/iSeries_VpdInfo.h>
+#include <asm/iSeries/iSeries_pci.h>
+#include "pci.h"
+
+/************************************************/
+/* Size of Bus VPD data                         */
+/************************************************/
+#define BUS_VPDSIZE      1024
+/************************************************/
+/* Bus Vpd Tags                                 */
+/************************************************/
+#define  VpdEndOfDataTag   0x78
+#define  VpdEndOfAreaTag   0x79
+#define  VpdIdStringTag    0x82
+#define  VpdVendorAreaTag  0x84
+/************************************************/
+/* Mfg Area Tags                                */
+/************************************************/
+#define  VpdFruFlag       0x4647     // "FG"
+#define  VpdFruFrameId    0x4649     // "FI"
+#define  VpdSlotMapFormat 0x4D46     // "MF"
+#define  VpdAsmPartNumber 0x504E     // "PN"
+#define  VpdFruSerial     0x534E     // "SN"
+#define  VpdSlotMap       0x534D     // "SM"
+
+/************************************************/
+/* Structures of the areas                      */
+/************************************************/
+struct MfgVpdAreaStruct {
+	u16 Tag;
+	u8  TagLength;
+	u8  AreaData1;
+	u8  AreaData2;
+};
+typedef struct MfgVpdAreaStruct MfgArea;
+#define MFG_ENTRY_SIZE   3
+
+struct SlotMapStruct {
+	u8   AgentId;
+	u8   SecondaryAgentId;
+	u8   PhbId;
+	char CardLocation[3];
+	char Parms[8];
+	char Reserved[2];
+}; 
+typedef struct SlotMapStruct SlotMap;
+#define SLOT_ENTRY_SIZE   16
+
+/****************************************************************
+ *                                                              *
+ * Bus, Card, Board, FrameId, CardLocation.                     *
+ ****************************************************************/
+LocationData* iSeries_GetLocationData(struct pci_dev* PciDev)
+{
+	struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata;
+	LocationData* LocationPtr = (LocationData*)kmalloc(LOCATION_DATA_SIZE, GFP_KERNEL);
+	if (LocationPtr == NULL) {
+		printk("PCI: LocationData area allocation failed!\n");
+		return NULL;
+	}
+	memset(LocationPtr,0,LOCATION_DATA_SIZE);
+	LocationPtr->Bus              = ISERIES_BUS(DevNode);
+	LocationPtr->Board            = DevNode->Board;
+	LocationPtr->FrameId          = DevNode->FrameId;
+	LocationPtr->Card             = PCI_SLOT(DevNode->DevFn);
+	strcpy(&LocationPtr->CardLocation[0],&DevNode->CardLocation[0]);
+	return LocationPtr;
+}
+
+/************************************************************************/
+/* Formats the device information.                                      */
+/* - Pass in pci_dev* pointer to the device.                            */
+/* - Pass in buffer to place the data.  Danger here is the buffer must  */
+/*   be as big as the client says it is.   Should be at least 128 bytes.*/
+/* Return will the length of the string data put in the buffer.         */
+/* Format:                                                              */
+/* PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet */
+/* controller                                                           */
+/************************************************************************/
+int  iSeries_Device_Information(struct pci_dev* PciDev,char* Buffer, int BufferSize)
+{
+	struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata;
+	char*          BufPtr  = Buffer;
+	int            LineLen = 0;
+
+	if (DevNode == NULL) {
+		LineLen = sprintf(BufPtr+LineLen, "PCI: iSeries_Device_Information DevNode is NULL");
+		return LineLen;
+	}
+
+	if (BufferSize >= 128) {
+		LineLen =  sprintf(BufPtr+LineLen,"PCI: Bus%3d, Device%3d, Vendor %04X ",
+				   ISERIES_BUS(DevNode), PCI_SLOT(PciDev->devfn),PciDev->vendor);
+
+		LineLen += sprintf(BufPtr+LineLen,"Frame%3d, Card %4s  ", DevNode->FrameId,DevNode->CardLocation);
+
+		if (pci_class_name(PciDev->class >> 8) == 0) {
+			LineLen += sprintf(BufPtr+LineLen,"0x%04X  ",(int)(PciDev->class >> 8));
+		}
+		else {
+			LineLen += sprintf(BufPtr+LineLen,"%s",pci_class_name(PciDev->class >> 8) );
+		}
+	}
+	return LineLen;
+}
+/************************************************************************/
+/* Build a character string of the device location, Frame  1, Card  C10 */
+/************************************************************************/
+int   device_Location(struct pci_dev* PciDev,char* BufPtr)
+{
+	struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)PciDev->sysdata;
+	return sprintf(BufPtr,"PCI: Bus%3d, Device%3d, Vendor %04X, Location %s",
+		       DevNode->DsaAddr.busNumber,
+		       DevNode->AgentId,
+		       DevNode->Vendor,
+		       DevNode->Location);
+}
+
+/*****************************************************************/
+/* Parse the Slot Area                                           */
+/*****************************************************************/
+void  iSeries_Parse_SlotArea(SlotMap* MapPtr,int MapLen, struct iSeries_Device_Node* DevNode)
+{
+	int      SlotMapLen = MapLen;
+	SlotMap* SlotMapPtr = MapPtr;
+	/*************************************************************/
+	/* Parse Slot label until we find the one requrested         */
+	/*************************************************************/
+	while (SlotMapLen > 0) {
+		if (SlotMapPtr->AgentId == DevNode->AgentId ) {
+			/*******************************************************/
+			/* If Phb wasn't found, grab the entry first one found.*/ 
+			/*******************************************************/
+			if (DevNode->PhbId == 0xff) {
+				DevNode->PhbId = SlotMapPtr->PhbId; 
+			}
+			/**************************************************/
+			/* Found it, extract the data.                    */
+			/**************************************************/
+			if (SlotMapPtr->PhbId == DevNode->PhbId ) {
+	        		memcpy(&DevNode->CardLocation,&SlotMapPtr->CardLocation,3);
+				DevNode->CardLocation[3]  = 0;
+				break;
+			}
+		}
+		/*********************************************************/
+		/* Point to the next Slot                                */
+		/*********************************************************/
+		SlotMapPtr = (SlotMap*)((char*)SlotMapPtr+SLOT_ENTRY_SIZE);
+		SlotMapLen -= SLOT_ENTRY_SIZE;
+	}
+}
+
+/*****************************************************************/
+/* Parse the Mfg Area                                            */
+/*****************************************************************/
+static void  iSeries_Parse_MfgArea(u8* AreaData,int AreaLen, struct iSeries_Device_Node* DevNode)
+{
+	MfgArea* MfgAreaPtr = (MfgArea*)AreaData;
+	int      MfgAreaLen = AreaLen;
+	u16      SlotMapFmt = 0;
+
+	/*************************************************************/
+	/* Parse Mfg Data                                            */
+	/*************************************************************/
+	while (MfgAreaLen > 0) {
+		int MfgTagLen  = MfgAreaPtr->TagLength;
+		/*******************************************************/
+		/* Frame ID         (FI 4649020310 )                   */
+		/*******************************************************/
+		if (MfgAreaPtr->Tag == VpdFruFrameId) {     /* FI  */
+			DevNode->FrameId = MfgAreaPtr->AreaData1;
+		}
+		/*******************************************************/
+		/* Slot Map Format  (MF 4D46020004 )                   */
+		/*******************************************************/
+		else if (MfgAreaPtr->Tag == VpdSlotMapFormat){   /* MF  */
+			SlotMapFmt = (MfgAreaPtr->AreaData1*256)+(MfgAreaPtr->AreaData2);
+		}
+		/*******************************************************/
+		/* Slot Map         (SM 534D90                         */
+		/*******************************************************/
+		else if (MfgAreaPtr->Tag == VpdSlotMap){         /* SM  */
+			SlotMap*  SlotMapPtr;
+			if (SlotMapFmt == 0x1004) SlotMapPtr = (SlotMap*)((char*)MfgAreaPtr+MFG_ENTRY_SIZE+1);
+ 	    		else                     SlotMapPtr = (SlotMap*)((char*)MfgAreaPtr+MFG_ENTRY_SIZE);
+	    		iSeries_Parse_SlotArea(SlotMapPtr,MfgTagLen, DevNode);
+		}
+		/*********************************************************/
+		/* Point to the next Mfg Area                            */
+		/* Use defined size, sizeof give wrong answer            */
+		/*********************************************************/
+		MfgAreaPtr = (MfgArea*)((char*)MfgAreaPtr + MfgTagLen + MFG_ENTRY_SIZE);
+		MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE); 
+	}	
+}
+
+/*****************************************************************/
+/* Look for "BUS".. Data is not Null terminated.                 */
+/* PHBID of 0xFF indicates PHB was not found in VPD Data.        */	
+/*****************************************************************/
+static int iSeries_Parse_PhbId(u8* AreaPtr,int AreaLength)
+{
+	u8*  PhbPtr  = AreaPtr;
+	int  DataLen = AreaLength;
+	char PhbId   = 0xFF;                   
+	while (DataLen > 0) {
+		if (*PhbPtr == 'B' && *(PhbPtr+1) == 'U' && *(PhbPtr+2) == 'S') {
+			PhbPtr += 3;
+			while(*PhbPtr == ' ') ++PhbPtr;
+			PhbId = (*PhbPtr & 0x0F);
+			break;
+        	}
+		++PhbPtr;
+		--DataLen;
+	}
+	return PhbId;
+}
+
+/****************************************************************/
+/* Parse out the VPD Areas                                      */
+/****************************************************************/
+static void  iSeries_Parse_Vpd(u8* VpdData, int VpdDataLen, struct iSeries_Device_Node* DevNode)
+{
+	u8*  TagPtr  = VpdData;
+	int  DataLen = VpdDataLen-3;
+	/*************************************************************/
+	/* Parse the Areas                                           */
+	/*************************************************************/
+	while (*TagPtr != VpdEndOfAreaTag && DataLen > 0) {
+		int  AreaLen   = *(TagPtr+1) + (*(TagPtr+2)*256);	
+		u8*  AreaData  = TagPtr+3;
+
+		if (*TagPtr == VpdIdStringTag) {
+			DevNode->PhbId = iSeries_Parse_PhbId(AreaData,AreaLen);
+		}
+		else if (*TagPtr == VpdVendorAreaTag) {
+	    		iSeries_Parse_MfgArea(AreaData,AreaLen,DevNode);
+		}
+		/*********************************************************
+		 * Point to next Area.
+		 *********************************************************/
+		TagPtr  = AreaData + AreaLen;
+		DataLen -= AreaLen;
+	}
+}    
+
+/****************************************************************
+ *  iSeries_Get_Location_Code(struct iSeries_Device_Node*)      *
+ *
+ ****************************************************************/
+void  iSeries_Get_Location_Code(struct iSeries_Device_Node* DevNode)
+{
+	int  BusVpdLen = 0;
+	u8*  BusVpdPtr = (u8*)kmalloc(BUS_VPDSIZE, GFP_KERNEL);
+	if (BusVpdPtr == NULL) {
+		printk("PCI: Bus VPD Buffer allocation failure.\n");
+		return;
+	}
+	BusVpdLen  = HvCallPci_getBusVpd(ISERIES_BUS(DevNode),REALADDR(BusVpdPtr),BUS_VPDSIZE);
+	if (BusVpdLen == 0) {
+		kfree(BusVpdPtr);
+		printk("PCI: Bus VPD Buffer zero length.\n");
+		return;
+	}
+	//printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen);
+	/*************************************************************/
+	/* Make sure this is what I think it is                      */
+	/*************************************************************/
+	if (*BusVpdPtr != VpdIdStringTag) {               /*0x82     */
+		printk("PCI: Bus VPD Buffer missing starting tag.\n");
+		kfree(BusVpdPtr);
+		return;
+	}
+	/***************************************************************/
+	/***************************************************************/
+	iSeries_Parse_Vpd(BusVpdPtr,BusVpdLen, DevNode);
+	sprintf(DevNode->Location,"Frame%3d, Card %-4s",DevNode->FrameId,DevNode->CardLocation);
+	kfree(BusVpdPtr);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_irq.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_irq.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_irq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_irq.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,259 @@
+/************************************************************************/
+/* This module supports the iSeries PCI bus interrupt handling          */
+/* Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, December 13, 2000 by Wayne Holm                           */ 
+/* End Change Activity                                                  */
+/************************************************************************/
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/blk.h>
+#include <linux/ide.h>
+
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <asm/ppcdebug.h>
+
+#include <asm/iSeries/HvCallPci.h>
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/iSeries_irq.h>
+#include <asm/iSeries/XmPciLpEvent.h>
+
+
+hw_irq_controller iSeries_IRQ_handler = {
+	"iSeries irq controller",
+	iSeries_startup_IRQ,	/* startup */
+	iSeries_shutdown_IRQ,	/* shutdown */
+	iSeries_enable_IRQ,	/* enable */
+	iSeries_disable_IRQ,	/* disable */
+	NULL,			/* ack  */
+	iSeries_end_IRQ,	/* end  */
+	NULL			/* set_affinity */
+};
+
+
+struct iSeries_irqEntry {
+	u32 dsa;
+	struct iSeries_irqEntry* next;
+};
+
+struct iSeries_irqAnchor {
+	u8  valid : 1;
+	u8  reserved : 7;
+	u16  entryCount;
+	struct iSeries_irqEntry* head;
+};
+
+struct iSeries_irqAnchor iSeries_irqMap[NR_IRQS];
+
+void iSeries_init_irqMap(int irq);
+
+/*  This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c */
+void __init iSeries_init_IRQ(void)
+{
+	int i;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].handler = &iSeries_IRQ_handler;
+		irq_desc[i].status = 0;
+		irq_desc[i].status |= IRQ_DISABLED;
+		irq_desc[i].depth = 1;
+		iSeries_init_irqMap(i);
+	}
+	/* Register PCI event handler and open an event path */
+	PPCDBG(PPCDBG_BUSWALK,"Register PCI event handler and open an event path\n");
+	XmPciLpEvent_init();
+	return;
+}
+
+/**********************************************************************
+ *  Called by iSeries_init_IRQ 
+ * Prevent IRQs 0 and 255 from being used.  IRQ 0 appears in
+ * uninitialized devices.  IRQ 255 appears in the PCI interrupt
+ * line register if a PCI error occurs,
+ *********************************************************************/
+void __init iSeries_init_irqMap(int irq)
+{
+	iSeries_irqMap[irq].valid = (irq == 0 || irq == 255)? 0 : 1;
+	iSeries_irqMap[irq].entryCount = 0;
+	iSeries_irqMap[irq].head = NULL;
+}
+
+/* This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot */
+/* It calculates the irq value for the slot.                                   */
+int __init iSeries_allocate_IRQ(HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId)
+{
+	u8 idsel = (deviceId >> 4);
+	u8 function = deviceId & 0x0F;
+	int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 253) + 2;
+	return irq;
+}
+
+/* This is called out of iSeries_scan_slot to assign the EADS slot to its IRQ number */
+int __init iSeries_assign_IRQ(int irq, HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId)
+{
+	int rc;
+	u32 dsa = (busNumber << 16) | (subBusNumber << 8) | deviceId;
+	struct iSeries_irqEntry* newEntry;
+	unsigned long flags;
+
+	if (irq < 0 || irq >= NR_IRQS) {
+		return -1;
+	}
+	newEntry = kmalloc(sizeof(*newEntry), GFP_KERNEL);
+	if (newEntry == NULL) {
+		return -ENOMEM;
+	}
+	newEntry->dsa  = dsa;
+	newEntry->next = NULL;
+	/********************************************************************
+	* Probably not necessary to lock the irq since allocation is only 
+	* done during buswalk, but it should not hurt anything except a 
+	* little performance to be smp safe.
+	*******************************************************************/
+	spin_lock_irqsave(&irq_desc[irq].lock, flags);
+
+	if (iSeries_irqMap[irq].valid) {
+		/* Push the new element onto the irq stack */
+		newEntry->next = iSeries_irqMap[irq].head;
+		iSeries_irqMap[irq].head = newEntry;
+		++iSeries_irqMap[irq].entryCount;
+		rc = 0;
+		PPCDBG(PPCDBG_BUSWALK,"iSeries_assign_IRQ   0x%04X.%02X.%02X = 0x%04X\n",busNumber, subBusNumber, deviceId, irq);
+	}
+	else {
+		printk("PCI: Something is wrong with the iSeries_irqMap. \n");
+		kfree(newEntry);
+		rc = -1;
+    }
+	spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+	return rc;
+}
+
+
+/* This is called by iSeries_activate_IRQs */
+unsigned int iSeries_startup_IRQ(unsigned int irq)
+{
+	struct iSeries_irqEntry* entry;
+	u32 bus, subBus, deviceId, function, mask;
+	for(entry=iSeries_irqMap[irq].head; entry!=NULL; entry=entry->next) {
+		bus      = (entry->dsa >> 16) & 0xFFFF;
+		subBus   = (entry->dsa >> 8) & 0xFF;
+		deviceId = entry->dsa & 0xFF;
+		function = deviceId & 0x0F;
+		/* Link the IRQ number to the bridge */
+		HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
+        	/* Unmask bridge interrupts in the FISR */
+		mask = 0x01010000 << function;
+		HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
+		PPCDBG(PPCDBG_BUSWALK,"iSeries_activate_IRQ 0x%02X.%02X.%02X  Irq:0x%02X\n",bus,subBus,deviceId,irq);
+	}
+	return 0;
+}
+
+/* This is called out of iSeries_fixup to activate interrupt
+ * generation for usable slots                              */
+void __init iSeries_activate_IRQs()
+{
+	int irq;
+	unsigned long flags;
+	for (irq=0; irq < NR_IRQS; irq++) {
+		spin_lock_irqsave(&irq_desc[irq].lock, flags);
+		irq_desc[irq].handler->startup(irq);
+		spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+    	}
+}
+
+/*  this is not called anywhere currently */
+void iSeries_shutdown_IRQ(unsigned int irq) {
+	struct iSeries_irqEntry* entry;
+	u32 bus, subBus, deviceId, function, mask;
+
+	/* irq should be locked by the caller */
+
+	for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
+		bus = (entry->dsa >> 16) & 0xFFFF;
+		subBus = (entry->dsa >> 8) & 0xFF;
+		deviceId = entry->dsa & 0xFF;
+		function = deviceId & 0x0F;
+		/* Invalidate the IRQ number in the bridge */
+		HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
+		/* Mask bridge interrupts in the FISR */
+		mask = 0x01010000 << function;
+		HvCallPci_maskFisr(bus, subBus, deviceId, mask);
+	}
+
+}
+
+/***********************************************************
+ * This will be called by device drivers (via disable_IRQ)
+ * to disable INTA in the bridge interrupt status register.
+ ***********************************************************/
+void iSeries_disable_IRQ(unsigned int irq)
+{
+	struct iSeries_irqEntry* entry;
+	u32 bus, subBus, deviceId, mask;
+
+	/* The IRQ has already been locked by the caller */
+
+	for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
+		bus      = (entry->dsa >> 16) & 0xFFFF;
+		subBus   = (entry->dsa >> 8) & 0xFF;
+		deviceId = entry->dsa & 0xFF;
+		/* Mask secondary INTA   */
+		mask = 0x80000000;
+		HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
+		PPCDBG(PPCDBG_BUSWALK,"iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",bus,subBus,deviceId,irq);
+    	}
+}
+
+/***********************************************************
+ * This will be called by device drivers (via enable_IRQ)
+ * to enable INTA in the bridge interrupt status register.
+ ***********************************************************/
+void iSeries_enable_IRQ(unsigned int irq)
+{
+	struct iSeries_irqEntry* entry;
+	u32 bus, subBus, deviceId, mask;
+
+	/* The IRQ has already been locked by the caller */
+	for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
+		bus      = (entry->dsa >> 16) & 0xFFFF;
+		subBus   = (entry->dsa >> 8) & 0xFF;
+		deviceId = entry->dsa & 0xFF;
+		/* Unmask secondary INTA */
+		mask = 0x80000000;
+		HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
+		PPCDBG(PPCDBG_BUSWALK,"iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",bus,subBus,deviceId,irq);
+	}
+}
+
+/* Need to define this so ppc_irq_dispatch_handler will NOT call
+   enable_IRQ at the end of interrupt handling.  However, this
+   does nothing because there is not enough information provided
+   to do the EOI HvCall.  This is done by XmPciLpEvent.c */
+void iSeries_end_IRQ(unsigned int irq)
+{
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_pci.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,926 @@
+/*
+ * iSeries_pci.c
+ *
+ * Copyright (C) 2001 Allan Trautman, IBM Corporation
+ *
+ * iSeries specific routines for PCI.
+ * 
+ * Based on code from pci.c and iSeries_pci.c 32bit
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/list.h> 
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppcdebug.h>
+#include <asm/Naca.h>
+#include <asm/flight_recorder.h>
+#include <asm/pci_dma.h>
+
+#include <asm/iSeries/HvCallPci.h>
+#include <asm/iSeries/HvCallSm.h>
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/iSeries_irq.h>
+#include <asm/iSeries/iSeries_pci.h>
+#include <asm/iSeries/mf.h>
+
+#include "iSeries_IoMmTable.h"
+#include "pci.h"
+
+extern struct pci_controller* hose_head;
+extern struct pci_controller** hose_tail;
+extern int    global_phb_number;
+extern int    panic_timeout;
+
+extern struct Naca *naca;
+extern struct device_node *allnodes;
+extern unsigned long phb_tce_table_init(struct pci_controller *phb);
+extern unsigned long iSeries_Base_Io_Memory;    
+
+extern struct pci_ops iSeries_pci_ops;
+extern struct flightRecorder* PciFr;
+extern struct TceTable* tceTables[256];
+
+/*******************************************************************
+ * Counters and control flags. 
+ *******************************************************************/
+extern long   Pci_Io_Read_Count;
+extern long   Pci_Io_Write_Count;
+extern long   Pci_Cfg_Read_Count;
+extern long   Pci_Cfg_Write_Count;
+extern long   Pci_Error_Count;
+
+extern int    Pci_Retry_Max;	
+extern int    Pci_Error_Flag;
+extern int    Pci_Trace_Flag;
+
+extern void iSeries_MmIoTest(void);
+
+
+/*******************************************************************
+ * Forward declares of prototypes. 
+ *******************************************************************/
+struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev);
+struct iSeries_Device_Node* get_Device_Node(struct pci_dev* PciDev);
+
+unsigned long find_and_init_phbs(void);
+void          fixup_resources(struct pci_dev *dev);
+void          iSeries_pcibios_fixup(void);
+struct        pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ;
+
+void  iSeries_Scan_PHBs_Slots(struct pci_controller* Phb);
+void  iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
+int   iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* Info);
+void  list_device_nodes(void);
+
+struct pci_dev;
+
+extern struct list_head iSeries_Global_Device_List;
+
+int DeviceCount = 0;
+
+/**********************************************************************************
+ * Log Error infor in Flight Recorder to system Console.
+ * Filter out the device not there errors.
+ * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx
+ * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
+ * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
+ **********************************************************************************/
+void  pci_Log_Error(char* Error_Text, int Bus, int SubBus, int AgentId, int HvRc)
+{
+	if( HvRc != 0x0302) { 
+		char ErrorString[128];
+		sprintf(ErrorString,"%s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",Error_Text,Bus,SubBus,AgentId,HvRc);
+		PCIFR(ErrorString);
+		printk("PCI: %s\n",ErrorString);
+	}
+}
+
+/**********************************************************************************
+ * Dump the iSeries Temp Device Node 
+ *<4>buswalk [swapper : - DeviceNode: 0xC000000000634300
+ *<4>00. Device Node   = 0xC000000000634300
+ *<4>    - PciDev      = 0x0000000000000000
+ *<4>    - tDevice     = 0x  17:01.00  0x1022 00
+ *<4>  4. Device Node = 0xC000000000634480
+ *<4>     - PciDev    = 0x0000000000000000
+ *<4>     - Device    = 0x  18:38.16 Irq:0xA7 Vendor:0x1014  Flags:0x00
+ *<4>     - Devfn     = 0xB0: 22.18
+ **********************************************************************************/
+void dumpDevice_Node(struct iSeries_Device_Node* DevNode)
+{
+	udbg_printf("Device Node      = 0x%p\n",DevNode);
+	udbg_printf("     - PciDev    = 0x%p\n",DevNode->PciDev);
+	udbg_printf("     - Device    = 0x%4X:%02X.%02X (0x%02X)\n",
+		    ISERIES_BUS(DevNode),
+		    ISERIES_SUBBUS(DevNode),
+		    DevNode->AgentId,
+		    DevNode->DevFn);
+	udbg_printf("     - LSlot     = 0x%02X\n",DevNode->LogicalSlot);
+	udbg_printf("     - TceTable  = 0x%p\n  ",DevNode->DevTceTable);
+
+	udbg_printf("     - DSA       = 0x%04X\n",ISERIES_DSA(DevNode)>>32 );
+
+	udbg_printf("                 = Irq:0x%02X Vendor:0x%04X  Flags:0x%02X\n",
+		    DevNode->Irq,
+		    DevNode->Vendor,
+		    DevNode->Flags );
+	udbg_printf("     - Location  = %s\n",DevNode->CardLocation);
+
+
+}
+/**********************************************************************************
+ * Walk down the device node chain 
+ **********************************************************************************/
+void  list_device_nodes(void)
+{
+	struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next;
+	while(Device_Node_Ptr != &iSeries_Global_Device_List) {
+		dumpDevice_Node( (struct iSeries_Device_Node*)Device_Node_Ptr );
+		Device_Node_Ptr = Device_Node_Ptr->next;
+	}
+}
+	
+
+/***********************************************************************
+ * build_device_node(u16 Bus, int SubBus, u8 DevFn)
+ *
+ ***********************************************************************/
+struct iSeries_Device_Node* build_device_node(HvBusNumber Bus, HvSubBusNumber  SubBus, int AgentId, int Function)
+{
+	struct iSeries_Device_Node*  DeviceNode;
+
+	PPCDBG(PPCDBG_BUSWALK,"-build_device_node 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function);
+
+	DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL);
+	if(DeviceNode == NULL) return NULL;
+
+	memset(DeviceNode,0,sizeof(struct iSeries_Device_Node) );
+	list_add_tail(&DeviceNode->Device_List,&iSeries_Global_Device_List);
+	/*DeviceNode->DsaAddr      = ((u64)Bus<<48)+((u64)SubBus<<40)+((u64)0x10<<32); */
+	ISERIES_BUS(DeviceNode)       = Bus;
+	ISERIES_SUBBUS(DeviceNode)    = SubBus;
+	DeviceNode->DsaAddr.deviceId  = 0x10;
+        DeviceNode->DsaAddr.barNumber = 0;
+	DeviceNode->AgentId           = AgentId;
+	DeviceNode->DevFn             = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId),Function );
+	DeviceNode->IoRetry           = 0;
+	iSeries_Get_Location_Code(DeviceNode);
+	PCIFR("Device 0x%02X.%2X, Node:0x%p ",ISERIES_BUS(DeviceNode),ISERIES_DEVFUN(DeviceNode),DeviceNode);
+	return DeviceNode;
+}
+/****************************************************************************
+* 
+* Allocate pci_controller(phb) initialized common variables. 
+* 
+*****************************************************************************/
+struct pci_controller* pci_alloc_pci_controllerX(char *model, enum phb_types controller_type)
+{
+	struct pci_controller *hose;
+	hose = (struct pci_controller*)kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
+	if(hose == NULL) return NULL;
+
+	memset(hose, 0, sizeof(struct pci_controller));
+	if(strlen(model) < 8) strcpy(hose->what,model);
+	else                  memcpy(hose->what,model,7);
+	hose->type = controller_type;
+	hose->global_number = global_phb_number;
+	global_phb_number++;
+
+	*hose_tail = hose;
+	hose_tail = &hose->next;
+	return hose;
+}
+
+/****************************************************************************
+ *
+ * unsigned int __init find_and_init_phbs(void)
+ *
+ * Description:
+ *   This function checks for all possible system PCI host bridges that connect
+ *   PCI buses.  The system hypervisor is queried as to the guest partition
+ *   ownership status.  A pci_controller is build for any bus which is partially
+ *   owned or fully owned by this guest partition.
+ ****************************************************************************/
+unsigned long __init find_and_init_phbs(void)
+{
+	struct      pci_controller* phb;
+	HvBusNumber BusNumber;
+
+	PPCDBG(PPCDBG_BUSWALK,"find_and_init_phbs Entry\n");
+
+	/* Check all possible buses. */
+	for (BusNumber = 0; BusNumber < 256; BusNumber++) {
+		int RtnCode = HvCallXm_testBus(BusNumber);
+		if (RtnCode == 0) {
+			phb = pci_alloc_pci_controllerX("PHB HV", phb_type_hypervisor);
+			if(phb == NULL) {
+				printk("PCI: Allocate pci_controller failed.\n");
+				PCIFR(      "Allocate pci_controller failed.");
+				return -1;
+			}
+			phb->pci_mem_offset = phb->local_number = BusNumber;
+			phb->first_busno  = BusNumber;
+			phb->last_busno   = BusNumber;
+			phb->ops          = &iSeries_pci_ops;
+
+			PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",phb,BusNumber);
+			PCIFR("Create iSeries PHB controller: %04X",BusNumber);
+
+			/***************************************************/
+			/* Find and connect the devices.                   */
+			/***************************************************/
+			iSeries_Scan_PHBs_Slots(phb);
+		}
+		/* Check for Unexpected Return code, a clue that something */
+		/* has gone wrong.                                         */
+		else if(RtnCode != 0x0301) {
+			PCIFR("Unexpected Return on Probe(0x%04X): 0x%04X",BusNumber,RtnCode);
+		}
+
+	}
+	return 0;
+}
+/*********************************************************************** 
+ * ppc64_pcibios_init
+ *  
+ * Chance to initialize and structures or variable before PCI Bus walk.
+ *  
+ *<4>buswalk [swapper : iSeries_pcibios_init Entry.
+ *<4>buswalk [swapper : IoMmTable Initialized 0xC00000000034BD30
+ *<4>buswalk [swapper : find_and_init_phbs Entry
+ *<4>buswalk [swapper : Create iSeries pci_controller:(0xC00000001F5C7000), Bus 0x0017
+ *<4>buswalk [swapper : Connect EADs: 0x17.00.12 = 0x00
+ *<4>buswalk [swapper : iSeries_assign_IRQ   0x0017.00.12 = 0x0091
+ *<4>buswalk [swapper : - allocate and assign IRQ 0x17.00.12 = 0x91
+ *<4>buswalk [swapper : - FoundDevice: 0x17.28.10 = 0x12AE
+ *<4>buswalk [swapper : - build_device_node 0x17.28.12
+ *<4>buswalk [swapper : iSeries_pcibios_init Exit.
+ ***********************************************************************/
+void iSeries_pcibios_init(void)
+{
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Entry.\n"); 
+
+	iSeries_IoMmTable_Initialize();
+
+	find_and_init_phbs();
+
+	pci_assign_all_busses = 0;
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n"); 
+}
+/***********************************************************************
+ * iSeries_pcibios_fixup(void)  
+ ***********************************************************************/
+void __init iSeries_pcibios_fixup(void)
+{
+	struct pci_dev* PciDev;
+	struct iSeries_Device_Node* DeviceNode;
+	char   Buffer[256];
+    	int    DeviceCount = 0;
+
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup Entry.\n"); 
+	/******************************************************/
+	/* Fix up at the device node and pci_dev relationship */
+	/******************************************************/
+	mf_displaySrc(0xC9000100);
+
+	pci_for_each_dev(PciDev) {
+		DeviceNode = find_Device_Node(PciDev);
+		if(DeviceNode != NULL) {
+			++DeviceCount;
+			PciDev->sysdata    = (void*)DeviceNode;
+			DeviceNode->PciDev = PciDev;
+
+			PPCDBG(PPCDBG_BUSWALK,"PciDev 0x%p <==> DevNode 0x%p\n",PciDev,DeviceNode );
+
+			iSeries_allocateDeviceBars(PciDev);
+
+			PPCDBGCALL(PPCDBG_BUSWALK,dumpPci_Dev(PciDev) );
+
+			iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) );
+			printk("%d. %s\n",DeviceCount,Buffer);
+
+			create_pci_bus_tce_table((unsigned long)DeviceNode);
+		} else {
+			printk("PCI: Device Tree not found for 0x%016lX\n",(unsigned long)PciDev);
+		}
+	}
+	iSeries_IoMmTable_Status();
+
+	iSeries_activate_IRQs();
+
+	mf_displaySrc(0xC9000200);
+}
+
+/***********************************************************************
+ * iSeries_pcibios_fixup_bus(int Bus)
+ *
+ ***********************************************************************/
+void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus)
+{
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number); 
+
+}
+
+
+/***********************************************************************
+ * fixup_resources(struct pci_dev *dev) 
+ *	
+ ***********************************************************************/
+void fixup_resources(struct pci_dev *PciDev)
+{
+	PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev);
+}   
+
+
+/********************************************************************************
+* Loop through each node function to find usable EADs bridges.  
+*********************************************************************************/
+void  iSeries_Scan_PHBs_Slots(struct pci_controller* Phb)
+{
+	struct HvCallPci_DeviceInfo* DevInfo;
+	HvBusNumber    Bus       = Phb->local_number;       /* System Bus        */	
+	HvSubBusNumber SubBus    = 0;                       /* EADs is always 0. */
+	int            HvRc      = 0;
+	int            IdSel     = 1;	
+	int            MaxAgents = 8;
+
+	DevInfo    = (struct HvCallPci_DeviceInfo*)kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
+	if(DevInfo == NULL) return;
+
+	/********************************************************************************
+	 * Probe for EADs Bridges      
+	 ********************************************************************************/
+	for (IdSel=1; IdSel < MaxAgents; ++IdSel) {
+    		HvRc = HvCallPci_getDeviceInfo(Bus, SubBus, IdSel,REALADDR(DevInfo), sizeof(struct HvCallPci_DeviceInfo));
+		if (HvRc == 0) {
+			if(DevInfo->deviceType == HvCallPci_NodeDevice) {
+				iSeries_Scan_EADs_Bridge(Bus, SubBus, IdSel);
+			}
+			else printk("PCI: Invalid System Configuration(0x%02X.\n",DevInfo->deviceType);
+		}
+		else pci_Log_Error("getDeviceInfo",Bus, SubBus, IdSel,HvRc);
+	}
+	kfree(DevInfo);
+}
+
+/********************************************************************************
+* 
+*********************************************************************************/
+void  iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel)
+{
+	struct HvCallPci_BridgeInfo* BridgeInfo;
+	HvAgentId      AgentId;
+	int            Function;
+	int            HvRc;
+
+	BridgeInfo = (struct HvCallPci_BridgeInfo*)kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL);
+	if(BridgeInfo == NULL) return;
+
+	/*********************************************************************
+	 * Note: hvSubBus and irq is always be 0 at this level!
+	 *********************************************************************/
+	for (Function=0; Function < 8; ++Function) {
+	  	AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
+		HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, 0);
+ 		if (HvRc == 0) {
+  			/*  Connect EADs: 0x18.00.12 = 0x00 */
+			PPCDBG(PPCDBG_BUSWALK,"PCI:Connect EADs: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId);
+			PCIFR(                    "Connect EADs: 0x%02X.%02X.%02X",  Bus, SubBus, AgentId);
+	    		HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId, 
+			                                REALADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo));
+	 		if (HvRc == 0) {
+				PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
+				       BridgeInfo->busUnitInfo.deviceType,
+				       BridgeInfo->subBusNumber,
+				       BridgeInfo->maxAgents,
+				       BridgeInfo->maxSubBusNumber,
+				       BridgeInfo->logicalSlotNumber);
+				PCIFR(                     "BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X",
+				       BridgeInfo->busUnitInfo.deviceType,
+				       BridgeInfo->subBusNumber,
+				       BridgeInfo->maxAgents,
+				       BridgeInfo->maxSubBusNumber,
+				       BridgeInfo->logicalSlotNumber);
+
+				if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice)  {
+					/* Scan_Bridge_Slot...: 0x18.00.12 */
+					iSeries_Scan_Bridge_Slot(Bus,BridgeInfo);
+				}
+				else printk("PCI: Invalid Bridge Configuration(0x%02X)",BridgeInfo->busUnitInfo.deviceType);
+			}
+    		}
+		else if(HvRc != 0x000B) pci_Log_Error("EADs Connect",Bus,SubBus,AgentId,HvRc);
+	}
+	kfree(BridgeInfo);
+}
+
+/********************************************************************************
+* 
+* This assumes that the node slot is always on the primary bus!
+*
+*********************************************************************************/
+int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* BridgeInfo)
+{
+	struct iSeries_Device_Node* DeviceNode;
+	HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
+	u16       VendorId    = 0;
+	int       HvRc        = 0;
+	int       Irq         = 0;
+	int       IdSel       = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
+	int       Function    = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
+	HvAgentId AgentId     = ISERIES_PCI_AGENTID(IdSel, Function);
+	HvAgentId EADsIdSel   = ISERIES_PCI_AGENTID(IdSel, Function);
+	int       FirstSlotId = 0; 	
+
+	/**********************************************************/
+	/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3)                */
+	/**********************************************************/
+  	Irq   = iSeries_allocate_IRQ(Bus, 0, AgentId);
+	iSeries_assign_IRQ(Irq, Bus, 0, AgentId);
+	PPCDBG(PPCDBG_BUSWALK,"PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",Bus, 0, AgentId, Irq );
+
+	/****************************************************************************
+	 * Connect all functions of any device found.  
+	 ****************************************************************************/
+  	for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
+    		for (Function = 0; Function < 8; ++Function) {
+			AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
+			HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq);
+			if( HvRc == 0) {
+				HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, PCI_VENDOR_ID, &VendorId);
+				if( HvRc == 0) {
+					/**********************************************************/
+					/* FoundDevice: 0x18.28.10 = 0x12AE                       */
+					/**********************************************************/
+					HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq);  
+					PPCDBG(PPCDBG_BUSWALK,"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
+					                                       Bus, SubBus, AgentId, VendorId);
+					++DeviceCount;
+					DeviceNode = build_device_node(Bus, SubBus, EADsIdSel, Function);
+					DeviceNode->Vendor      = VendorId;
+					DeviceNode->Irq         = Irq;
+					DeviceNode->LogicalSlot = BridgeInfo->logicalSlotNumber;
+					PCIFR("Device(%4d): 0x%02X.%02X.%02X 0x%02X 0x%04X",
+					      DeviceCount,Bus, SubBus, AgentId,
+					      DeviceNode->LogicalSlot,DeviceNode->Vendor);
+
+					/***********************************************************
+					 * On the first device/function, assign irq to slot
+					 ***********************************************************/
+					if(Function == 0) { 
+						FirstSlotId = AgentId;
+						// AHT iSeries_assign_IRQ(Irq, Bus, SubBus, AgentId);
+    					}
+				}
+				else pci_Log_Error("Read Vendor",Bus,SubBus,AgentId,HvRc);
+			}
+			else pci_Log_Error("Connect Bus Unit",Bus,SubBus, AgentId,HvRc);
+		} /* for (Function = 0; Function < 8; ++Function) */
+	} /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */
+	return HvRc;
+}
+/************************************************************************/
+/* I/0 Memory copy MUST use mmio commands on iSeries                    */
+/* To do; For performance, include the hv call directly                 */
+/************************************************************************/
+void* iSeries_memset(void* dest, char c, size_t Count)
+{
+	u8    ByteValue     = c;
+	long  NumberOfBytes = Count;
+	char* IoBuffer      = dest;
+	while(NumberOfBytes > 0) {
+		iSeries_Write_Byte( ByteValue, (void*)IoBuffer );
+		++IoBuffer;
+		-- NumberOfBytes;
+	}
+	return dest;
+}	
+void* iSeries_memcpy_toio(void *dest, void *source, size_t count)
+{
+	char *dst           = dest;
+	char *src           = source;
+	long  NumberOfBytes = count;
+	while(NumberOfBytes > 0) {
+		iSeries_Write_Byte(*src++, (void*)dst++);
+		-- NumberOfBytes;
+	}
+	return dest;
+}
+void* iSeries_memcpy_fromio(void *dest, void *source, size_t count)
+{
+	char *dst = dest;
+	char *src = source;
+	long  NumberOfBytes = count;
+	while(NumberOfBytes > 0) {
+		*dst++ = iSeries_Read_Byte( (void*)src++);
+		-- NumberOfBytes;
+	}
+	return dest;
+}
+/**********************************************************************************
+ * Look down the chain to find the matching Device Device
+ **********************************************************************************/
+struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev)
+{
+	struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next;
+	int Bus   = PciDev->bus->number;
+	int DevFn = PciDev->devfn;
+	
+	while(Device_Node_Ptr != &iSeries_Global_Device_List) { 
+		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)Device_Node_Ptr;
+		if(Bus == ISERIES_BUS(DevNode) && DevFn == DevNode->DevFn) {
+			return DevNode;
+		}
+		Device_Node_Ptr = Device_Node_Ptr->next;
+	}
+	return NULL;
+}
+/******************************************************************/
+/* Returns the device node for the passed pci_dev                 */
+/* Sanity Check Node PciDev to passed pci_dev                     */
+/* If none is found, returns a NULL which the client must handle. */
+/******************************************************************/
+struct iSeries_Device_Node* get_Device_Node(struct pci_dev* PciDev)
+{
+	struct iSeries_Device_Node* Node;
+	Node = (struct iSeries_Device_Node*)PciDev->sysdata;
+	if(Node == NULL ) {
+		Node = find_Device_Node(PciDev);
+	}
+	else if(Node->PciDev != PciDev) { 
+		Node = find_Device_Node(PciDev);
+	}
+	return Node;
+}
+/**********************************************************************************
+ *
+ * Read PCI Config Space Code 
+ *
+ **********************************************************************************/
+/** BYTE  *************************************************************************/
+int iSeries_Node_read_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8* ReadValue)
+{
+	u8  ReadData; 
+	if(DevNode == NULL) { return 0x301; } 
+	++Pci_Cfg_Read_Count;
+	DevNode->ReturnCode = HvCallPci_configLoad8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
+	                                                Offset,&ReadData);
+	if(Pci_Trace_Flag == 1) {
+		PCIFR("RCB: 0x%04X.%02X 0x%04X = 0x%02X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData);
+	}
+	if(DevNode->ReturnCode != 0 ) { 
+		printk("PCI: RCB: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+		PCIFR(      "RCB: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+	}
+	*ReadValue = ReadData; 
+ 	return DevNode->ReturnCode;
+}
+/** WORD  *************************************************************************/
+int iSeries_Node_read_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16* ReadValue)
+{
+	u16  ReadData; 
+	if(DevNode == NULL) { return 0x301; } 
+	++Pci_Cfg_Read_Count;
+	DevNode->ReturnCode = HvCallPci_configLoad16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
+	                                                Offset,&ReadData);
+	if(Pci_Trace_Flag == 1) {
+		PCIFR("RCW: 0x%04X.%02X 0x%04X = 0x%04X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData);
+	}
+	if(DevNode->ReturnCode != 0 ) { 
+		printk("PCI: RCW: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+		PCIFR(      "RCW: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+
+	}
+	*ReadValue = ReadData; 
+ 	return DevNode->ReturnCode;
+}
+/** DWORD *************************************************************************/
+int iSeries_Node_read_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32* ReadValue)
+{
+ 	u32  ReadData; 
+	if(DevNode == NULL) { return 0x301; } 
+	++Pci_Cfg_Read_Count;
+	DevNode->ReturnCode = HvCallPci_configLoad32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
+	                                                Offset,&ReadData);
+	if(Pci_Trace_Flag == 1) {
+		PCIFR("RCL: 0x%04X.%02X 0x%04X = 0x%08X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData);
+	}
+	if(DevNode->ReturnCode != 0 ) { 
+		printk("PCI: RCL: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+		PCIFR(      "RCL: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+	}
+	*ReadValue = ReadData; 
+ 	return DevNode->ReturnCode;
+}
+int iSeries_pci_read_config_byte(struct pci_dev* PciDev, int Offset, u8* ReadValue) { 
+	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
+	if(DevNode == NULL) return 0x0301;
+	return iSeries_Node_read_config_byte( DevNode ,Offset,ReadValue);
+}
+int iSeries_pci_read_config_word(struct pci_dev* PciDev, int Offset, u16* ReadValue) { 
+	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
+	if(DevNode == NULL) return 0x0301;
+	return iSeries_Node_read_config_word( DevNode ,Offset,ReadValue );
+}
+int iSeries_pci_read_config_dword(struct pci_dev* PciDev, int Offset, u32* ReadValue) { 
+	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
+	if(DevNode == NULL) return 0x0301;
+	return iSeries_Node_read_config_dword(DevNode ,Offset,ReadValue  );
+}
+/**********************************************************************************/
+/*                                                                                */
+/* Write PCI Config Space                                                         */
+/*                                                                                */
+/** BYTE  *************************************************************************/
+int iSeries_Node_write_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8 WriteData)
+{
+	++Pci_Cfg_Write_Count;
+	DevNode->ReturnCode = HvCallPci_configStore8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
+	                                                  Offset,WriteData);
+	if(Pci_Trace_Flag == 1) {
+		PCIFR("WCB: 0x%04X.%02X 0x%04X = 0x%02X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData);
+	}
+	if(DevNode->ReturnCode != 0 ) { 
+		printk("PCI: WCB: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+		PCIFR(      "WCB: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+	}
+ 	return DevNode->ReturnCode;
+}
+/** WORD  *************************************************************************/
+int iSeries_Node_write_config_word(struct iSeries_Device_Node* DevNode, int Offset, u16 WriteData)
+{
+	++Pci_Cfg_Write_Count;
+	DevNode->ReturnCode = HvCallPci_configStore16(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
+	                                                  Offset,WriteData);
+	if(Pci_Trace_Flag == 1) {
+		PCIFR("WCW: 0x%04X.%02X 0x%04X = 0x%04X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData);
+	}
+	if(DevNode->ReturnCode != 0 ) { 
+		printk("PCI: WCW: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+		PCIFR(      "WCW: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+	}
+ 	return DevNode->ReturnCode;
+}
+/** DWORD *************************************************************************/
+int iSeries_Node_write_config_dword(struct iSeries_Device_Node* DevNode, int Offset, u32 WriteData)
+{
+	++Pci_Cfg_Write_Count;
+	DevNode->ReturnCode = HvCallPci_configStore32(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
+	                                                  Offset,WriteData);
+	if(Pci_Trace_Flag == 1) {
+		PCIFR("WCL: 0x%04X.%02X 0x%04X = 0x%08X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData);
+	}
+	if(DevNode->ReturnCode != 0 ) { 
+		printk("PCI: WCL: 0x%04X.%02X  Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+		PCIFR(      "WCL: 0x%04X.%02X  Error: 0x%04X",  ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
+	}
+	return DevNode->ReturnCode;
+}
+int iSeries_pci_write_config_byte( struct pci_dev* PciDev,int Offset, u8 WriteValue)
+{
+	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
+	if(DevNode == NULL) return 0x0301;
+	return iSeries_Node_write_config_byte( DevNode,Offset,WriteValue);
+}
+int iSeries_pci_write_config_word( struct pci_dev* PciDev,int Offset,u16 WriteValue)
+{
+	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
+	if(DevNode == NULL) return 0x0301;
+	return iSeries_Node_write_config_word( DevNode,Offset,WriteValue);
+}
+int iSeries_pci_write_config_dword(struct pci_dev* PciDev,int Offset,u32 WriteValue)
+{
+	struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
+	if(DevNode == NULL) return 0x0301;
+	return iSeries_Node_write_config_dword(DevNode,Offset,WriteValue);
+}
+
+/************************************************************************/
+/* Branch Table                                                         */
+/************************************************************************/
+struct pci_ops iSeries_pci_ops = {
+	iSeries_pci_read_config_byte,
+	iSeries_pci_read_config_word,
+	iSeries_pci_read_config_dword,
+	iSeries_pci_write_config_byte,
+	iSeries_pci_write_config_word,
+	iSeries_pci_write_config_dword 
+};
+
+/************************************************************************
+ * Check Return Code
+ * -> On Failure, print and log information.
+ *    Increment Retry Count, if exceeds max, panic partition.
+ * -> If in retry, print and log success 
+ ************************************************************************
+ * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
+ * PCI: Device 23.90 ReadL Retry( 1)
+ * PCI: Device 23.90 ReadL Retry Successful(1)
+ ************************************************************************/
+int  CheckReturnCode(char* TextHdr, struct iSeries_Device_Node* DevNode, u64 RtnCode)
+{
+	if(RtnCode != 0)  {
+		++Pci_Error_Count;
+		++DevNode->IoRetry;
+		PCIFR(      "%s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X",
+			    TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode);
+		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
+		            TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry,(int)RtnCode);
+		/*******************************************************/
+		/* Bump the retry and check for retry count exceeded.  */
+		/* If, Exceeded, panic the system.                     */           
+		/*******************************************************/
+		if(DevNode->IoRetry > Pci_Retry_Max && Pci_Error_Flag > 0 ) {
+			mf_displaySrc(0xB6000103);
+			panic_timeout = 0; 
+			panic("PCI: Hardware I/O Error, SRC B6000103, Automatic Reboot Disabled.\n");
+		}
+		return -1;	/* Retry Try */
+	}
+	/********************************************************************
+	* If retry was in progress, log success and rest retry count        *
+	*********************************************************************/
+	else if(DevNode->IoRetry > 0) {
+		PCIFR("%s: Device 0x%04X:%02X Retry Successful(%2d).",
+		      TextHdr,ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->IoRetry);
+		DevNode->IoRetry = 0;
+		return 0; 
+	}
+	return 0; 
+}
+/************************************************************************/
+/* Translate the I/O Address into a device node, bar, and bar offset.   */
+/* Note: Make sure the passed variable end up on the stack to avoid     */
+/* the exposure of being device global.                                 */
+/************************************************************************/
+static inline struct iSeries_Device_Node* xlateIoMmAddress(void* IoAddress,
+							    union HvDsaMap* DsaPtr,
+							   u64* BarOffsetPtr) {
+
+	unsigned long BaseIoAddr = (unsigned long)IoAddress-iSeries_Base_Io_Memory;
+	long          TableIndex = BaseIoAddr/iSeries_IoMmTable_Entry_Size;
+	struct iSeries_Device_Node* DevNode = *(iSeries_IoMmTable +TableIndex);
+	if(DevNode != NULL) {
+		DsaPtr->DsaAddr       = ISERIES_DSA(DevNode);
+		DsaPtr->Dsa.barNumber = *(iSeries_IoBarTable+TableIndex);
+		*BarOffsetPtr         = BaseIoAddr % iSeries_IoMmTable_Entry_Size;
+	}
+	else {
+		panic("PCI: Invalid PCI IoAddress detected!\n");
+	}
+	return DevNode;
+}
+
+/************************************************************************/
+/* Read MM I/O Instructions for the iSeries                             */
+/* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal*/
+/* else, data is returned in big Endian format.                         */
+/************************************************************************/
+/* iSeries_Read_Byte = Read Byte  ( 8 bit)                              */
+/* iSeries_Read_Word = Read Word  (16 bit)                              */
+/* iSeries_Read_Long = Read Long  (32 bit)                              */
+/************************************************************************/
+u8  iSeries_Read_Byte(void* IoAddress)
+{
+	u64    BarOffset;
+	union  HvDsaMap DsaData;
+	struct HvCallPci_LoadReturn Return;
+	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
+
+	do {
+		++Pci_Io_Read_Count;
+		HvCall3Ret16(HvCallPciBarLoad8, &Return, DsaData.DsaAddr,BarOffset, 0);
+	} while (CheckReturnCode("RDB",DevNode, Return.rc) != 0);
+
+	if(Pci_Trace_Flag == 1)	PCIFR("RDB: IoAddress 0x%p = 0x%02X",IoAddress, (u8)Return.value); 
+	return (u8)Return.value;
+}
+u16  iSeries_Read_Word(void* IoAddress)
+{
+	u64    BarOffset;
+	union  HvDsaMap DsaData;
+	struct HvCallPci_LoadReturn Return;
+	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
+
+	do {
+		++Pci_Io_Read_Count;
+		HvCall3Ret16(HvCallPciBarLoad16,&Return, DsaData.DsaAddr,BarOffset, 0);
+	} while (CheckReturnCode("RDW",DevNode, Return.rc) != 0);
+
+	if(Pci_Trace_Flag == 1) PCIFR("RDW: IoAddress 0x%p = 0x%04X",IoAddress, swab16((u16)Return.value));
+	return swab16((u16)Return.value);
+}
+u32  iSeries_Read_Long(void* IoAddress)
+{
+	u64    BarOffset;
+	union  HvDsaMap DsaData;
+	struct HvCallPci_LoadReturn Return;
+	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
+
+	do {
+		++Pci_Io_Read_Count;
+		HvCall3Ret16(HvCallPciBarLoad32,&Return, DsaData.DsaAddr,BarOffset, 0);
+	} while (CheckReturnCode("RDL",DevNode, Return.rc) != 0);
+
+	if(Pci_Trace_Flag == 1) PCIFR("RDL: IoAddress 0x%p = 0x%04X",IoAddress, swab32((u32)Return.value));
+	return swab32((u32)Return.value);
+}
+/************************************************************************/
+/* Write MM I/O Instructions for the iSeries                            */
+/************************************************************************/
+/* iSeries_Write_Byte = Write Byte (8 bit)                              */
+/* iSeries_Write_Word = Write Word(16 bit)                              */
+/* iSeries_Write_Long = Write Long(32 bit)                              */
+/************************************************************************/
+void iSeries_Write_Byte(u8 Data, void* IoAddress)
+{
+	u64    BarOffset;
+	union  HvDsaMap DsaData;
+	struct HvCallPci_LoadReturn Return;
+	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
+
+	do {
+		++Pci_Io_Write_Count;
+		Return.rc = HvCall4(HvCallPciBarStore8, DsaData.DsaAddr,BarOffset, Data, 0);
+	} while (CheckReturnCode("WWB",DevNode, Return.rc) != 0);
+	if(Pci_Trace_Flag == 1) PCIFR("WWB: IoAddress 0x%p = 0x%02X",IoAddress,Data);
+}
+void iSeries_Write_Word(u16 Data, void* IoAddress)
+{
+	u64    BarOffset;
+	union  HvDsaMap DsaData;
+	struct HvCallPci_LoadReturn Return;
+	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
+
+	do {
+		++Pci_Io_Write_Count;
+		Return.rc = HvCall4(HvCallPciBarStore16,DsaData.DsaAddr,BarOffset, swab16(Data), 0);
+	} while (CheckReturnCode("WWW",DevNode, Return.rc) != 0);
+	if(Pci_Trace_Flag == 1) PCIFR("WWW: IoAddress 0x%p = 0x%04X",IoAddress,Data);
+}
+void iSeries_Write_Long(u32 Data, void* IoAddress)
+{
+	u64    BarOffset;
+	union  HvDsaMap DsaData;
+	struct HvCallPci_LoadReturn Return;
+	struct iSeries_Device_Node* DevNode = xlateIoMmAddress(IoAddress,&DsaData,&BarOffset);
+
+	do {
+		++Pci_Io_Write_Count;
+		Return.rc = HvCall4(HvCallPciBarStore32,DsaData.DsaAddr,BarOffset, swab32(Data), 0);
+	} while (CheckReturnCode("WWL",DevNode, Return.rc) != 0);
+	if(Pci_Trace_Flag == 1) PCIFR("WWL: IoAddress 0x%p = 0x%08X",IoAddress, Data);
+}
+/*
+ * This is called very early before the page table is setup.
+ * There are warnings here because of type mismatches.. Okay for now. AHT
+ */
+void 
+iSeries_pcibios_init_early(void)
+{
+	//ppc_md.pcibios_read_config_byte   = iSeries_Node_read_config_byte;
+	//ppc_md.pcibios_read_config_word   = iSeries_Node_read_config_word;
+	//ppc_md.pcibios_read_config_dword  = iSeries_Node_read_config_dword;
+	//ppc_md.pcibios_write_config_byte  = iSeries_Node_write_config_byte;
+	//ppc_md.pcibios_write_config_word  = iSeries_Node_write_config_word;
+	//ppc_md.pcibios_write_config_dword = iSeries_Node_write_config_dword;
+}
+
+/************************************************************************/
+/* Set the slot reset line to the state passed in.                      */
+/* This is the platform specific for code for the pci_reset_device      */
+/* function.                                                            */
+/************************************************************************/
+int pci_set_reset(struct pci_dev* PciDev, int State) {
+	struct iSeries_Device_Node* DeviceNode = (struct iSeries_Device_Node*)PciDev->sysdata;
+ 	if (DeviceNode == NULL) { 
+		printk("PCI: Pci Reset Failed, Device Node not found for pci_dev %p\n",PciDev);
+		return -1;
+	}
+	DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),0x00,DeviceNode->AgentId,State);
+	return DeviceNode->ReturnCode;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_pci_reset.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci_reset.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_pci_reset.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_pci_reset.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,88 @@
+/************************************************************************/
+/* File iSeries_pci_reset.c created by Allan Trautman on Mar 21 2001.   */
+/************************************************************************/
+/* This code supports the pci interface on the IBM iSeries systems.     */
+/* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, March 20, 2001                                            */
+/*   April 30, 2001, Added return codes on functions.                   */
+/*   September 10, 2001, Ported to ppc64.                               */
+/* End Change Activity                                                  */
+/************************************************************************/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/init.h>
+#include <asm/iSeries/HvCallPci.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/mf.h>
+#include <asm/flight_recorder.h>
+#include <asm/pci.h>
+
+#include <asm/iSeries/iSeries_pci.h>
+#include "pci.h"
+
+/************************************************************************/
+/* Interface to toggle the reset line                                   */
+/* Time is in .1 seconds, need for seconds.                             */
+/************************************************************************/
+int  iSeries_Device_ToggleReset(struct pci_dev* PciDev, int AssertTime, int DelayTime)
+{
+	unsigned long AssertDelay, WaitDelay;
+	struct iSeries_Device_Node* DeviceNode = (struct iSeries_Device_Node*)PciDev->sysdata;
+ 	if (DeviceNode == NULL) { 
+		printk("PCI: Pci Reset Failed, Device Node not found for pci_dev %p\n",PciDev);
+		return -1;
+	}
+	/********************************************************************
+	 * Set defaults, Assert is .5 second, Wait is 3 seconds.
+	 ********************************************************************/
+	if (AssertTime == 0) AssertDelay = ( 5 * HZ)/10;
+	else                 AssertDelay = (AssertTime*HZ)/10;
+	if (WaitDelay == 0)  WaitDelay   = (30 * HZ)/10;
+	else                 WaitDelay   = (DelayTime* HZ)/10;
+
+	/********************************************************************
+	 * Assert reset
+	 ********************************************************************/
+	DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),0x00,DeviceNode->AgentId,1);
+	if (DeviceNode->ReturnCode == 0) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(AssertDelay);       /* Sleep for the time     */
+		DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode),0x00,DeviceNode->AgentId, 0);
+
+		/***************************************************************
+   		 * Wait for device to reset
+		 ***************************************************************/
+		set_current_state(TASK_UNINTERRUPTIBLE);  
+		schedule_timeout(WaitDelay);
+	}
+	if (DeviceNode->ReturnCode == 0) {
+		PCIFR("Slot 0x%04X.%02 Reset\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId );
+	} 
+	else {
+		printk("PCI: Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId,DeviceNode->ReturnCode);
+		PCIFR(      "Slot 0x%04X.%02X Reset Failed, RCode: %04X\n",ISERIES_BUS(DeviceNode),DeviceNode->AgentId,DeviceNode->ReturnCode);
+	}
+	return DeviceNode->ReturnCode;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_proc.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_proc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_proc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_proc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,142 @@
+/*
+  * iSeries_proc.c
+  * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
+  * 
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+  */
+
+
+/* Change Activity: */
+/* End Change Activity */
+
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#ifndef _ISERIES_PROC_H
+#include <asm/iSeries/iSeries_proc.h>
+#endif
+
+
+static struct proc_dir_entry * iSeries_proc_root = NULL;
+static int iSeries_proc_initializationDone = 0;
+static spinlock_t iSeries_proc_lock;
+
+struct iSeries_proc_registration
+{
+	struct iSeries_proc_registration *next;
+	iSeriesProcFunction functionMember;
+};
+
+
+struct iSeries_proc_registration preallocated[16];
+#define MYQUEUETYPE(T) struct MYQueue##T
+#define MYQUEUE(T) \
+MYQUEUETYPE(T) \
+{ \
+	struct T *head; \
+	struct T *tail; \
+}
+#define MYQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; } while(0)
+#define MYQUEUEENQ(q, p) \
+do { \
+	(p)->next = NULL; \
+	if ((q)->head != NULL) { \
+		(q)->head->next = (p); \
+		(q)->head = (p); \
+	} else { \
+		(q)->tail = (q)->head = (p); \
+	} \
+} while(0)
+
+#define MYQUEUEDEQ(q,p) \
+do { \
+	(p) = (q)->tail; \
+	if ((p) != NULL) { \
+		(q)->tail = (p)->next; \
+		(p)->next = NULL; \
+	} \
+	if ((q)->tail == NULL) \
+		(q)->head = NULL; \
+} while(0)
+MYQUEUE(iSeries_proc_registration);
+typedef MYQUEUETYPE(iSeries_proc_registration) aQueue;
+
+
+aQueue iSeries_free;
+aQueue iSeries_queued;
+
+void iSeries_proc_early_init(void)
+{
+	int i = 0;
+	unsigned long flags;
+	iSeries_proc_initializationDone = 0;
+	spin_lock_init(&iSeries_proc_lock);
+	MYQUEUECTOR(&iSeries_free);
+	MYQUEUECTOR(&iSeries_queued);
+
+	spin_lock_irqsave(&iSeries_proc_lock, flags);
+	for (i = 0; i < 16; ++i) {
+		MYQUEUEENQ(&iSeries_free, preallocated+i);
+	}
+	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
+}
+
+void iSeries_proc_create(void)
+{
+	unsigned long flags;
+	struct iSeries_proc_registration *reg = NULL;
+	spin_lock_irqsave(&iSeries_proc_lock, flags);
+	printk("iSeries_proc: Creating /proc/iSeries\n");
+
+	iSeries_proc_root = proc_mkdir("iSeries", 0);
+	if (!iSeries_proc_root) return;
+
+	MYQUEUEDEQ(&iSeries_queued, reg);
+
+	while (reg != NULL) {
+		(*(reg->functionMember))(iSeries_proc_root);
+
+		MYQUEUEDEQ(&iSeries_queued, reg);
+	}
+
+	iSeries_proc_initializationDone = 1;
+	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
+}
+
+void iSeries_proc_callback(iSeriesProcFunction initFunction)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&iSeries_proc_lock, flags);
+
+	if (iSeries_proc_initializationDone) {
+		(*initFunction)(iSeries_proc_root);
+	} else {
+		struct iSeries_proc_registration *reg = NULL;
+
+		MYQUEUEDEQ(&iSeries_free, reg);
+
+		if (reg != NULL) {
+			/* printk("Registering %p in reg %p\n", initFunction, reg); */
+			reg->functionMember = initFunction;
+
+			MYQUEUEENQ(&iSeries_queued, reg);
+		} else {
+			printk("Couldn't get a queue entry\n");
+		}
+	}
+
+	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
+}
+
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_rtc.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_rtc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_rtc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_rtc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,264 @@
+/*
+ *	Real Time Clock interface for IBM iSeries	
+ *
+ *	Based on rtc.c by Paul Gortmaker
+ *
+ *	This driver allows use of the real time clock
+ *	from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the
+ *	/proc/driver/rtc pseudo-file for status information.
+ *
+ * 	iSeries does not support RTC interrupts nor an alarm.
+ *
+ *	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.
+ *
+ *      1.0	Mike Corrigan: IBM iSeries rtc support
+ */
+
+#define RTC_VERSION		"1.0"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <asm/iSeries/mf.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin);
+
+static ssize_t rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos);
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg);
+
+static void get_rtc_time (struct rtc_time *rtc_tm);
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data);
+
+/*
+ *	If this driver ever becomes modularised, it will be really nice
+ *	to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900;	/* year corresponding to 0x00	*/
+
+static const unsigned char days_in_mo[] = 
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ *	Now all the various file operations that we export.
+ */
+
+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	return -EIO;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	struct rtc_time wtime; 
+
+	switch (cmd) {
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+	{
+		get_rtc_time(&wtime);
+		break;
+	}
+	case RTC_SET_TIME:	/* Set the RTC */
+	{
+		struct rtc_time rtc_tm;
+		unsigned char mon, day, hrs, min, sec, leap_yr;
+		unsigned int yrs;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		yrs = rtc_tm.tm_year;
+		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+		day = rtc_tm.tm_mday;
+		hrs = rtc_tm.tm_hour;
+		min = rtc_tm.tm_min;
+		sec = rtc_tm.tm_sec;
+
+		if (yrs < 70)
+			return -EINVAL;
+
+		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+		if ((mon > 12) || (day == 0))
+			return -EINVAL;
+
+		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+			return -EINVAL;
+			
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+			return -EINVAL;
+
+		if ( yrs > 169 )
+			return -EINVAL;
+
+		mf_setRtc( &rtc_tm );
+		
+		return 0;
+	}
+	case RTC_EPOCH_READ:	/* Read the epoch.	*/
+	{
+		return put_user (epoch, (unsigned long *)arg);
+	}
+	case RTC_EPOCH_SET:	/* Set the epoch.	*/
+	{
+		/* 
+		 * There were no RTC clocks before 1900.
+		 */
+		if (arg < 1900)
+			return -EINVAL;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		epoch = arg;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+	owner:		THIS_MODULE,
+	llseek:		rtc_llseek,
+	read:		rtc_read,
+	ioctl:		rtc_ioctl,
+	open:		rtc_open,
+	release:	rtc_release,
+};
+
+static struct miscdevice rtc_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+static int __init rtc_init(void)
+{
+	misc_register(&rtc_dev);
+	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
+
+	printk(KERN_INFO "iSeries Real Time Clock Driver v" RTC_VERSION "\n");
+
+	return 0;
+}
+
+static void __exit rtc_exit (void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister(&rtc_dev);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+EXPORT_NO_SYMBOLS;
+
+/*
+ *	Info exported via "/proc/driver/rtc".
+ */
+
+static int rtc_proc_output (char *buf)
+{
+	
+	char *p;
+	struct rtc_time tm;
+	
+	p = buf;
+
+	get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+	 	     "rtc_epoch\t: %04lu\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+
+	p += sprintf(p,
+		     "DST_enable\t: no\n"
+		     "BCD\t\t: yes\n"
+		     "24hr\t\t: yes\n" );
+
+	return  p - buf;
+}
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+        int len = rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+static void get_rtc_time(struct rtc_time *rtc_tm)
+{
+	mf_getRtc( rtc_tm );
+
+	rtc_tm->tm_mon--;
+}
+
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_setup.c linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_setup.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,901 @@
+/*
+ * 
+ *
+ *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: iSeries_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM iSeries LPAR.  Adapted from original code by Grant Erickson and
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+ 
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/blk.h>
+#include <linux/seq_file.h>
+
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+
+#include <asm/time.h>
+#include "iSeries_setup.h"
+#include <asm/Naca.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/HvCallHpt.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/HvCallEvent.h>
+#include <asm/iSeries/HvCallSm.h>
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/IoHriMainStore.h>
+#include <asm/iSeries/iSeries_proc.h>
+#include <asm/proc_pmc.h>
+#include <asm/iSeries/mf.h>
+
+/* Function Prototypes */
+
+extern void abort(void);
+#ifdef CONFIG_PPC_ISERIES
+static void build_iSeries_Memory_Map( void );
+static void setup_iSeries_cache_sizes( void );
+static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
+#endif
+void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
+		       pte_t * ptep, unsigned hpteflags, unsigned bolted );
+extern void ppcdbg_initialize(void);
+extern void iSeries_pcibios_init(void);
+extern void iSeries_pcibios_fixup(void);
+extern void iSeries_pcibios_fixup_bus(int);
+static void iSeries_setup_dprofile(void);
+
+/* Global Variables */
+
+static unsigned long procFreqHz = 0;
+static unsigned long procFreqMhz = 0;
+static unsigned long procFreqMhzHundreths = 0;
+
+static unsigned long tbFreqHz = 0;
+static unsigned long tbFreqMhz = 0;
+static unsigned long tbFreqMhzHundreths = 0;
+
+unsigned long dprof_shift = 0;
+unsigned long dprof_len = 0;
+unsigned int * dprof_buffer = NULL;
+
+int piranha_simulator = 0;
+
+extern char _end[];
+
+extern struct Naca *naca;
+extern int rd_size;		/* Defined in drivers/block/rd.c */
+extern unsigned long klimit;
+extern unsigned long embedded_sysmap_start;
+extern unsigned long embedded_sysmap_end;
+
+extern unsigned long iSeries_recal_tb;
+extern unsigned long iSeries_recal_titan;
+
+extern char _stext;
+extern char _etext;
+
+static int mf_initialized = 0;
+
+struct MemoryBlock {
+	unsigned long absStart;
+	unsigned long absEnd;
+	unsigned long logicalStart;
+	unsigned long logicalEnd;
+};
+
+/*
+ * Process the main store vpd to determine where the holes in memory are
+ * and return the number of physical blocks and fill in the array of
+ * block data.
+ */
+
+unsigned long iSeries_process_Condor_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries )
+{
+	/* Determine if absolute memory has any
+	 * holes so that we can interpret the
+	 * access map we get back from the hypervisor
+	 * correctly.
+	 */
+	
+	unsigned long holeFirstChunk, holeSizeChunks;
+	unsigned long numMemoryBlocks = 1;
+	struct IoHriMainStoreSegment4 * msVpd = (struct IoHriMainStoreSegment4 *)xMsVpd;
+	unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;
+	unsigned long holeEnd   = msVpd->nonInterleavedBlocksEndAdr;
+	unsigned long holeSize = holeEnd - holeStart;
+
+	printk("Mainstore_VPD: Condor\n");
+
+	mb_array[0].logicalStart = 0;
+	mb_array[0].logicalEnd   = 0x100000000;
+	mb_array[0].absStart     = 0;
+	mb_array[0].absEnd       = 0x100000000;
+
+	if ( holeSize ) {
+		numMemoryBlocks = 2;
+		holeStart = holeStart & 0x000fffffffffffff;
+		holeStart = addr_to_chunk(holeStart);
+		holeFirstChunk = holeStart;
+		holeSize = addr_to_chunk(holeSize);
+		holeSizeChunks = holeSize;
+		printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n",
+				holeFirstChunk, holeSizeChunks );
+		mb_array[0].logicalEnd   = holeFirstChunk;
+		mb_array[0].absEnd       = holeFirstChunk;
+		mb_array[1].logicalStart = holeFirstChunk;
+		mb_array[1].logicalEnd   = 0x100000000 - holeSizeChunks;
+		mb_array[1].absStart     = holeFirstChunk + holeSizeChunks;
+		mb_array[1].absEnd       = 0x100000000;
+	}
+
+	
+	return numMemoryBlocks;
+}
+
+#define MaxSegmentAreas 32
+#define MaxSegmentAdrRangeBlocks 128
+#define MaxAreaRangeBlocks 4
+unsigned long iSeries_process_Regatta_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries )
+{
+	struct IoHriMainStoreSegment5 * msVpdP = (struct IoHriMainStoreSegment5 *)xMsVpd;
+	unsigned long numSegmentBlocks = 0;
+	u32 existsBits = msVpdP->msAreaExists;
+	unsigned long area_num;
+
+	printk("Mainstore_VPD: Regatta\n");
+
+	for ( area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {
+		unsigned long numAreaBlocks;
+		struct IoHriMainStoreArea4 * currentArea;
+
+		if ( existsBits & 0x80000000 ) {
+			unsigned long block_num;
+
+			currentArea = &msVpdP->msAreaArray[area_num];
+			numAreaBlocks = currentArea->numAdrRangeBlocks;
+
+			printk("ms_vpd: processing area %2ld  blocks=%ld", area_num, numAreaBlocks);
+
+			for ( block_num = 0; block_num < numAreaBlocks; ++block_num ) {
+				/* Process an address range block */
+				struct MemoryBlock tempBlock;
+				unsigned long i;
+
+				tempBlock.absStart = (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;
+				tempBlock.absEnd   = (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;
+				tempBlock.logicalStart = 0;
+				tempBlock.logicalEnd   = 0;
+
+				printk("\n          block %ld absStart=%016lx absEnd=%016lx", block_num,
+							tempBlock.absStart, tempBlock.absEnd);
+
+				for ( i=0; i<numSegmentBlocks; ++i ) {
+					if ( mb_array[i].absStart == tempBlock.absStart )
+						break;
+				}
+				if ( i == numSegmentBlocks ) {
+					if ( numSegmentBlocks == max_entries ) {
+						panic("iSeries_process_mainstore_vpd: too many memory blocks");
+					}
+					mb_array[numSegmentBlocks] = tempBlock;
+					++numSegmentBlocks;
+				}
+				else {
+					printk(" (duplicate)");
+				}
+			}
+			printk("\n");
+		}
+		existsBits <<= 1;
+	}
+	/* Now sort the blocks found into ascending sequence */
+	if ( numSegmentBlocks > 1 ) {
+		unsigned long m, n;
+		for ( m=0; m<numSegmentBlocks-1; ++m ) {
+			for ( n=numSegmentBlocks-1; m<n; --n ) {
+				if ( mb_array[n].absStart < mb_array[n-1].absStart ) {
+					struct MemoryBlock tempBlock;
+					tempBlock = mb_array[n];
+					mb_array[n] = mb_array[n-1];
+					mb_array[n-1] = tempBlock;
+				}
+				
+			}
+		}
+	}
+	/* Assign "logical" addresses to each block.  These
+	 * addresses correspond to the hypervisor "bitmap" space.
+	 * Convert all addresses into units of 256K chunks.
+	 */
+	{
+	unsigned long i, nextBitmapAddress;
+	printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks);
+	nextBitmapAddress = 0;
+	for ( i=0; i<numSegmentBlocks; ++i ) {
+		unsigned long length = mb_array[i].absEnd - mb_array[i].absStart;
+		mb_array[i].logicalStart = nextBitmapAddress;
+		mb_array[i].logicalEnd = nextBitmapAddress + length;
+		nextBitmapAddress += length;
+		printk("          Bitmap range: %016lx - %016lx\n"
+		       "        Absolute range: %016lx - %016lx\n",
+				mb_array[i].logicalStart, mb_array[i].logicalEnd, 
+				mb_array[i].absStart, mb_array[i].absEnd);
+		mb_array[i].absStart     = addr_to_chunk( mb_array[i].absStart & 0x000fffffffffffff );
+		mb_array[i].absEnd       = addr_to_chunk( mb_array[i].absEnd & 0x000fffffffffffff );
+		mb_array[i].logicalStart = addr_to_chunk( mb_array[i].logicalStart );
+		mb_array[i].logicalEnd   = addr_to_chunk( mb_array[i].logicalEnd );
+	}
+	}
+
+	return numSegmentBlocks;
+
+}
+
+unsigned long iSeries_process_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries )
+{
+	unsigned long i;
+	unsigned long mem_blocks = 0;
+	if ( __is_processor( PV_POWER4 ) )
+		mem_blocks = iSeries_process_Regatta_mainstore_vpd( mb_array, max_entries );
+	else
+		mem_blocks = iSeries_process_Condor_mainstore_vpd( mb_array, max_entries );
+
+	printk("Mainstore_VPD: numMemoryBlocks = %ld \n", mem_blocks);
+	for ( i=0; i<mem_blocks; ++i ) {
+		printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n"
+		       "                             abs chunks %016lx - %016lx\n",
+			i, mb_array[i].logicalStart, mb_array[i].logicalEnd,
+			mb_array[i].absStart, mb_array[i].absEnd);
+	}
+
+	return mem_blocks;
+}
+
+/*
+ * void __init iSeries_init_early()
+ */
+
+
+
+void __init
+iSeries_init_early(void)
+{
+#ifdef CONFIG_PPC_ISERIES
+	ppcdbg_initialize();
+	
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured and there is
+	 * a non-zero starting address for it, set it up
+	 */
+
+	if ( naca->xRamDisk ) {
+		initrd_start = (unsigned long)__va(naca->xRamDisk);
+		initrd_end   = initrd_start + naca->xRamDiskSize * PAGE_SIZE;
+		initrd_below_start_ok = 1;	// ramdisk in kernel space
+		ROOT_DEV = MKDEV( RAMDISK_MAJOR, 0 );
+
+		if ( ((rd_size*1024)/PAGE_SIZE) < naca->xRamDiskSize )
+			rd_size = (naca->xRamDiskSize*PAGE_SIZE)/1024;
+	} else
+	
+#endif /* CONFIG_BLK_DEV_INITRD */
+	  {
+                
+	    /*		ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 ); */
+	  }
+
+	iSeries_recal_tb = get_tb();
+	iSeries_recal_titan = HvCallXm_loadTod();
+
+	ppc_md.setup_arch	 	= iSeries_setup_arch;
+	ppc_md.setup_residual	 	= iSeries_setup_residual;
+	ppc_md.get_cpuinfo	 	= iSeries_get_cpuinfo;
+	ppc_md.irq_cannonicalize 	= NULL;
+	ppc_md.init_IRQ		 	= iSeries_init_IRQ;
+	ppc_md.init_ras_IRQ		= NULL;
+	ppc_md.get_irq		 	= iSeries_get_irq;
+	ppc_md.init		 	= NULL;
+
+ 	ppc_md.pcibios_fixup        = iSeries_pcibios_fixup;
+	ppc_md.pcibios_fixup_bus    = iSeries_pcibios_fixup_bus;
+
+	ppc_md.restart		 	= iSeries_restart;
+	ppc_md.power_off	 	= iSeries_power_off;
+	ppc_md.halt		 	= iSeries_halt;
+
+	ppc_md.time_init	 	= NULL;
+	ppc_md.get_boot_time    = iSeries_get_boot_time;
+	ppc_md.set_rtc_time	 	= iSeries_set_rtc_time;
+	ppc_md.get_rtc_time	 	= iSeries_get_rtc_time;
+	ppc_md.calibrate_decr	 	= iSeries_calibrate_decr;
+	ppc_md.progress			= iSeries_progress;
+
+	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;
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
+#endif
+	
+	hpte_init_iSeries();
+	tce_init_iSeries();
+
+	/* Initialize the table which translate Linux physical addresses to
+	 * AS/400 absolute addresses
+	 */
+
+	build_iSeries_Memory_Map();
+
+	setup_iSeries_cache_sizes();
+
+	/* Initialize machine-dependency vectors */
+
+
+#ifdef CONFIG_SMP
+	smp_init_iSeries();
+#endif
+
+	if ( itLpNaca.xPirEnvironMode == 0 ) 
+		piranha_simulator = 1;
+#endif
+}
+
+/*
+ * void __init iSeries_init()
+ */
+
+void __init
+iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5, 
+	   unsigned long r6, unsigned long r7)
+{
+	/* Associate Lp Event Queue 0 with processor 0 */
+	HvCallEvent_setLpEventQueueInterruptProc( 0, 0 );
+
+	{
+		/* copy the command line parameter from the primary VSP  */
+		char *p, *q;
+		HvCallEvent_dmaToSp( cmd_line,
+				     2*64*1024,
+				     256,
+				     HvLpDma_Direction_RemoteToLocal );
+
+		p = q = cmd_line + 255;
+		while( p > cmd_line ) {
+			if ((*p == 0) || (*p == ' ') || (*p == '\n'))
+				--p;
+			else
+				break;
+		}
+		if ( p < q )
+			*(p+1) = 0;
+	}
+
+        if (strstr(cmd_line, "dprofile=")) {
+                char *p, *q;
+
+                for (q = cmd_line; (p = strstr(q, "dprofile=")) != 0; ) {
+			unsigned long size, new_klimit;
+                        q = p + 9;
+                        if (p > cmd_line && p[-1] != ' ')
+                                continue;
+                        dprof_shift = simple_strtoul(q, &q, 0);
+			dprof_len = (unsigned long)&_etext - (unsigned long)&_stext;
+			dprof_len >>= dprof_shift;
+			size = ((dprof_len * sizeof(unsigned int)) + (PAGE_SIZE-1)) & PAGE_MASK;
+			dprof_buffer = (unsigned int *)((klimit + (PAGE_SIZE-1)) & PAGE_MASK);
+			new_klimit = ((unsigned long)dprof_buffer) + size;
+			lmb_reserve( __pa(klimit), (new_klimit-klimit));
+			klimit = new_klimit;
+			memset( dprof_buffer, 0, size );
+                }
+        }
+
+	iSeries_setup_dprofile();
+
+	iSeries_proc_early_init();	
+	mf_init();
+	mf_initialized = 1;
+	mb();
+
+	iSeries_proc_callback( &pmc_proc_init );
+}
+
+#ifdef CONFIG_PPC_ISERIES
+/*
+ * The iSeries may have very large memories ( > 128 GB ) and a partition
+ * may get memory in "chunks" that may be anywhere in the 2**52 real
+ * address space.  The chunks are 256K in size.  To map this to the 
+ * memory model Linux expects, the AS/400 specific code builds a 
+ * translation table to translate what Linux thinks are "physical"
+ * addresses to the actual real addresses.  This allows us to make 
+ * it appear to Linux that we have contiguous memory starting at
+ * physical address zero while in fact this could be far from the truth.
+ * To avoid confusion, I'll let the words physical and/or real address 
+ * apply to the Linux addresses while I'll use "absolute address" to 
+ * refer to the actual hardware real address.
+ *
+ * build_iSeries_Memory_Map gets information from the Hypervisor and 
+ * looks at the Main Store VPD to determine the absolute addresses
+ * of the memory that has been assigned to our partition and builds
+ * a table used to translate Linux's physical addresses to these
+ * absolute addresses.  Absolute addresses are needed when 
+ * communicating with the hypervisor (e.g. to build HPT entries)
+ */
+
+static void __init build_iSeries_Memory_Map(void)
+{
+	u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
+	u32 nextPhysChunk;
+	u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;
+	u32 num_ptegs;
+	u32 totalChunks,moreChunks;
+	u32 currChunk, thisChunk, absChunk;
+	u32 currDword;
+	u32 chunkBit;
+	u64 map;
+	struct MemoryBlock mb[32];
+	unsigned long numMemoryBlocks, curBlock;
+
+	/* Chunk size on iSeries is 256K bytes */
+	totalChunks = (u32)HvLpConfig_getMsChunks();
+	klimit = msChunks_alloc(klimit, totalChunks, 1UL<<18);
+
+	/* Get absolute address of our load area
+	 * and map it to physical address 0
+	 * This guarantees that the loadarea ends up at physical 0
+	 * otherwise, it might not be returned by PLIC as the first
+	 * chunks
+	 */
+	
+	loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
+	loadAreaSize =  itLpNaca.xLoadAreaChunks;
+
+	/* Only add the pages already mapped here.  
+	 * Otherwise we might add the hpt pages 
+	 * The rest of the pages of the load area
+	 * aren't in the HPT yet and can still
+	 * be assigned an arbitrary physical address
+	 */
+	if ( (loadAreaSize * 64) > HvPagesToMap )
+		loadAreaSize = HvPagesToMap / 64;
+
+	loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
+
+	/* TODO Do we need to do something if the HPT is in the 64MB load area?
+	 * This would be required if the itLpNaca.xLoadAreaChunks includes 
+	 * the HPT size
+	 */
+
+	printk( "Mapping load area - physical addr = 0000000000000000\n"
+                "                    absolute addr = %016lx\n", 
+			chunk_to_addr(loadAreaFirstChunk) );
+	printk( "Load area size %dK\n", loadAreaSize*256 );
+	
+	for (	nextPhysChunk = 0; 
+		nextPhysChunk < loadAreaSize; 
+		++nextPhysChunk ) {
+		msChunks.abs[nextPhysChunk] = loadAreaFirstChunk+nextPhysChunk;
+	}
+	
+	/* Get absolute address of our HPT and remember it so
+	 * we won't map it to any physical address
+	 */
+
+	hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
+	hptSizePages =  (u32)(HvCallHpt_getHptPages());
+	hptSizeChunks = hptSizePages >> (msChunks.chunk_shift-PAGE_SHIFT);
+	hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
+	
+	printk( "HPT absolute addr = %016lx, size = %dK\n",
+			chunk_to_addr(hptFirstChunk), hptSizeChunks*256 );
+
+	/* Fill in the htab_data structure */
+	
+	/* Fill in size of hashed page table */
+	num_ptegs = hptSizePages * (PAGE_SIZE/(sizeof(HPTE)*HPTES_PER_GROUP));
+	htab_data.htab_num_ptegs = num_ptegs;
+	htab_data.htab_hash_mask = num_ptegs - 1;
+	
+	/* The actual hashed page table is in the hypervisor, we have no direct access */
+	htab_data.htab = NULL;
+
+	/* Determine if absolute memory has any
+	 * holes so that we can interpret the
+	 * access map we get back from the hypervisor
+	 * correctly.
+	 */
+	numMemoryBlocks = iSeries_process_mainstore_vpd( mb, 32 );
+
+	/* Process the main store access map from the hypervisor
+	 * to build up our physical -> absolute translation table
+	 */
+	curBlock = 0;
+	currChunk = 0;
+	currDword = 0;
+	moreChunks = totalChunks;
+
+	while ( moreChunks ) {
+		map = HvCallSm_get64BitsOfAccessMap( itLpNaca.xLpIndex,
+						     currDword );
+		thisChunk = currChunk;
+		while ( map ) {
+			chunkBit = map >> 63;
+			map <<= 1;
+			if ( chunkBit ) {
+				--moreChunks;
+
+				while ( thisChunk >= mb[curBlock].logicalEnd ) {
+					++curBlock;
+					if ( curBlock >= numMemoryBlocks )
+						panic("out of memory blocks");
+				}
+				if ( thisChunk < mb[curBlock].logicalStart )
+					panic("memory block error");
+
+				absChunk = mb[curBlock].absStart + ( thisChunk - mb[curBlock].logicalStart );
+
+				if ( ( ( absChunk < hptFirstChunk ) ||
+				       ( absChunk > hptLastChunk ) ) &&
+				     ( ( absChunk < loadAreaFirstChunk ) ||
+				       ( absChunk > loadAreaLastChunk ) ) ) {
+					msChunks.abs[nextPhysChunk] = absChunk;
+					++nextPhysChunk;
+				}
+			}
+			++thisChunk;
+		}
+		++currDword;
+		currChunk += 64;
+	}
+					
+	/* main store size (in chunks) is 
+	 *   totalChunks - hptSizeChunks
+	 * which should be equal to 
+	 *   nextPhysChunk
+	 */
+	naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+
+	/* Bolt kernel mappings for all of memory */
+	iSeries_bolt_kernel( 0, naca->physicalMemorySize );
+
+	lmb_init();
+	lmb_add( 0, naca->physicalMemorySize );
+	lmb_analyze();	/* ?? */
+	lmb_reserve( 0, __pa(klimit));
+
+	/* 
+	 * Hardcode to GP size.  I am not sure where to get this info. DRENG
+	 */
+	naca->slb_size = 64;
+}
+
+/*
+ * Set up the variables that describe the cache line sizes
+ * for this machine.
+ */
+
+static void __init setup_iSeries_cache_sizes(void)
+{
+	unsigned i,n;
+	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
+
+	naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
+	naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
+	naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
+	naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
+	i = naca->iCacheL1LineSize;
+	n = 0;
+	while ((i=(i/2))) ++n;
+	naca->iCacheL1LogLineSize = n;
+	i = naca->dCacheL1LineSize;
+	n = 0;
+	while ((i=(i/2))) ++n;
+	naca->dCacheL1LogLineSize = n;
+
+	printk( "D-cache line size = %d  (log = %d)\n",
+			(unsigned)naca->dCacheL1LineSize,
+			(unsigned)naca->dCacheL1LogLineSize );
+	printk( "I-cache line size = %d  (log = %d)\n",
+			(unsigned)naca->iCacheL1LineSize,
+			(unsigned)naca->iCacheL1LogLineSize );
+	
+}
+
+/*
+ * Bolt the kernel addr space into the HPT
+ */
+
+static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
+{
+	unsigned long pa;
+	unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
+	HPTE hpte;
+
+	for (pa=saddr; pa < eaddr ;pa+=PAGE_SIZE) {
+		unsigned long ea = (unsigned long)__va(pa);
+		unsigned long vsid = get_kernel_vsid( ea );
+		unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff );
+		unsigned long vpn = va >> PAGE_SHIFT;
+		unsigned long slot = HvCallHpt_findValid( &hpte, vpn );
+		if ( hpte.dw0.dw0.v ) {
+			/* HPTE exists, so just bolt it */
+			HvCallHpt_setSwBits( slot, 0x10, 0 );
+		} else {
+			/* No HPTE exists, so create a new bolted one */
+			build_valid_hpte(vsid, ea, pa, NULL, mode_rw, 1);
+		}
+	}
+}
+#endif /* CONFIG_PPC_ISERIES */
+
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
+
+/*
+ * Document me.
+ */
+void __init
+iSeries_setup_arch(void)
+{
+	void *	eventStack;
+	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
+
+	/* Setup the Lp Event Queue */
+
+	/* Allocate a page for the Event Stack
+	 * The hypervisor wants the absolute real address, so
+	 * we subtract out the KERNELBASE and add in the
+	 * absolute real address of the kernel load area
+	 */
+	
+	eventStack = alloc_bootmem_pages( LpEventStackSize );
+	
+	memset( eventStack, 0, LpEventStackSize );
+	
+	/* Invoke the hypervisor to initialize the event stack */
+	
+	HvCallEvent_setLpEventStack( 0, eventStack, LpEventStackSize );
+	
+	/* Initialize fields in our Lp Event Queue */
+	
+	xItLpQueue.xSlicEventStackPtr = (char *)eventStack;
+	xItLpQueue.xSlicCurEventPtr = (char *)eventStack;
+	xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack + 
+					(LpEventStackSize - LpEventMaxSize);
+	xItLpQueue.xIndex = 0;
+	
+	/* Compute processor frequency */
+	procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[procIx].xProcFreq );
+	procFreqMhz = procFreqHz / 1000000;
+	procFreqMhzHundreths = (procFreqHz/10000) - (procFreqMhz*100);
+
+	ppc_proc_freq = procFreqHz;
+
+	/* Compute time base frequency */
+	tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[procIx].xTimeBaseFreq );
+	tbFreqMhz = tbFreqHz / 1000000;
+	tbFreqMhzHundreths = (tbFreqHz/10000) - (tbFreqMhz*100);
+
+	ppc_tb_freq = tbFreqHz;
+
+	printk("Max  logical processors = %d\n", 
+			itVpdAreas.xSlicMaxLogicalProcs );
+	printk("Max physical processors = %d\n",
+			itVpdAreas.xSlicMaxPhysicalProcs );
+	printk("Processor frequency = %lu.%02lu\n",
+			procFreqMhz, 
+			procFreqMhzHundreths );
+	printk("Time base frequency = %lu.%02lu\n",
+			tbFreqMhz,
+			tbFreqMhzHundreths );
+	printk("Processor version = %x\n",
+			xIoHriProcessorVpd[procIx].xPVR );
+
+}
+
+/*
+ * int as400_setup_residual()
+ *
+ * Description:
+ *   This routine pretty-prints CPU information gathered from the VPD    
+ *   for use in /proc/cpuinfo                               
+ *
+ * Input(s):
+ *  *buffer - Buffer into which CPU data is to be printed.             
+ *
+ * Output(s):
+ *  *buffer - Buffer with CPU data.
+ *
+ * Returns:
+ *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ *   on error.
+ */
+void iSeries_setup_residual(struct seq_file *m)
+{
+	
+	seq_printf(m,"clock\t\t: %lu.%02luMhz\n",
+		procFreqMhz, procFreqMhzHundreths );
+	seq_printf(m,"time base\t: %lu.%02luMHz\n",
+		tbFreqMhz, tbFreqMhzHundreths );
+	seq_printf(m,"i-cache\t\t: %d\n",
+		naca->iCacheL1LineSize);
+	seq_printf(m,"d-cache\t\t: %d\n",
+		naca->dCacheL1LineSize);
+
+}
+
+void iSeries_get_cpuinfo(struct seq_file *m)
+{
+
+	seq_printf(m,"machine\t\t: 64-bit iSeries Logical Partition\n");
+
+}
+
+/*
+ * Document me.
+ * and Implement me.
+ */
+int
+iSeries_get_irq(struct pt_regs *regs)
+{
+	/* -2 means ignore this interrupt */
+	return -2;
+}
+
+/*
+ * Document me.
+ */
+void
+iSeries_restart(char *cmd)
+{
+	mf_reboot();
+}
+
+/*
+ * Document me.
+ */
+void
+iSeries_power_off(void)
+{
+	mf_powerOff();
+}
+
+/*
+ * Document me.
+ */
+void
+iSeries_halt(void)
+{
+	mf_powerOff();
+}
+
+/*
+ * Nothing to do here.
+ */
+void __init
+iSeries_time_init(void)
+{
+	/* Nothing to do */
+}
+
+/* JDH Hack */
+unsigned long jdh_time = 0;
+
+extern void setup_default_decr(void);
+
+/*
+ * void __init iSeries_calibrate_decr()
+ *
+ * Description:
+ *   This routine retrieves the internal processor frequency from the VPD,
+ *   and sets up the kernel timer decrementer based on that value.
+ *
+ */
+void __init
+iSeries_calibrate_decr(void)
+{
+	unsigned long	cyclesPerUsec;
+
+	struct div_result divres;
+	
+	/* Compute decrementer (and TB) frequency 
+	 * in cycles/sec 
+	 */
+
+	cyclesPerUsec = ppc_tb_freq / 1000000;	/* cycles / usec */
+
+	/* Set the amount to refresh the decrementer by.  This
+	 * is the number of decrementer ticks it takes for 
+	 * 1/HZ seconds.
+	 */
+
+	tb_ticks_per_jiffy = ppc_tb_freq / HZ;
+
+#if 0
+	/* TEST CODE FOR ADJTIME */
+	tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000;
+	/* END OF TEST CODE */
+#endif
+
+	/*
+	 * tb_ticks_per_sec = freq; would give better accuracy
+	 * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures
+	 * that jiffies (and xtime) will match the time returned
+	 * by do_gettimeofday.
+	 */
+	tb_ticks_per_sec   = tb_ticks_per_jiffy * HZ;
+	tb_ticks_per_usec = cyclesPerUsec;
+	tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
+	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
+	tb_to_xs = divres.result_low;
+	setup_default_decr();
+}
+
+void __init
+iSeries_progress( char * st, unsigned short code )
+{
+	printk( "Progress: [%04x] - %s\n", (unsigned)code, st );
+	if ( !piranha_simulator && mf_initialized ) {
+	    if (code != 0xffff)
+		mf_displayProgress( code );
+	    else
+		mf_clearSrc();
+	}
+}
+
+
+void iSeries_fixup_klimit(void)
+{
+	/* Change klimit to take into account any ram disk that may be included */
+	if (naca->xRamDisk)
+		klimit = KERNELBASE + (u64)naca->xRamDisk + (naca->xRamDiskSize * PAGE_SIZE);
+	else {
+		/* No ram disk was included - check and see if there was an embedded system map */
+		/* Change klimit to take into account any embedded system map */
+		if (embedded_sysmap_end)
+			klimit = KERNELBASE + ((embedded_sysmap_end+4095) & 0xfffffffffffff000);
+	}
+}
+
+static void iSeries_setup_dprofile(void)
+{
+	if ( dprof_buffer ) {
+		unsigned i;
+		for (i=0; i<maxPacas; ++i) {
+			xPaca[i].prof_shift = dprof_shift;
+			xPaca[i].prof_len = dprof_len-1;
+			xPaca[i].prof_buffer = dprof_buffer;
+			xPaca[i].prof_stext = (unsigned *)&_stext;
+			mb();
+			xPaca[i].prof_enabled = 1;
+		}
+	}
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_setup.h linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_setup.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/iSeries_setup.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/iSeries_setup.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,43 @@
+/*
+ *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: as400_setup.h
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and
+ *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ *      <dan@netx4.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.
+ */
+
+#ifndef	__ISERIES_SETUP_H__
+#define	__ISERIES_SETUP_H__
+
+extern void		 iSeries_init_early(void);
+extern void		 iSeries_init(unsigned long r3,
+			            unsigned long ird_start,
+				    unsigned long ird_end,
+				    unsigned long cline_start,
+				    unsigned long cline_end);
+extern void		 iSeries_setup_arch(void);
+extern void		 iSeries_setup_residual(struct seq_file *m);
+extern void		 iSeries_get_cpuinfo(struct seq_file *m);
+extern void		 iSeries_init_IRQ(void);
+extern int		 iSeries_get_irq(struct pt_regs *regs);
+extern void		 iSeries_restart(char *cmd);
+extern void		 iSeries_power_off(void);
+extern void		 iSeries_halt(void);
+extern void		 iSeries_time_init(void);
+extern void      iSeries_get_boot_time(struct rtc_time *tm);
+extern int		 iSeries_set_rtc_time(unsigned long now);
+extern unsigned long	 iSeries_get_rtc_time(void);
+extern void		 iSeries_calibrate_decr(void);
+extern void 	 iSeries_progress( char *, unsigned short );
+
+#endif /* __ISERIES_SETUP_H__ */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/idle.c linux-2.4.19-pre5/arch/ppc64/kernel/idle.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/idle.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/idle.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,135 @@
+/*
+ * Idle daemon for PowerPC.  Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#include <asm/time.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/iSeries/ItLpQueue.h>
+
+unsigned long maxYieldTime = 0;
+unsigned long minYieldTime = 0xffffffffffffffffUL;
+
+#ifdef CONFIG_PPC_ISERIES
+static void yield_shared_processor(void)
+{
+	struct Paca *paca;
+	unsigned long tb;
+	unsigned long yieldTime;
+
+	paca = (struct Paca *)mfspr(SPRG3);
+	HvCall_setEnabledInterrupts( HvCall_MaskIPI |
+				     HvCall_MaskLpEvent |
+				     HvCall_MaskLpProd |
+				     HvCall_MaskTimeout );
+
+	tb = get_tb();
+	/* Compute future tb value when yield should expire */
+	HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
+
+	yieldTime = get_tb() - tb;
+	if ( yieldTime > maxYieldTime )
+		maxYieldTime = yieldTime;
+
+	if ( yieldTime < minYieldTime )
+		minYieldTime = yieldTime;
+	
+	/* The decrementer stops during the yield.  Force a fake decrementer
+	 * here and let the timer_interrupt code sort out the actual time.
+	 */
+	paca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	process_iSeries_events();
+}
+#endif /* CONFIG_PPC_ISERIES */
+
+int idled(void)
+{
+	struct Paca *paca;
+	long oldval;
+#ifdef CONFIG_PPC_ISERIES
+	unsigned long CTRL;
+#endif
+
+	/* endless loop with no priority at all */
+	current->nice = 20;
+	current->counter = -100;
+#ifdef CONFIG_PPC_ISERIES
+	/* ensure iSeries run light will be out when idle */
+	current->thread.flags &= ~PPC_FLAG_RUN_LIGHT;
+	CTRL = mfspr(CTRLF);
+	CTRL &= ~RUNLATCH;
+	mtspr(CTRLT, CTRL);
+#endif
+	init_idle();	
+
+	paca = (struct Paca *)mfspr(SPRG3);
+
+	for (;;) {
+#ifdef CONFIG_PPC_ISERIES
+		if ( paca->xLpPaca.xSharedProc ) {
+			if ( ItLpQueue_isLpIntPending( paca->lpQueuePtr ) )
+				process_iSeries_events();
+			if ( !current->need_resched )
+				yield_shared_processor();
+		}
+		else 
+#endif
+		{
+			/* Avoid an IPI by setting need_resched */
+			oldval = xchg(&current->need_resched, -1);
+			if (!oldval) {
+				while(current->need_resched == -1) {
+#ifdef CONFIG_PPC_ISERIES
+					HMT_medium();
+					if ( ItLpQueue_isLpIntPending( paca->lpQueuePtr ) )
+						process_iSeries_events();
+#endif
+					HMT_low();
+				}
+			}
+		}
+		HMT_medium();
+		if (current->need_resched) {
+			schedule();
+			check_pgt_cache();
+		}
+	}
+	return 0;
+}
+
+/*
+ * SMP entry into the idle task - calls the same thing as the
+ * non-smp versions. -- Cort
+ */
+int cpu_idle(void)
+{
+	idled();
+	return 0; 
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ioctl32.c linux-2.4.19-pre5/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ioctl32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ioctl32.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,4498 @@
+/* 
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ * 
+ * Based on sparc64 ioctl32.c by:
+ *
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * ppc64 changes:
+ *
+ * Copyright (C) 2000  Ken Aaker (kdaaker@rchland.vnet.ibm.com)
+ * Copyright (C) 2001  Anton Blanchard (antonb@au.ibm.com)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/if.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+#include <linux/raid/md.h>
+#include <linux/kd.h>
+#include <linux/route.h>
+#include <linux/in6.h>
+#include <linux/ipv6_route.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/vt.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fd.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppox.h>
+#include <linux/mtio.h>
+#include <linux/cdrom.h>
+#include <linux/loop.h>
+#include <linux/auto_fs.h>
+#include <linux/devfs_fs.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/fb.h>
+#include <linux/ext2_fs.h>
+#include <linux/videodev.h>
+#include <linux/netdevice.h>
+#include <linux/raw.h>
+#include <linux/smb_fs.h>
+#include <linux/blkpg.h>
+#include <linux/blk.h>
+#include <linux/elevator.h>
+#include <linux/rtc.h>
+#include <linux/pci.h>
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+#include <linux/lvm.h>
+#endif /* LVM */
+
+#include <scsi/scsi.h>
+/* Ugly hack. */
+#undef __KERNEL__
+#include <scsi/scsi_ioctl.h>
+#define __KERNEL__
+#include <scsi/sg.h>
+
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_bonding.h>
+#include <asm/module.h>
+#include <linux/soundcard.h>
+#include <linux/watchdog.h>
+#include <linux/lp.h>
+
+#include <linux/atm.h>
+#include <linux/atmarp.h>
+#include <linux/atmclip.h>
+#include <linux/atmdev.h>
+#include <linux/atmioc.h>
+#include <linux/atmlec.h>
+#include <linux/atmmpc.h>
+#include <linux/atmsvc.h>
+#include <linux/atm_tcp.h>
+#include <linux/sonet.h>
+#include <linux/atm_suni.h>
+#include <linux/mtd/mtd.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/nbd.h>
+#include <asm/ppcdebug.h>
+
+/* Use this to get at 32-bit user passed pointers. 
+   See sys_sparc32.c for description about these. */
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x)				\
+({	unsigned long __ret;		\
+	__asm__ ("clrldi	%0, %0, 32"	\
+		 : "=r" (__ret)		\
+		 : "0" (__x));		\
+	__ret;				\
+})
+
+/* Aiee. Someone does not find a difference between int and long */
+#define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
+#define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
+#define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
+#define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)
+
+extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)arg))
+		return -EFAULT;
+	return err;
+}
+ 
+static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	if (get_user(val, (u32 *)arg))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)arg))
+		return -EFAULT;
+	return err;
+}
+
+static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* These are just misnamed, they actually get/put from/to user an int */
+	switch (cmd) {
+	case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+	case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+	case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+	case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+	}
+	return sys_ioctl(fd, cmd, arg);
+}
+ 
+struct video_tuner32 {
+	s32 tuner;
+	u8 name[32];
+	u32 rangelow, rangehigh;
+	u32 flags;
+	u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if (get_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__get_user(kp->name[i], &up->name[i]);
+	__get_user(kp->rangelow, &up->rangelow);
+	__get_user(kp->rangehigh, &up->rangehigh);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->mode, &up->mode);
+	__get_user(kp->signal, &up->signal);
+	return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if (put_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__put_user(kp->name[i], &up->name[i]);
+	__put_user(kp->rangelow, &up->rangelow);
+	__put_user(kp->rangehigh, &up->rangehigh);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->mode, &up->mode);
+	__put_user(kp->signal, &up->signal);
+	return 0;
+}
+
+struct video_buffer32 {
+	/* void * */ u32 base;
+	s32 height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp;
+
+	if (get_user(tmp, &up->base))
+		return -EFAULT;
+	kp->base = (void *) ((unsigned long)tmp);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->depth, &up->depth);
+	__get_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->base);
+
+	if (put_user(tmp, &up->base))
+		return -EFAULT;
+	__put_user(kp->height, &up->height);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->depth, &up->depth);
+	__put_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+struct video_clip32 {
+	s32 x, y, width, height;
+	/* struct video_clip32 * */ u32 next;
+};
+
+struct video_window32 {
+	u32 x, y, width, height, chromakey, flags;
+	/* struct video_clip32 * */ u32 clips;
+	s32 clipcount;
+};
+
+static void free_kvideo_clips(struct video_window *kp)
+{
+	struct video_clip *cp;
+
+	cp = kp->clips;
+	if (cp != NULL)
+		kfree(cp);
+}
+
+static int get_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	struct video_clip32 *ucp;
+	struct video_clip *kcp;
+	int nclips, err, i;
+	u32 tmp;
+
+	if (get_user(kp->x, &up->x))
+		return -EFAULT;
+	__get_user(kp->y, &up->y);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->chromakey, &up->chromakey);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->clipcount, &up->clipcount);
+	__get_user(tmp, &up->clips);
+	ucp = (struct video_clip32 *)A(tmp);
+	kp->clips = NULL;
+
+	nclips = kp->clipcount;
+	if (nclips == 0)
+		return 0;
+
+	if (ucp == 0)
+		return -EINVAL;
+
+	/* Peculiar interface... */
+	if (nclips < 0)
+		nclips = VIDEO_CLIPMAP_SIZE;
+
+	kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
+	err = -ENOMEM;
+	if (kcp == NULL)
+		goto cleanup_and_err;
+
+	kp->clips = kcp;
+	for(i = 0; i < nclips; i++) {
+		__get_user(kcp[i].x, &ucp[i].x);
+		__get_user(kcp[i].y, &ucp[i].y);
+		__get_user(kcp[i].width, &ucp[i].width);
+		__get_user(kcp[i].height, &ucp[i].height);
+		kcp[nclips].next = NULL;
+	}
+
+	return 0;
+
+cleanup_and_err:
+	free_kvideo_clips(kp);
+	return err;
+}
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	if (put_user(kp->x, &up->x))
+		return -EFAULT;
+	__put_user(kp->y, &up->y);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->height, &up->height);
+	__put_user(kp->chromakey, &up->chromakey);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->clipcount, &up->clipcount);
+	return 0;
+}
+
+#define VIDIOCGTUNER32		_IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32		_IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32		_IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32		_IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32		_IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32		_IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32		_IOR('v',14, u32)
+#define VIDIOCSFREQ32		_IOW('v',15, u32)
+
+static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	union {
+		struct video_tuner vt;
+		struct video_buffer vb;
+		struct video_window vw;
+		unsigned long vx;
+	} karg;
+	mm_segment_t old_fs = get_fs();
+	void *up = (void *)arg;
+	int err = 0;
+
+	/* First, convert the command. */
+	switch(cmd) {
+	case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+	case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+	case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+	case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+	case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+	case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+	case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+	case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+	};
+
+	switch(cmd) {
+	case VIDIOCSTUNER:
+	case VIDIOCGTUNER:
+		err = get_video_tuner32(&karg.vt, up);
+		break;
+
+	case VIDIOCSWIN:
+		err = get_video_window32(&karg.vw, up);
+		break;
+
+	case VIDIOCSFBUF:
+		err = get_video_buffer32(&karg.vb, up);
+		break;
+
+	case VIDIOCSFREQ:
+		err = get_user(karg.vx, (u32 *)up);
+		break;
+	};
+	if (err)
+		goto out;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&karg);
+	set_fs(old_fs);
+
+	if (cmd == VIDIOCSWIN)
+		free_kvideo_clips(&karg.vw);
+
+	if (err == 0) {
+		switch(cmd) {
+		case VIDIOCGTUNER:
+			err = put_video_tuner32(&karg.vt, up);
+			break;
+
+		case VIDIOCGWIN:
+			err = put_video_window32(&karg.vw, up);
+			break;
+
+		case VIDIOCGFBUF:
+			err = put_video_buffer32(&karg.vb, up);
+			break;
+
+		case VIDIOCGFREQ:
+			err = put_user(((u32)karg.vx), (u32 *)up);
+			break;
+		};
+	}
+out:
+	return err;
+}
+
+struct timeval32 {
+	int tv_sec;
+	int tv_usec;
+};
+
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct timeval32 *up = (struct timeval32 *)arg;
+	struct timeval ktv;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+	set_fs(old_fs);
+	if (!err) {
+		err = put_user(ktv.tv_sec, &up->tv_sec);
+		err |= __put_user(ktv.tv_usec, &up->tv_usec);
+	}
+	return err;
+}
+
+struct ifmap32 {
+	u32 mem_start;
+	u32 mem_end;
+	unsigned short base_addr;
+	unsigned char irq;
+	unsigned char dma;
+	unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN     6
+#define IFNAMSIZ        16
+        union {
+                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+        } ifr_ifrn;
+        union {
+                struct  sockaddr ifru_addr;
+                struct  sockaddr ifru_dstaddr;
+                struct  sockaddr ifru_broadaddr;
+                struct  sockaddr ifru_netmask;
+                struct  sockaddr ifru_hwaddr;
+                short   ifru_flags;
+                int     ifru_ivalue;
+                int     ifru_mtu;
+                struct  ifmap32 ifru_map;
+                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+		char	ifru_newname[IFNAMSIZ];
+                __kernel_caddr_t32 ifru_data;
+        } ifr_ifru;
+};
+
+struct ifconf32 {
+        int     ifc_len;                        /* size of buffer       */
+        __kernel_caddr_t32  ifcbuf;
+};
+
+#ifdef CONFIG_NET
+static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct net_device *dev;
+	struct ifreq32 ifr32;
+	int err;
+
+	if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+
+	dev = dev_get_by_index(ifr32.ifr_ifindex);
+	if (!dev)
+		return -ENODEV;
+
+	strcpy(ifr32.ifr_name, dev->name);
+
+	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
+	return (err ? -EFAULT : 0);
+}
+#endif
+
+static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifconf32 ifc32;
+	struct ifconf ifc;
+	struct ifreq32 *ifr32;
+	struct ifreq *ifr;
+	mm_segment_t old_fs;
+	unsigned int i, j;
+	int err;
+
+	if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32)))
+		return -EFAULT;
+
+	if (ifc32.ifcbuf == 0) {
+		ifc32.ifc_len = 0;
+		ifc.ifc_len = 0;
+		ifc.ifc_buf = NULL;
+	} else {
+		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
+			sizeof (struct ifreq);
+		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+		if (!ifc.ifc_buf)
+			return -ENOMEM;
+	}
+	ifr = ifc.ifc_req;
+	ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+	for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
+		if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
+			kfree (ifc.ifc_buf);
+			return -EFAULT;
+		}
+	}
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
+	set_fs (old_fs);
+	if (!err) {
+		ifr = ifc.ifc_req;
+		ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+		for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
+		     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
+			if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
+				err = -EFAULT;
+				break;
+			}
+		}
+		if (!err) {
+			if (ifc32.ifcbuf == 0) {
+				/* Translate from 64-bit structure multiple to
+				 * a 32-bit one.
+				 */
+				i = ifc.ifc_len;
+				i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));
+				ifc32.ifc_len = i;
+			} else {
+				if (i <= ifc32.ifc_len)
+					ifc32.ifc_len = i;
+				else
+					ifc32.ifc_len = i - sizeof (struct ifreq32);
+			}
+			if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32)))
+				err = -EFAULT;
+		}
+	}
+	if (ifc.ifc_buf != NULL)
+		kfree (ifc.ifc_buf);
+	return err;
+}
+
+static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data, ethcmd;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+
+	if (get_user(ethcmd, (u32 *)A(data))) {
+		err = -EFAULT;
+		goto out;
+	}
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GMSGLVL:
+	case ETHTOOL_SMSGLVL:
+	case ETHTOOL_GLINK:
+	case ETHTOOL_NWAY_RST:	len = sizeof(struct ethtool_value); break;
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data);
+		/* darned variable size arguments */
+		if (get_user(len, (u32 *)&regaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		len += sizeof(struct ethtool_regs);
+		break;
+	}
+	case ETHTOOL_GSET:
+	case ETHTOOL_SSET:	len = sizeof(struct ethtool_cmd); break;
+	default:
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		u32 data;
+
+		__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
+static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	switch (cmd) {
+	case SIOCBONDENSLAVE:
+	case SIOCBONDRELEASE:
+	case SIOCBONDSETHWADDR:
+	case SIOCBONDCHANGEACTIVE:
+		len = IFNAMSIZ * sizeof(char);
+		break;
+	case SIOCBONDSLAVEINFOQUERY:
+		len = sizeof(struct ifslave);
+		break;
+	case SIOCBONDINFOQUERY:
+		len = sizeof(struct ifbond);
+		break;
+	default:
+		err = -EINVAL;
+		goto out;
+	};
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
+static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err;
+	
+	switch (cmd) {
+	case SIOCSIFMAP:
+		err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name));
+		err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+		err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+		err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+		err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+		err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+		err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+		if (err)
+			return -EFAULT;
+		break;
+	default:
+		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+			return -EFAULT;
+		break;
+	}
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		switch (cmd) {
+		case SIOCGIFFLAGS:
+		case SIOCGIFMETRIC:
+		case SIOCGIFMTU:
+		case SIOCGIFMEM:
+		case SIOCGIFHWADDR:
+		case SIOCGIFINDEX:
+		case SIOCGIFADDR:
+		case SIOCGIFBRDADDR:
+		case SIOCGIFDSTADDR:
+		case SIOCGIFNETMASK:
+		case SIOCGIFTXQLEN:
+			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
+				return -EFAULT;
+			break;
+		case SIOCGIFMAP:
+			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
+			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+			err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+			err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+			err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+			err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+			err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+			if (err)
+				err = -EFAULT;
+			break;
+		}
+	}
+	return err;
+}
+
+struct rtentry32 {
+        u32   		rt_pad1;
+        struct sockaddr rt_dst;         /* target address               */
+        struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+        struct sockaddr rt_genmask;     /* target network mask (IP)     */
+        unsigned short  rt_flags;
+        short           rt_pad2;
+        u32   		rt_pad3;
+        unsigned char   rt_tos;
+        unsigned char   rt_class;
+        short           rt_pad4;
+        short           rt_metric;      /* +1 for binary compatibility! */
+        /* char * */ u32 rt_dev;        /* forcing the device at add    */
+        u32   		rt_mtu;         /* per route MTU/Window         */
+        u32   		rt_window;      /* Window clamping              */
+        unsigned short  rt_irtt;        /* Initial RTT                  */
+
+};
+
+struct in6_rtmsg32 {
+	struct in6_addr		rtmsg_dst;
+	struct in6_addr		rtmsg_src;
+	struct in6_addr		rtmsg_gateway;
+	u32			rtmsg_type;
+	u16			rtmsg_dst_len;
+	u16			rtmsg_src_len;
+	u32			rtmsg_metric;
+	u32			rtmsg_info;
+	u32			rtmsg_flags;
+	s32			rtmsg_ifindex;
+};
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
+static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	int ret;
+	void *r = NULL;
+	struct in6_rtmsg r6;
+	struct rtentry r4;
+	char devname[16];
+	u32 rtdev;
+	mm_segment_t old_fs = get_fs();
+	
+	struct socket *mysock = sockfd_lookup(fd, &ret);
+
+	if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */
+		ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst),
+			3 * sizeof(struct in6_addr));
+		ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type));
+		ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len));
+		ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len));
+		ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric));
+		ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info));
+		ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags));
+		ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex));
+		
+		r = (void *) &r6;
+	} else { /* ipv4 */
+		ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
+		ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
+		ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
+		ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
+		ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window));
+		ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt));
+		ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev));
+		if (rtdev) {
+			ret |= copy_from_user (devname, (char *)A(rtdev), 15);
+			r4.rt_dev = devname; devname[15] = 0;
+		} else
+			r4.rt_dev = 0;
+
+		r = (void *) &r4;
+	}
+
+	if (ret)
+		return -EFAULT;
+
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, cmd, (long) r);
+	set_fs (old_fs);
+
+	return ret;
+}
+
+struct hd_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	u32 start;
+};
+                        
+static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4);
+		err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start));
+	}
+	return err ? -EFAULT : 0;
+}
+
+
+static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	unsigned long kval;
+	unsigned int *uvp;
+	int error;
+
+	set_fs(KERNEL_DS);
+	error = sys_ioctl(fd, cmd, (long)&kval);
+	set_fs(old_fs);
+
+	if (error == 0) {
+		uvp = (unsigned int *)arg;
+		if (put_user(kval, uvp))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+struct floppy_struct32 {
+	unsigned int	size;
+	unsigned int	sect;
+	unsigned int	head;
+	unsigned int	track;
+	unsigned int	stretch;
+	unsigned char	gap;
+	unsigned char	rate;
+	unsigned char	spec1;
+	unsigned char	fmt_gap;
+	const __kernel_caddr_t32 name;
+};
+
+struct floppy_drive_params32 {
+	char		cmos;
+	u32		max_dtr;
+	u32		hlt;
+	u32		hut;
+	u32		srt;
+	u32		spinup;
+	u32		spindown;
+	unsigned char	spindown_offset;
+	unsigned char	select_delay;
+	unsigned char	rps;
+	unsigned char	tracks;
+	u32		timeout;
+	unsigned char	interleave_sect;
+	struct floppy_max_errors max_errors;
+	char		flags;
+	char		read_track;
+	short		autodetect[8];
+	int		checkfreq;
+	int		native_format;
+};
+
+struct floppy_drive_struct32 {
+	signed char	flags;
+	u32		spinup_date;
+	u32		select_date;
+	u32		first_read_date;
+	short		probed_format;
+	short		track;
+	short		maxblock;
+	short		maxtrack;
+	int		generation;
+	int		keep_data;
+	int		fd_ref;
+	int		fd_device;
+	int		last_checked;
+	__kernel_caddr_t32 dmabuf;
+	int		bufblocks;
+};
+
+struct floppy_fdc_state32 {
+	int		spec1;
+	int		spec2;
+	int		dtr;
+	unsigned char	version;
+	unsigned char	dor;
+	u32		address;
+	unsigned int	rawcmd:2;
+	unsigned int	reset:1;
+	unsigned int	need_configure:1;
+	unsigned int	perp_mode:2;
+	unsigned int	has_fifo:1;
+	unsigned int	driver_version;
+	unsigned char	track[4];
+};
+
+struct floppy_write_errors32 {
+	unsigned int	write_errors;
+	u32		first_error_sector;
+	int		first_error_generation;
+	u32		last_error_sector;
+	int		last_error_generation;
+	unsigned int	badness;
+};
+
+#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32)
+#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32)
+#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32)
+#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32)
+#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32)
+#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32)
+#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32)
+#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32)
+#define FDWERRORGET32  _IOR(2, 0x17, struct floppy_write_errors32)
+
+static struct {
+	unsigned int	cmd32;
+	unsigned int	cmd;
+} fd_ioctl_trans_table[] = {
+	{ FDSETPRM32, FDSETPRM },
+	{ FDDEFPRM32, FDDEFPRM },
+	{ FDGETPRM32, FDGETPRM },
+	{ FDSETDRVPRM32, FDSETDRVPRM },
+	{ FDGETDRVPRM32, FDGETDRVPRM },
+	{ FDGETDRVSTAT32, FDGETDRVSTAT },
+	{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
+	{ FDGETFDCSTAT32, FDGETFDCSTAT },
+	{ FDWERRORGET32, FDWERRORGET }
+};
+
+#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0]))
+
+static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	void *karg = NULL;
+	unsigned int kcmd = 0;
+	int i, err;
+
+	for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
+		if (cmd == fd_ioctl_trans_table[i].cmd32) {
+			kcmd = fd_ioctl_trans_table[i].cmd;
+			break;
+		}
+	if (!kcmd)
+		return -EINVAL;
+
+	switch (cmd) {
+		case FDSETPRM32:
+		case FDDEFPRM32:
+		case FDGETPRM32:
+		{
+			struct floppy_struct *f;
+
+			f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			if (cmd == FDGETPRM32)
+				break;
+			err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size);
+			err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+			err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head);
+			err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track);
+			err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+			err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+			err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+			err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+			err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+			err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			if (err) {
+				err = -EFAULT;
+				goto out;
+			}
+			break;
+		}
+		case FDSETDRVPRM32:
+		case FDGETDRVPRM32:
+		{
+			struct floppy_drive_params *f;
+
+			f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			if (cmd == FDGETDRVPRM32)
+				break;
+			err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+			err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+			err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+			err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+			err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+			err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+			err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+			err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+			err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+			err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+			err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+			err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+			err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+			err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors));
+			err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+			err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+			err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect));
+			err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+			err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+			if (err) {
+				err = -EFAULT;
+				goto out;
+			}
+			break;
+		}
+		case FDGETDRVSTAT32:
+		case FDPOLLDRVSTAT32:
+			karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		case FDGETFDCSTAT32:
+			karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		case FDWERRORGET32:
+			karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
+			if (!karg)
+				return -ENOMEM;
+			break;
+		default:
+			return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+		case FDGETPRM32:
+		{
+			struct floppy_struct *f = karg;
+
+			err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size);
+			err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+			err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head);
+			err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track);
+			err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+			err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+			err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+			err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+			err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+			err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			break;
+		}
+		case FDGETDRVPRM32:
+		{
+			struct floppy_drive_params *f = karg;
+
+			err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+			err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+			err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+			err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+			err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+			err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+			err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+			err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+			err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+			err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+			err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+			err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+			err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+			err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors));
+			err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+			err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+			err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect));
+			err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+			err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+			break;
+		}
+		case FDGETDRVSTAT32:
+		case FDPOLLDRVSTAT32:
+		{
+			struct floppy_drive_struct *f = karg;
+
+			err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags);
+			err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date);
+			err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date);
+			err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date);
+			err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format);
+			err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track);
+			err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock);
+			err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack);
+			err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation);
+			err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data);
+			err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref);
+			err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device);
+			err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked);
+			err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf);
+			err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks);
+			break;
+		}
+		case FDGETFDCSTAT32:
+		{
+			struct floppy_fdc_state *f = karg;
+
+			err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1);
+			err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2);
+			err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr);
+			err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version);
+			err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor);
+			err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address);
+			err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address
+			    		   + sizeof(((struct floppy_fdc_state32 *)arg)->address),
+					   (char *)&f->address + sizeof(f->address), sizeof(int));
+			err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version);
+			err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track));
+			break;
+		}
+		case FDWERRORGET32:
+		{
+			struct floppy_write_errors *f = karg;
+
+			err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors);
+			err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector);
+			err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation);
+			err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector);
+			err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation);
+			err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness);
+			break;
+		}
+		default:
+			break;
+	}
+	if (err)
+		err = -EFAULT;
+
+out:	if (karg) kfree(karg);
+	return err;
+}
+
+struct ppp_option_data32 {
+	__kernel_caddr_t32	ptr;
+	__u32			length;
+	int			transmit;
+};
+#define PPPIOCSCOMPRESS32	_IOW('t', 77, struct ppp_option_data32)
+
+struct ppp_idle32 {
+	__kernel_time_t32 xmit_idle;
+	__kernel_time_t32 recv_idle;
+};
+#define PPPIOCGIDLE32		_IOR('t', 63, struct ppp_idle32)
+
+static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct ppp_option_data32 data32;
+	struct ppp_option_data data;
+	struct ppp_idle32 idle32;
+	struct ppp_idle idle;
+	unsigned int kcmd;
+	void *karg;
+	int err = 0;
+
+	switch (cmd) {
+	case PPPIOCGIDLE32:
+		kcmd = PPPIOCGIDLE;
+		karg = &idle;
+		break;
+	case PPPIOCSCOMPRESS32:
+		if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
+			return -EFAULT;
+		data.ptr = kmalloc (data32.length, GFP_KERNEL);
+		if (!data.ptr)
+			return -ENOMEM;
+		if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) {
+			kfree(data.ptr);
+			return -EFAULT;
+		}
+		data.length = data32.length;
+		data.transmit = data32.transmit;
+		kcmd = PPPIOCSCOMPRESS;
+		karg = &data;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("ppp_ioctl: Unknown cmd fd(%d) "
+				       "cmd(%08x) arg(%08x)\n",
+				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while (0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	switch (cmd) {
+	case PPPIOCGIDLE32:
+		if (err)
+			return err;
+		idle32.xmit_idle = idle.xmit_idle;
+		idle32.recv_idle = idle.recv_idle;
+		if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32)))
+			return -EFAULT;
+		break;
+	case PPPIOCSCOMPRESS32:
+		kfree(data.ptr);
+		break;
+	default:
+		break;
+	}
+	return err;
+}
+
+
+struct mtget32 {
+	__u32	mt_type;
+	__u32	mt_resid;
+	__u32	mt_dsreg;
+	__u32	mt_gstat;
+	__u32	mt_erreg;
+	__kernel_daddr_t32	mt_fileno;
+	__kernel_daddr_t32	mt_blkno;
+};
+#define MTIOCGET32	_IOR('m', 2, struct mtget32)
+
+struct mtpos32 {
+	__u32	mt_blkno;
+};
+#define MTIOCPOS32	_IOR('m', 3, struct mtpos32)
+
+struct mtconfiginfo32 {
+	__u32	mt_type;
+	__u32	ifc_type;
+	__u16	irqnr;
+	__u16	dmanr;
+	__u16	port;
+	__u32	debug;
+	__u32	have_dens:1;
+	__u32	have_bsf:1;
+	__u32	have_fsr:1;
+	__u32	have_bsr:1;
+	__u32	have_eod:1;
+	__u32	have_seek:1;
+	__u32	have_tell:1;
+	__u32	have_ras1:1;
+	__u32	have_ras2:1;
+	__u32	have_ras3:1;
+	__u32	have_qfa:1;
+	__u32	pad1:5;
+	char	reserved[10];
+};
+#define	MTIOCGETCONFIG32	_IOR('m', 4, struct mtconfiginfo32)
+#define	MTIOCSETCONFIG32	_IOW('m', 5, struct mtconfiginfo32)
+
+static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct mtconfiginfo info;
+	struct mtget get;
+	struct mtpos pos;
+	unsigned long kcmd;
+	void *karg;
+	int err = 0;
+
+	switch(cmd) {
+	case MTIOCPOS32:
+		kcmd = MTIOCPOS;
+		karg = &pos;
+		break;
+	case MTIOCGET32:
+		kcmd = MTIOCGET;
+		karg = &get;
+		break;
+	case MTIOCGETCONFIG32:
+		kcmd = MTIOCGETCONFIG;
+		karg = &info;
+		break;
+	case MTIOCSETCONFIG32:
+		kcmd = MTIOCSETCONFIG;
+		karg = &info;
+		err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+		err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+		err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+		err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+		err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+		err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+		err |= __copy_from_user((char *)&info.debug + sizeof(info.debug),
+				     (char *)&((struct mtconfiginfo32 *)arg)->debug
+				     + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32));
+		if (err)
+			return -EFAULT;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("mt_ioctl: Unknown cmd fd(%d) "
+				       "cmd(%08x) arg(%08x)\n",
+				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while (0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		return err;
+	switch (cmd) {
+	case MTIOCPOS32:
+		err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno);
+		break;
+	case MTIOCGET32:
+		err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type);
+		err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid);
+		err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg);
+		err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat);
+		err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg);
+		err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno);
+		err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno);
+		break;
+	case MTIOCGETCONFIG32:
+		err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+		err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+		err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+		err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+		err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+		err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+		err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug
+			    		   + sizeof(((struct mtconfiginfo32 *)arg)->debug),
+					   (char *)&info.debug + sizeof(info.debug), sizeof(__u32));
+		break;
+	case MTIOCSETCONFIG32:
+		break;
+	}
+	return err ? -EFAULT: 0;
+}
+
+struct cdrom_read_audio32 {
+	union cdrom_addr	addr;
+	u_char			addr_format;
+	int			nframes;
+	__kernel_caddr_t32	buf;
+};
+
+struct cdrom_generic_command32 {
+	unsigned char		cmd[CDROM_PACKET_SIZE];
+	__kernel_caddr_t32	buffer;
+	unsigned int		buflen;
+	int			stat;
+	__kernel_caddr_t32	sense;
+	__kernel_caddr_t32	reserved[3];
+};
+
+static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct cdrom_read_audio cdreadaudio;
+	struct cdrom_generic_command cgc;
+	__kernel_caddr_t32 addr;
+	char *data = 0;
+	void *karg;
+	int err = 0;
+
+	switch(cmd) {
+	case CDROMREADAUDIO:
+		karg = &cdreadaudio;
+		err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr));
+		err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format);
+		err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); 
+		err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
+		if (err)
+			return -EFAULT;
+		data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		cdreadaudio.buf = data;
+		break;
+	case CDROM_SEND_PACKET:
+		karg = &cgc;
+		err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd));
+		err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer);
+		err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen);
+		if (err)
+			return -EFAULT;
+		if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		cgc.buffer = data;
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk("cdrom_ioctl: Unknown cmd fd(%d) "
+				       "cmd(%08x) arg(%08x)\n",
+				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		} while (0);
+		return -EINVAL;
+	}
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)karg);
+	set_fs (old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+	case CDROMREADAUDIO:
+		err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352);
+		break;
+	case CDROM_SEND_PACKET:
+		err = copy_to_user((char *)A(addr), data, cgc.buflen);
+		break;
+	default:
+		break;
+	}
+out:	if (data)
+		kfree(data);
+	return err ? -EFAULT : 0;
+}
+
+struct loop_info32 {
+	int			lo_number;      /* ioctl r/o */
+	__kernel_dev_t32	lo_device;      /* ioctl r/o */
+	unsigned int		lo_inode;       /* ioctl r/o */
+	__kernel_dev_t32	lo_rdevice;     /* ioctl r/o */
+	int			lo_offset;
+	int			lo_encrypt_type;
+	int			lo_encrypt_key_size;    /* ioctl w/o */
+	int			lo_flags;       /* ioctl r/o */
+	char			lo_name[LO_NAME_SIZE];
+	unsigned char		lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned int		lo_init[2];
+	char			reserved[4];
+};
+
+static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct loop_info l;
+	int err = -EINVAL;
+
+	switch(cmd) {
+	case LOOP_SET_STATUS:
+		err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+		err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+		err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+		err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+		err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
+					   8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+		if (err) {
+			err = -EFAULT;
+		} else {
+			set_fs (KERNEL_DS);
+			err = sys_ioctl (fd, cmd, (unsigned long)&l);
+			set_fs (old_fs);
+		}
+		break;
+	case LOOP_GET_STATUS:
+		set_fs (KERNEL_DS);
+		err = sys_ioctl (fd, cmd, (unsigned long)&l);
+		set_fs (old_fs);
+		if (!err) {
+			err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+			err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+			err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+			err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+			err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset,
+					   (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+			if (err)
+				err = -EFAULT;
+		}
+		break;
+	default: {
+		static int count = 0;
+		if (++count <= 20)
+			printk("%s: Unknown loop ioctl cmd, fd(%d) "
+			       "cmd(%08x) arg(%08lx)\n",
+			       __FUNCTION__, fd, cmd, arg);
+	}
+	}
+	return err;
+}
+
+extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_VT
+static int vt_check(struct file *file)
+{
+	struct tty_struct *tty;
+	struct inode *inode = file->f_dentry->d_inode;
+	
+	if (file->f_op->ioctl != tty_ioctl)
+		return -EINVAL;
+	                
+	tty = (struct tty_struct *)file->private_data;
+	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+		return -EINVAL;
+	                                                
+	if (tty->driver.ioctl != vt_ioctl)
+		return -EINVAL;
+	
+	/*
+	 * To have permissions to do most of the vt ioctls, we either have
+	 * to be the owner of the tty, or super-user.
+	 */
+	if (current->tty == tty || suser())
+		return 1;
+	return 0;                                                    
+}
+
+struct consolefontdesc32 {
+	unsigned short charcount;       /* characters in font (256 or 512) */
+	unsigned short charheight;      /* scan lines per character (1-32) */
+	u32 chardata;			/* font data in expanded form */
+};
+
+static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file)
+{
+	struct consolefontdesc cfdarg;
+	struct console_font_op op;
+	int i, perm;
+
+	perm = vt_check(file);
+	if (perm < 0) return perm;
+	
+	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32)))
+		return -EFAULT;
+	
+	cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata);
+ 	
+	switch (cmd) {
+	case PIO_FONTX:
+		if (!perm)
+			return -EPERM;
+		op.op = KD_FONT_OP_SET;
+		op.flags = 0;
+		op.width = 8;
+		op.height = cfdarg.charheight;
+		op.charcount = cfdarg.charcount;
+		op.data = cfdarg.chardata;
+		return con_font_op(fg_console, &op);
+	case GIO_FONTX:
+		if (!cfdarg.chardata)
+			return 0;
+		op.op = KD_FONT_OP_GET;
+		op.flags = 0;
+		op.width = 8;
+		op.height = cfdarg.charheight;
+		op.charcount = cfdarg.charcount;
+		op.data = cfdarg.chardata;
+		i = con_font_op(fg_console, &op);
+		if (i)
+			return i;
+		cfdarg.charheight = op.height;
+		cfdarg.charcount = op.charcount;
+		((struct consolefontdesc32 *)&cfdarg)->chardata	= (unsigned long)cfdarg.chardata;
+		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32)))
+			return -EFAULT;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+struct console_font_op32 {
+	unsigned int op;        /* operation code KD_FONT_OP_* */
+	unsigned int flags;     /* KD_FONT_FLAG_* */
+	unsigned int width, height;     /* font size */
+	unsigned int charcount;
+	u32 data;    /* font data with height fixed to 32 */
+};
+                                        
+static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file)
+{
+	struct console_font_op op;
+	int perm = vt_check(file), i;
+	struct vt_struct *vt;
+	
+	if (perm < 0) return perm;
+	
+	if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32)))
+		return -EFAULT;
+	if (!perm && op.op != KD_FONT_OP_GET)
+		return -EPERM;
+	op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data);
+	op.flags |= KD_FONT_FLAG_OLD;
+	vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data;
+	i = con_font_op(vt->vc_num, &op);
+	if (i) return i;
+	((struct console_font_op32 *)&op)->data = (unsigned long)op.data;
+	if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32)))
+		return -EFAULT;
+	return 0;
+}
+
+struct fb_fix_screeninfo32 {
+	char id[16];			/* identification string eg "TT Builtin" */
+	unsigned int smem_start;	/* Start of frame buffer mem */
+					/* (physical address) */
+	__u32 smem_len;			/* Length of frame buffer mem */
+	__u32 type;			/* see FB_TYPE_*		*/
+	__u32 type_aux;			/* Interleave for interleaved Planes */
+	__u32 visual;			/* see FB_VISUAL_*		*/ 
+	__u16 xpanstep;			/* zero if no hardware panning  */
+	__u16 ypanstep;			/* zero if no hardware panning  */
+	__u16 ywrapstep;		/* zero if no hardware ywrap    */
+	__u32 line_length;		/* length of a line in bytes    */
+	unsigned int mmio_start;	/* Start of Memory Mapped I/O   */
+					/* (physical address) */
+	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
+	__u32 accel;			/* Type of acceleration available */
+	__u16 reserved[3];		/* Reserved for future compatibility */
+};
+
+static int do_fbioget_fscreeninfo_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct fb_fix_screeninfo fix;
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (long)&fix);
+	set_fs(old_fs);
+
+	if (err == 0) {
+		unsigned int smem_start = fix.smem_start;  /* lose top 32 bits */
+		unsigned int mmio_start = fix.mmio_start;  /* lose top 32 bits */
+		int i;
+
+		err = put_user(fix.id[0], &((struct fb_fix_screeninfo32 *)arg)->id[0]);
+		for (i=1; i<16; i++) {
+			err |= __put_user(fix.id[i], &((struct fb_fix_screeninfo32 *)arg)->id[i]);
+		}
+		err |= __put_user(smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start);
+		err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len);
+		err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type);
+		err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux);
+		err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual);
+		err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep);
+		err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep);
+		err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep);
+		err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length);
+		err |= __put_user(mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start);
+		err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len);
+		err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel);
+		err |= __put_user(fix.reserved[0], &((struct fb_fix_screeninfo32 *)arg)->reserved[0]);
+		err |= __put_user(fix.reserved[1], &((struct fb_fix_screeninfo32 *)arg)->reserved[1]);
+		err |= __put_user(fix.reserved[2], &((struct fb_fix_screeninfo32 *)arg)->reserved[2]);
+		if (err)
+			err = -EFAULT;
+	}
+	return err;
+}
+
+struct fb_cmap32 {
+	__u32 start;			/* First entry	*/
+	__u32 len;			/* Number of entries */
+	__u32 redptr;			/* Red values	*/
+	__u32 greenptr;
+	__u32 blueptr;
+	__u32 transpptr;		/* transparency, can be NULL */
+};
+
+static int do_fbiogetcmap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct fb_cmap cmap;
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (long)&cmap);
+	set_fs(old_fs);
+
+	if (err == 0) {
+		__u32 redptr = (__u32)(__u64)cmap.red;
+		__u32 greenptr = (__u32)(__u64)cmap.green;
+		__u32 blueptr = (__u32)(__u64)cmap.blue;
+		__u32 transpptr = (__u32)(__u64)cmap.transp;
+
+		err = put_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
+		err |= __put_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
+		err |= __put_user(redptr, &((struct fb_cmap32 *)arg)->redptr);
+		err |= __put_user(greenptr, &((struct fb_cmap32 *)arg)->greenptr);
+		err |= __put_user(blueptr, &((struct fb_cmap32 *)arg)->blueptr);
+		err |= __put_user(transpptr, &((struct fb_cmap32 *)arg)->transpptr);
+		if (err)
+			err = -EFAULT;
+	}
+	return err;
+}
+
+static int do_fbioputcmap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct fb_cmap cmap;
+	__u32 redptr, greenptr, blueptr, transpptr;
+	int err;
+
+	err = get_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
+	err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
+	err |= __get_user(redptr, &((struct fb_cmap32 *)arg)->redptr);
+	err |= __get_user(greenptr, &((struct fb_cmap32 *)arg)->greenptr);
+	err |= __get_user(blueptr, &((struct fb_cmap32 *)arg)->blueptr);
+	err |= __get_user(transpptr, &((struct fb_cmap32 *)arg)->transpptr);
+
+	if (err) {
+		err = -EFAULT;
+	} else {
+		cmap.red = (__u16 *)(__u64)redptr;
+		cmap.green = (__u16 *)(__u64)greenptr;
+		cmap.blue = (__u16 *)(__u64)blueptr;
+		cmap.transp = (__u16 *)(__u64)transpptr;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl (fd, cmd, (unsigned long)&cmap);
+		set_fs (old_fs);
+	}
+	return err;
+}
+
+struct unimapdesc32 {
+	unsigned short entry_ct;
+	u32 entries;
+};
+
+static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file)
+{
+	struct unimapdesc32 tmp;
+	int perm = vt_check(file);
+	
+	if (perm < 0) return perm;
+	if (copy_from_user(&tmp, user_ud, sizeof tmp))
+		return -EFAULT;
+	switch (cmd) {
+	case PIO_UNIMAP:
+		if (!perm) return -EPERM;
+		return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries));
+	case GIO_UNIMAP:
+		return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries));
+	}
+	return 0;
+}
+#endif /* CONFIG_VT */
+static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = SMB_IOC_GETMOUNTUID;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (err >= 0)
+		err = put_user(kuid, (__kernel_uid_t32 *)arg);
+
+	return err;
+}
+
+struct atmif_sioc32 {
+        int                number;
+        int                length;
+        __kernel_caddr_t32 arg;
+};
+
+struct atm_iobuf32 {
+	int                length;
+	__kernel_caddr_t32 buffer;
+};
+
+#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32)
+#define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32)
+#define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32)
+#define ATM_GETESI32	  _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32)
+#define ATM_GETADDR32	  _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32)
+#define ATM_RSTADDR32	  _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32)
+#define ATM_ADDADDR32	  _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32)
+#define ATM_DELADDR32	  _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32)
+#define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32)
+#define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32)
+#define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32)
+#define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
+#define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
+#define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
+#define ATM_GETLOOP32	  _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
+#define ATM_SETLOOP32	  _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
+#define ATM_QUERYLOOP32	  _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
+
+static struct {
+        unsigned int cmd32;
+        unsigned int cmd;
+} atm_ioctl_map[] = {
+        { ATM_GETLINKRATE32, ATM_GETLINKRATE },
+	{ ATM_GETNAMES32,    ATM_GETNAMES },
+        { ATM_GETTYPE32,     ATM_GETTYPE },
+        { ATM_GETESI32,      ATM_GETESI },
+        { ATM_GETADDR32,     ATM_GETADDR },
+        { ATM_RSTADDR32,     ATM_RSTADDR },
+        { ATM_ADDADDR32,     ATM_ADDADDR },
+        { ATM_DELADDR32,     ATM_DELADDR },
+        { ATM_GETCIRANGE32,  ATM_GETCIRANGE },
+	{ ATM_SETCIRANGE32,  ATM_SETCIRANGE },
+	{ ATM_SETESI32,      ATM_SETESI },
+	{ ATM_SETESIF32,     ATM_SETESIF },
+	{ ATM_GETSTAT32,     ATM_GETSTAT },
+	{ ATM_GETSTATZ32,    ATM_GETSTATZ },
+	{ ATM_GETLOOP32,     ATM_GETLOOP },
+	{ ATM_SETLOOP32,     ATM_SETLOOP },
+	{ ATM_QUERYLOOP32,   ATM_QUERYLOOP }
+};
+
+#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0]))
+
+
+static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct atm_iobuf32 iobuf32;
+	struct atm_iobuf   iobuf = { 0, NULL };
+	mm_segment_t old_fs;
+	int err;
+
+	err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg,
+	    sizeof(struct atm_iobuf32));
+	if (err)
+		return -EFAULT;
+
+	iobuf.length = iobuf32.length;
+
+	if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) {
+		iobuf.buffer = (void*)(unsigned long)iobuf32.buffer;
+	} else {
+		iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL);
+		if (iobuf.buffer == NULL) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		err = copy_from_user(iobuf.buffer, (void *)A(iobuf32.buffer), iobuf.length);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);      
+	set_fs (old_fs);
+        if (err)
+		goto out;
+
+        if (iobuf.buffer && iobuf.length > 0) {
+		err = copy_to_user((void *)A(iobuf32.buffer), iobuf.buffer, iobuf.length);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+	err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
+
+ out:
+        if (iobuf32.buffer && iobuf32.length > 0)
+		kfree(iobuf.buffer);
+
+	return err;
+}
+
+
+static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+        struct atmif_sioc32 sioc32;
+        struct atmif_sioc   sioc = { 0, 0, NULL };
+        mm_segment_t old_fs;
+        int err;
+        
+        err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg,
+			     sizeof(struct atmif_sioc32));
+        if (err)
+                return -EFAULT;
+
+        sioc.number = sioc32.number;
+        sioc.length = sioc32.length;
+        
+	if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) {
+		sioc.arg = (void*)(unsigned long)sioc32.arg;
+        } else {
+                sioc.arg = kmalloc(sioc.length, GFP_KERNEL);
+                if (sioc.arg == NULL) {
+                        err = -ENOMEM;
+			goto out;
+		}
+                
+                err = copy_from_user(sioc.arg, (void *)A(sioc32.arg), sioc32.length);
+                if (err) {
+                        err = -EFAULT;
+                        goto out;
+                }
+        }
+        
+        old_fs = get_fs(); set_fs (KERNEL_DS);
+        err = sys_ioctl (fd, cmd, (unsigned long)&sioc);	
+        set_fs (old_fs);
+        if (err) {
+                goto out;
+	}
+        
+        if (sioc.arg && sioc.length > 0) {
+                err = copy_to_user((void *)A(sioc32.arg), sioc.arg, sioc.length);
+                if (err) {
+                        err = -EFAULT;
+                        goto out;
+                }
+        }
+        err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
+        
+ out:
+        if (sioc32.arg && sioc32.length > 0)
+		kfree(sioc.arg);
+        
+	return err;
+}
+
+
+static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
+{
+        int i;
+        unsigned int cmd = 0;
+        
+	switch (cmd32) {
+	case SONET_GETSTAT:
+	case SONET_GETSTATZ:
+	case SONET_GETDIAG:
+	case SONET_SETDIAG:
+	case SONET_CLRDIAG:
+	case SONET_SETFRAMING:
+	case SONET_GETFRAMING:
+	case SONET_GETFRSENSE:
+		return do_atmif_sioc(fd, cmd32, arg);
+	}
+
+		for (i = 0; i < NR_ATM_IOCTL; i++) {
+			if (cmd32 == atm_ioctl_map[i].cmd32) {
+				cmd = atm_ioctl_map[i].cmd;
+				break;
+			}
+		}
+	        if (i == NR_ATM_IOCTL) {
+	        return -EINVAL;
+	        }
+        
+        switch (cmd) {
+	case ATM_GETNAMES:
+		return do_atm_iobuf(fd, cmd, arg);
+	    
+	case ATM_GETLINKRATE:
+        case ATM_GETTYPE:
+        case ATM_GETESI:
+        case ATM_GETADDR:
+        case ATM_RSTADDR:
+        case ATM_ADDADDR:
+        case ATM_DELADDR:
+        case ATM_GETCIRANGE:
+	case ATM_SETCIRANGE:
+	case ATM_SETESI:
+	case ATM_SETESIF:
+	case ATM_GETSTAT:
+	case ATM_GETSTATZ:
+	case ATM_GETLOOP:
+	case ATM_SETLOOP:
+	case ATM_QUERYLOOP:
+                return do_atmif_sioc(fd, cmd, arg);
+        }
+
+        return -EINVAL;
+}
+
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */
+typedef struct {
+	uint8_t vg_name[NAME_LEN];
+	uint32_t vg_number;
+	uint32_t vg_access;
+	uint32_t vg_status;
+	uint32_t lv_max;
+	uint32_t lv_cur;
+	uint32_t lv_open;
+	uint32_t pv_max;
+	uint32_t pv_cur;
+	uint32_t pv_act;
+	uint32_t dummy;
+	uint32_t vgda;
+	uint32_t pe_size;
+	uint32_t pe_total;
+	uint32_t pe_allocated;
+	uint32_t pvg_total;
+	u32 proc;
+	u32 pv[ABS_MAX_PV + 1];
+	u32 lv[ABS_MAX_LV + 1];
+    	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	uint8_t dummy1[200];
+} vg32_t;
+
+typedef struct {
+	uint8_t id[2];
+	uint16_t version;
+	lvm_disk_data_t pv_on_disk;
+	lvm_disk_data_t vg_on_disk;
+	lvm_disk_data_t pv_namelist_on_disk;
+	lvm_disk_data_t lv_on_disk;
+	lvm_disk_data_t pe_on_disk;
+	uint8_t pv_name[NAME_LEN];
+	uint8_t vg_name[NAME_LEN];
+	uint8_t system_id[NAME_LEN];
+	kdev_t pv_dev;
+	uint32_t pv_number;
+	uint32_t pv_status;
+	uint32_t pv_allocatable;
+	uint32_t pv_size;
+	uint32_t lv_cur;
+	uint32_t pe_size;
+	uint32_t pe_total;
+	uint32_t pe_allocated;
+	uint32_t pe_stale;
+	u32 pe;
+	u32 inode;
+	uint8_t pv_uuid[UUID_LEN+1];
+} pv32_t;
+
+typedef struct {
+	char lv_name[NAME_LEN];
+	u32 lv;
+} lv_req32_t;
+
+typedef struct {
+	u32 lv_index;
+	u32 lv;
+	/* Transfer size because user space and kernel space differ */
+	uint16_t size;
+} lv_status_byindex_req32_t;
+
+typedef struct {
+	__kernel_dev_t32 dev;
+	u32   lv;
+} lv_status_bydev_req32_t;
+
+typedef struct {
+	uint8_t lv_name[NAME_LEN];
+	kdev_t old_dev;
+	kdev_t new_dev;
+	u32 old_pe;
+	u32 new_pe;
+} le_remap_req32_t;
+
+typedef struct {
+	char pv_name[NAME_LEN];
+	u32 pv;
+} pv_status_req32_t;
+
+typedef struct {
+	uint8_t lv_name[NAME_LEN];
+	uint8_t vg_name[NAME_LEN];
+	uint32_t lv_access;
+	uint32_t lv_status;
+	uint32_t lv_open;
+	kdev_t lv_dev;
+	uint32_t lv_number;
+	uint32_t lv_mirror_copies;
+	uint32_t lv_recovery;
+	uint32_t lv_schedule;
+	uint32_t lv_size;
+	u32 lv_current_pe;
+	uint32_t lv_current_le;
+	uint32_t lv_allocated_le;
+	uint32_t lv_stripes;
+	uint32_t lv_stripesize;
+	uint32_t lv_badblock;
+	uint32_t lv_allocation;
+	uint32_t lv_io_timeout;
+	uint32_t lv_read_ahead;
+	/* delta to version 1 starts here */
+	u32 lv_snapshot_org;
+	u32 lv_snapshot_prev;
+	u32 lv_snapshot_next;
+	u32 lv_block_exception;
+	uint32_t lv_remap_ptr;
+	uint32_t lv_remap_end;
+	uint32_t lv_chunk_size;
+	uint32_t lv_snapshot_minor;
+	char dummy[200];
+} lv32_t;
+
+typedef struct {
+	u32 hash[2];
+	u32 rsector_org;
+	kdev_t rdev_org;
+	u32 rsector_new;
+	kdev_t rdev_new;
+} lv_block_exception32_t;
+
+static void put_lv_t(lv_t *l)
+{
+	if (l->lv_current_pe) vfree(l->lv_current_pe);
+	if (l->lv_block_exception) vfree(l->lv_block_exception);
+	kfree(l);
+}
+
+static lv_t *get_lv_t(u32 p, int *errp)
+{
+	int err, i;
+	u32 ptr1, ptr2;
+	size_t size;
+	lv_block_exception32_t *lbe32;
+	lv_block_exception_t *lbe;
+	lv32_t *ul = (lv32_t *)A(p);
+	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
+	if (!l) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+	memset(l, 0, sizeof(lv_t));
+	err = copy_from_user(l, ul, (long)&((lv32_t *)0)->lv_current_pe);
+	err |= __copy_from_user(&l->lv_current_le, &ul->lv_current_le,
+				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
+	err |= __copy_from_user(&l->lv_remap_ptr, &ul->lv_remap_ptr,
+				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
+	err |= __get_user(ptr1, &ul->lv_current_pe);
+	err |= __get_user(ptr2, &ul->lv_block_exception);
+	if (err) {
+		kfree(l);
+		*errp = -EFAULT;
+		return NULL;
+	}
+	if (ptr1) {
+		size = l->lv_allocated_le * sizeof(pe_t);
+		l->lv_current_pe = vmalloc(size);
+		if (l->lv_current_pe)
+			err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size);
+	}
+	if (!err && ptr2) {
+		size = l->lv_remap_end * sizeof(lv_block_exception_t);
+		l->lv_block_exception = lbe = vmalloc(size);
+		if (l->lv_block_exception) {
+			lbe32 = (lv_block_exception32_t *)A(ptr2);
+			memset(lbe, 0, size);
+                       for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+                               err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+                               err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+                               err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+                               err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
+
+			}
+		}
+	}
+	if (err || (ptr1 && !l->lv_current_pe) || (ptr2 && !l->lv_block_exception)) {
+		if (!err)
+			*errp = -ENOMEM;
+		else
+			*errp = -EFAULT;
+		put_lv_t(l);
+		return NULL;
+	}
+	return l;
+}
+
+static int copy_lv_t(u32 ptr, lv_t *l)
+{
+	int err;
+	lv32_t *ul = (lv32_t *)A(ptr);
+	u32 ptr1;
+	size_t size;
+
+	err = get_user(ptr1, &ul->lv_current_pe);
+	if (err)
+		return -EFAULT;
+	err = copy_to_user(ul, l, (long)&((lv32_t *)0)->lv_current_pe);
+	err |= __copy_to_user(&ul->lv_current_le, &l->lv_current_le,
+				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
+	err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr,
+				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
+	size = l->lv_allocated_le * sizeof(pe_t);
+	if (ptr1)
+		err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size);
+	return err ? -EFAULT : 0;
+}
+
+static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	vg_t *v = NULL;
+	union {
+		lv_req_t lv_req;
+		le_remap_req_t le_remap;
+		lv_status_byindex_req_t lv_byindex;
+	        lv_status_bydev_req_t lv_bydev;
+		pv_status_req_t pv_status;
+	} u;
+	pv_t p;
+	int err;
+	u32 ptr = 0;
+	int i;
+	mm_segment_t old_fs;
+	void *karg = &u;
+
+	switch (cmd) {
+	case VG_STATUS:
+		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
+		if (!v) return -ENOMEM;
+		karg = v;
+		break;
+
+	case VG_CREATE_OLD:
+	case VG_CREATE:
+		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
+		if (!v) return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
+		    __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+			kfree(v);
+			return -EFAULT;
+		}
+		/* 'proc' field is unused, just NULL it out. */
+		v->proc = NULL;
+		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
+			kfree(v);
+			return -EFAULT;
+		}
+		    
+		karg = v;
+		memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv));
+		if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV)
+			return -EPERM;
+		for (i = 0; i < v->pv_max; i++) {
+			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
+			if (err) break;
+			if (ptr) {
+				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
+				if (!v->pv[i]) {
+					err = -ENOMEM;
+					break;
+				}
+				err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+				if (err) {
+					err = -EFAULT;
+					break;
+				}
+				err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+				if (err) {
+				        err = -EFAULT;
+					break;
+				}
+
+				
+				v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+			}
+		}
+		if (!err) {
+			for (i = 0; i < v->lv_max; i++) {
+				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
+				if (err) break;
+				if (ptr) {
+					v->lv[i] = get_lv_t(ptr, &err);
+					if (err) break;
+				}
+			}
+		}
+		break;
+	case LV_CREATE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+	case LV_REMOVE:
+	case LV_RENAME:
+	case LV_STATUS_BYNAME:
+	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
+		if (err) return -EFAULT;
+		if (cmd != LV_REMOVE) {
+			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
+			if (err) return err;
+			u.lv_req.lv = get_lv_t(ptr, &err);
+		} else
+			u.lv_req.lv = NULL;
+		break;
+
+
+	case LV_STATUS_BYINDEX:
+		err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
+		if (err) return err;
+		u.lv_byindex.lv = get_lv_t(ptr, &err);
+		break;
+	case LV_STATUS_BYDEV:
+	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		u.lv_bydev.lv = get_lv_t(ptr, &err);
+		if (err) return err;
+		u.lv_bydev.lv = &p;
+		p.pe = NULL; p.inode = NULL;		
+		break;		
+	case VG_EXTEND:
+		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
+		if (err) return -EFAULT;
+		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
+		if (err) return -EFAULT;
+		p.pe = NULL; p.inode = NULL;
+		karg = &p;
+		break;
+	case PV_CHANGE:
+	case PV_STATUS:
+		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
+		if (err) return -EFAULT;
+		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
+		if (err) return err;
+		u.pv_status.pv = &p;
+		if (cmd == PV_CHANGE) {
+			err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err) return -EFAULT;
+			p.pe = NULL; p.inode = NULL;
+		}
+		break;
+	}
+        old_fs = get_fs(); set_fs (KERNEL_DS);
+        err = sys_ioctl (fd, cmd, (unsigned long)karg);
+        set_fs (old_fs);
+	switch (cmd) {
+	case VG_STATUS:
+		if (!err) {
+			if (copy_to_user((void *)arg, v, (long)&((vg32_t *)0)->proc) ||
+			    clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc))
+				err = -EFAULT;
+		}
+		if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) {
+		        err = -EFAULT;
+		}
+		kfree(v);
+		break;
+
+	case VG_CREATE_OLD:
+	case VG_CREATE:
+		for (i = 0; i < v->pv_max; i++) {
+			if (v->pv[i])
+				kfree(v->pv[i]);
+		}
+		for (i = 0; i < v->lv_max; i++) {
+			if (v->lv[i])
+				put_lv_t(v->lv[i]);
+		}
+		kfree(v);
+		break;
+	case LV_STATUS_BYNAME:
+		if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+		/* Fall through */
+        case LV_CREATE:
+	case LV_EXTEND:
+	case LV_REDUCE:
+		if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+		break;
+	case LV_STATUS_BYINDEX:
+		if (u.lv_byindex.lv) {
+			if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+			put_lv_t(u.lv_byindex.lv);
+		}
+		break;
+
+	case LV_STATUS_BYDEV:
+	        if (u.lv_bydev.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_bydev.lv);
+			put_lv_t(u.lv_byindex.lv);
+	        }
+	        break;
+
+	case PV_STATUS:
+		if (!err) {
+			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err) return -EFAULT;
+			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
+			if (err) return -EFAULT;
+		}
+		break;
+	};
+
+	return err;
+}
+#endif
+
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+/* This really belongs in include/linux/drm.h -DaveM */
+#include "../../../drivers/char/drm/drm.h"
+
+typedef struct drm32_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	int    name_len;	  /* Length of name buffer		    */
+	u32    name;		  /* Name of driver			    */
+	int    date_len;	  /* Length of date buffer		    */
+	u32    date;		  /* User-space buffer to hold date	    */
+	int    desc_len;	  /* Length of desc buffer		    */
+	u32    desc;		  /* User-space buffer to hold desc	    */
+} drm32_version_t;
+#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
+
+static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_version_t *uversion = (drm32_version_t *)arg;
+	char *name_ptr, *date_ptr, *desc_ptr;
+	u32 tmp1, tmp2, tmp3;
+	drm_version_t kversion;
+	mm_segment_t old_fs;
+	int ret;
+
+	memset(&kversion, 0, sizeof(kversion));
+	if (get_user(kversion.name_len, &uversion->name_len) ||
+	    get_user(kversion.date_len, &uversion->date_len) ||
+	    get_user(kversion.desc_len, &uversion->desc_len) ||
+	    get_user(tmp1, &uversion->name) ||
+	    get_user(tmp2, &uversion->date) ||
+	    get_user(tmp3, &uversion->desc))
+		return -EFAULT;
+
+	name_ptr = (char *) A(tmp1);
+	date_ptr = (char *) A(tmp2);
+	desc_ptr = (char *) A(tmp3);
+
+	ret = -ENOMEM;
+	if (kversion.name_len && name_ptr) {
+		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
+		if (!kversion.name)
+			goto out;
+	}
+	if (kversion.date_len && date_ptr) {
+		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
+		if (!kversion.date)
+			goto out;
+	}
+	if (kversion.desc_len && desc_ptr) {
+		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
+		if (!kversion.desc)
+			goto out;
+	}
+
+        old_fs = get_fs();
+	set_fs(KERNEL_DS);
+        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if ((kversion.name &&
+		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
+		    (kversion.date &&
+		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
+		    (kversion.desc &&
+		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
+			ret = -EFAULT;
+		if (put_user(kversion.version_major, &uversion->version_major) ||
+		    put_user(kversion.version_minor, &uversion->version_minor) ||
+		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
+		    put_user(kversion.name_len, &uversion->name_len) ||
+		    put_user(kversion.date_len, &uversion->date_len) ||
+		    put_user(kversion.desc_len, &uversion->desc_len))
+			ret = -EFAULT;
+	}
+
+out:
+	if (kversion.name)
+		kfree(kversion.name);
+	if (kversion.date)
+		kfree(kversion.date);
+	if (kversion.desc)
+		kfree(kversion.desc);
+	return ret;
+}
+
+typedef struct drm32_unique {
+	int	unique_len;	  /* Length of unique			    */
+	u32	unique;		  /* Unique name for driver instantiation   */
+} drm32_unique_t;
+#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
+#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
+
+static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_unique_t *uarg = (drm32_unique_t *)arg;
+	drm_unique_t karg;
+	mm_segment_t old_fs;
+	char *uptr;
+	u32 tmp;
+	int ret;
+
+	if (get_user(karg.unique_len, &uarg->unique_len))
+		return -EFAULT;
+	karg.unique = NULL;
+
+	if (get_user(tmp, &uarg->unique))
+		return -EFAULT;
+
+	uptr = (char *) A(tmp);
+
+	if (uptr) {
+		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
+		if (!karg.unique)
+			return -ENOMEM;
+		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
+		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
+			kfree(karg.unique);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == DRM32_IOCTL_GET_UNIQUE)
+		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
+	else
+		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
+		    uptr != NULL &&
+		    copy_to_user(uptr, karg.unique, karg.unique_len))
+			ret = -EFAULT;
+		if (put_user(karg.unique_len, &uarg->unique_len))
+			ret = -EFAULT;
+	}
+
+	if (karg.unique != NULL)
+		kfree(karg.unique);
+
+	return ret;
+}
+
+typedef struct drm32_map {
+	u32		offset;	 /* Requested physical address (0 for SAREA)*/
+	u32		size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	u32		handle;  /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm32_map_t;
+#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
+
+static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_map_t *uarg = (drm32_map_t *) arg;
+	drm_map_t karg;
+	mm_segment_t old_fs;
+	u32 tmp;
+	int ret;
+
+	ret  = get_user(karg.offset, &uarg->offset);
+	ret |= get_user(karg.size, &uarg->size);
+	ret |= get_user(karg.type, &uarg->type);
+	ret |= get_user(karg.flags, &uarg->flags);
+	ret |= get_user(tmp, &uarg->handle);
+	ret |= get_user(karg.mtrr, &uarg->mtrr);
+	if (ret)
+		return -EFAULT;
+
+	karg.handle = (void *) A(tmp);
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		ret  = put_user(karg.offset, &uarg->offset);
+		ret |= put_user(karg.size, &uarg->size);
+		ret |= put_user(karg.type, &uarg->type);
+		ret |= put_user(karg.flags, &uarg->flags);
+		tmp = (u32) (long)karg.handle;
+		ret |= put_user(tmp, &uarg->handle);
+		ret |= put_user(karg.mtrr, &uarg->mtrr);
+		if (ret)
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+typedef struct drm32_buf_info {
+	int	       count;	/* Entries in list			     */
+	u32	       list;    /* (drm_buf_desc_t *) */ 
+} drm32_buf_info_t;
+#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
+
+static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
+	drm_buf_desc_t *ulist;
+	drm_buf_info_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (drm_buf_desc_t *) A(tmp);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
+	if (!karg.list)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (karg.count <= orig_count &&
+		    (copy_to_user(ulist, karg.list,
+				  karg.count * sizeof(drm_buf_desc_t))))
+			ret = -EFAULT;
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_free {
+	int	       count;
+	u32	       list;	/* (int *) */
+} drm32_buf_free_t;
+#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
+
+static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
+	drm_buf_free_t karg;
+	mm_segment_t old_fs;
+	int *ulist;
+	int ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (int *) A(tmp);
+
+	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
+		goto out;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+out:
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	u32		  address;     /* Address of buffer (void *)	     */
+} drm32_buf_pub_t;
+
+typedef struct drm32_buf_map {
+	int	      count;	/* Length of buflist			    */
+	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
+	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
+} drm32_buf_map_t;
+#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
+
+static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
+	drm32_buf_pub_t *ulist;
+	drm_buf_map_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret, i;
+	u32 tmp1, tmp2;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp1, &uarg->virtual) ||
+	    get_user(tmp2, &uarg->list))
+		return -EFAULT;
+
+	karg.virtual = (void *) A(tmp1);
+	ulist = (drm32_buf_pub_t *) A(tmp2);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	for (i = 0; i < karg.count; i++) {
+		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
+		    get_user(karg.list[i].total, &ulist[i].total) ||
+		    get_user(karg.list[i].used, &ulist[i].used) ||
+		    get_user(tmp1, &ulist[i].address))
+			goto out;
+
+		karg.list[i].address = (void *) A(tmp1);
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		for (i = 0; i < orig_count; i++) {
+			tmp1 = (u32) (long) karg.list[i].address;
+			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
+			    put_user(karg.list[i].total, &ulist[i].total) ||
+			    put_user(karg.list[i].used, &ulist[i].used) ||
+			    put_user(tmp1, &ulist[i].address)) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+out:
+	kfree(karg.list);
+	return ret;
+}
+
+typedef struct drm32_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	u32		send_indices;	  /* List of handles to buffers (int *) */
+	u32		send_sizes;	  /* Lengths of data to send (int *) */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	u32		request_indices;  /* Buffer information (int *)	    */
+	u32		request_sizes;    /* (int *) */
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm32_dma_t;
+#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
+
+/* RED PEN	The DRM layer blindly dereferences the send/request
+ * 		indice/size arrays even though they are userland
+ * 		pointers.  -DaveM
+ */
+static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_dma_t *uarg = (drm32_dma_t *) arg;
+	int *u_si, *u_ss, *u_ri, *u_rs;
+	drm_dma_t karg;
+	mm_segment_t old_fs;
+	int ret;
+	u32 tmp1, tmp2, tmp3, tmp4;
+
+	karg.send_indices = karg.send_sizes = NULL;
+	karg.request_indices = karg.request_sizes = NULL;
+
+	if (get_user(karg.context, &uarg->context) ||
+	    get_user(karg.send_count, &uarg->send_count) ||
+	    get_user(tmp1, &uarg->send_indices) ||
+	    get_user(tmp2, &uarg->send_sizes) ||
+	    get_user(karg.flags, &uarg->flags) ||
+	    get_user(karg.request_count, &uarg->request_count) ||
+	    get_user(karg.request_size, &uarg->request_size) ||
+	    get_user(tmp3, &uarg->request_indices) ||
+	    get_user(tmp4, &uarg->request_sizes) ||
+	    get_user(karg.granted_count, &uarg->granted_count))
+		return -EFAULT;
+
+	u_si = (int *) A(tmp1);
+	u_ss = (int *) A(tmp2);
+	u_ri = (int *) A(tmp3);
+	u_rs = (int *) A(tmp4);
+
+	if (karg.send_count) {
+		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.send_indices || !karg.send_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.send_indices, u_si,
+				   (karg.send_count * sizeof(int))) ||
+		    copy_from_user(karg.send_sizes, u_ss,
+				   (karg.send_count * sizeof(int))))
+			goto out;
+	}
+
+	if (karg.request_count) {
+		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.request_indices || !karg.request_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.request_indices, u_ri,
+				   (karg.request_count * sizeof(int))) ||
+		    copy_from_user(karg.request_sizes, u_rs,
+				   (karg.request_count * sizeof(int))))
+			goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (put_user(karg.context, &uarg->context) ||
+		    put_user(karg.send_count, &uarg->send_count) ||
+		    put_user(karg.flags, &uarg->flags) ||
+		    put_user(karg.request_count, &uarg->request_count) ||
+		    put_user(karg.request_size, &uarg->request_size) ||
+		    put_user(karg.granted_count, &uarg->granted_count))
+			ret = -EFAULT;
+
+		if (karg.send_count) {
+			if (copy_to_user(u_si, karg.send_indices,
+					 (karg.send_count * sizeof(int))) ||
+			    copy_to_user(u_ss, karg.send_sizes,
+					 (karg.send_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+		if (karg.request_count) {
+			if (copy_to_user(u_ri, karg.request_indices,
+					 (karg.request_count * sizeof(int))) ||
+			    copy_to_user(u_rs, karg.request_sizes,
+					 (karg.request_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+	}
+
+out:
+	if (karg.send_indices)
+		kfree(karg.send_indices);
+	if (karg.send_sizes)
+		kfree(karg.send_sizes);
+	if (karg.request_indices)
+		kfree(karg.request_indices);
+	if (karg.request_sizes)
+		kfree(karg.request_sizes);
+
+	return ret;
+}
+
+typedef struct drm32_ctx_res {
+	int		count;
+	u32		contexts; /* (drm_ctx_t *) */
+} drm32_ctx_res_t;
+#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
+
+static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
+	drm_ctx_t *ulist;
+	drm_ctx_res_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	karg.contexts = NULL;
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->contexts))
+		return -EFAULT;
+
+	ulist = (drm_ctx_t *) A(tmp);
+
+	orig_count = karg.count;
+	if (karg.count && ulist) {
+		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
+		if (!karg.contexts)
+			return -ENOMEM;
+		if (copy_from_user(karg.contexts, ulist,
+				   (karg.count * sizeof(drm_ctx_t)))) {
+			kfree(karg.contexts);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (orig_count) {
+			if (copy_to_user(ulist, karg.contexts,
+					 (orig_count * sizeof(drm_ctx_t))))
+				ret = -EFAULT;
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	if (karg.contexts)
+		kfree(karg.contexts);
+
+	return ret;
+}
+
+#endif
+
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
+
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
+                                
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
+	
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
+}
+
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
+
+struct usbdevfs_ctrltransfer32 {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+
+static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_ctrltransfer kctrl;
+	struct usbdevfs_ctrltransfer32 *uctrl;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+
+	if (copy_from_user(&kctrl, uctrl,
+			   (sizeof(struct usbdevfs_ctrltransfer) -
+			    sizeof(void *))))
+		return -EFAULT;
+
+	if (get_user(udata, &uctrl->data))
+		return -EFAULT;
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kctrl.length > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *)__get_free_page(GFP_KERNEL);
+
+	if ((kctrl.requesttype & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kctrl.length))
+			goto out;
+	}
+
+	kctrl.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kctrl.requesttype & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.length))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+struct usbdevfs_bulktransfer32 {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+
+static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_bulktransfer kbulk;
+	struct usbdevfs_bulktransfer32 *ubulk;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+
+	if (get_user(kbulk.ep, &ubulk->ep) ||
+	    get_user(kbulk.len, &ubulk->len) ||
+	    get_user(kbulk.timeout, &ubulk->timeout) ||
+	    get_user(udata, &ubulk->data))
+		return -EFAULT;
+
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kbulk.len > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *) __get_free_page(GFP_KERNEL);
+
+	if ((kbulk.ep & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kbulk.len))
+			goto out;
+	}
+
+	kbulk.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kbulk.ep & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kbulk.len))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+/* This needs more work before we can enable it.  Unfortunately
+ * because of the fancy asynchronous way URB status/error is written
+ * back to userspace, we'll need to fiddle with USB devio internals
+ * and/or reimplement entirely the frontend of it ourselves. -DaveM
+ *
+ * The issue is:
+ *
+ *	When an URB is submitted via usbdevicefs it is put onto an
+ *	asynchronous queue.  When the URB completes, it may be reaped
+ *	via another ioctl.  During this reaping the status is written
+ *	back to userspace along with the length of the transfer.
+ *
+ *	We must translate into 64-bit kernel types so we pass in a kernel
+ *	space copy of the usbdevfs_urb structure.  This would mean that we
+ *	must do something to deal with the async entry reaping.  First we
+ *	have to deal somehow with this transitory memory we've allocated.
+ *	This is problematic since there are many call sites from which the
+ *	async entries can be destroyed (and thus when we'd need to free up
+ *	this kernel memory).  One of which is the close() op of usbdevicefs.
+ *	To handle that we'd need to make our own file_operations struct which
+ *	overrides usbdevicefs's release op with our own which runs usbdevicefs's
+ *	real release op then frees up the kernel memory.
+ *
+ *	But how to keep track of these kernel buffers?  We'd need to either
+ *	keep track of them in some table _or_ know about usbdevicefs internals
+ *	(ie. the exact layout of it's file private, which is actually defined
+ *	in linux/usbdevice_fs.h, the layout of the async queues are private to
+ *	devio.c)
+ *
+ * There is one possible other solution I considered, also involving knowledge
+ * of usbdevicefs internals:
+ *
+ *	After an URB is submitted, we "fix up" the address back to the user
+ *	space one.  This would work if the status/length fields written back
+ *	by the async URB completion lines up perfectly in the 32-bit type with
+ *	the 64-bit kernel type.  Unfortunately, it does not because the iso
+ *	frame descriptors, at the end of the struct, can be written back.
+ *
+ * I think we'll just need to simply duplicate the devio URB engine here.
+ */
+#if 0
+struct usbdevfs_urb32 {
+	__u8 type;
+	__u8 endpoint;
+	__s32 status;
+	__u32 flags;
+	__u32 buffer;
+	__s32 buffer_length;
+	__s32 actual_length;
+	__s32 start_frame;
+	__s32 number_of_packets;
+	__s32 error_count;
+	__u32 signr;
+	__u32 usercontext; /* unused */
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (get_user(kurb->type, &uurb->type) ||
+	    __get_user(kurb->endpoint, &uurb->endpoint) ||
+	    __get_user(kurb->status, &uurb->status) ||
+	    __get_user(kurb->flags, &uurb->flags) ||
+	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+	    __get_user(kurb->actual_length, &uurb->actual_length) ||
+	    __get_user(kurb->start_frame, &uurb->start_frame) ||
+	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+	    __get_user(kurb->error_count, &uurb->error_count) ||
+	    __get_user(kurb->signr, &uurb->signr))
+		return -EFAULT;
+
+	kurb->usercontext = 0; /* unused currently */
+
+	return 0;
+}
+
+/* Just put back the values which usbdevfs actually changes. */
+static int put_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (put_user(kurb->status, &uurb->status) ||
+	    __put_user(kurb->actual_length, &uurb->actual_length) ||
+	    __put_user(kurb->error_count, &uurb->error_count))
+		return -EFAULT;
+
+	if (kurb->number_of_packets != 0) {
+		int i;
+
+		for (i = 0; i < kurb->number_of_packets; i++) {
+			if (__put_user(kurb->iso_frame_desc[i].actual_length,
+				       &uurb->iso_frame_desc[i].actual_length) ||
+			    __put_user(kurb->iso_frame_desc[i].status,
+				       &uurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+			       struct usbdevfs_urb32 *uurb)
+{
+	unsigned int totlen;
+	int i;
+
+	if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+		kurb->number_of_packets = 0;
+		return 0;
+	}
+
+	if (kurb->number_of_packets < 1 ||
+	    kurb->number_of_packets > 128)
+		return -EINVAL;
+
+	if (copy_from_user(&kurb->iso_frame_desc[0],
+			   &uurb->iso_frame_desc[0],
+			   sizeof(struct usbdevfs_iso_packet_desc) *
+			   kurb->number_of_packets))
+		return -EFAULT;
+
+	totlen = 0;
+	for (i = 0; i < kurb->number_of_packets; i++) {
+		unsigned int this_len;
+
+		this_len = kurb->iso_frame_desc[i].length;
+		if (this_len > 1023)
+			return -EINVAL;
+
+		totlen += this_len;
+	}
+
+	if (totlen > 32768)
+		return -EINVAL;
+
+	kurb->buffer_length = totlen;
+
+	return 0;
+}
+
+static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_urb *kurb;
+	struct usbdevfs_urb32 *uurb;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	unsigned int buflen;
+	int err;
+
+	uurb = (struct usbdevfs_urb32 *) arg;
+
+	err = -ENOMEM;
+	kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+		       (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+		       GFP_KERNEL);
+	if (!kurb)
+		goto out;
+
+	err = -EFAULT;
+	if (get_urb32(kurb, uurb))
+		goto out;
+
+	err = get_urb32_isoframes(kurb, uurb);
+	if (err)
+		goto out;
+
+	err = -EFAULT;
+	if (__get_user(udata, &uurb->buffer))
+		goto out;
+	uptr = (void *) A(udata);
+
+	err = -ENOMEM;
+	buflen = kurb->buffer_length;
+	kptr = kmalloc(buflen, GFP_KERNEL);
+	if (!kptr)
+		goto out;
+
+	kurb->buffer = kptr;
+
+	err = -EFAULT;
+	if (copy_from_user(kptr, uptr, buflen))
+		goto out_kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+	set_fs(old_fs);
+
+	if (err >= 0) {
+		/* XXX Shit, this doesn't work for async URBs :-( XXX */
+		if (put_urb32(kurb, uurb)) {
+			err = -EFAULT;
+		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+			if (copy_to_user(uptr, kptr, buflen))
+				err = -EFAULT;
+		}
+	}
+
+out_kptr:
+	kfree(kptr);
+
+out:
+	kfree(kurb);
+	return err;
+}
+#endif
+
+#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+
+static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs;
+	void *kptr;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd,
+			(cmd == USBDEVFS_REAPURB32 ?
+			 USBDEVFS_REAPURB :
+			 USBDEVFS_REAPURBNDELAY),
+			(unsigned long) &kptr);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    put_user(((u32)(long)kptr), (u32 *) A(arg)))
+		err = -EFAULT;
+
+	return err;
+}
+
+struct usbdevfs_disconnectsignal32 {
+	unsigned int signr;
+	u32 context;
+};
+
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+
+static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_disconnectsignal kdis;
+	struct usbdevfs_disconnectsignal32 *udis;
+	mm_segment_t old_fs;
+	u32 uctx;
+	int err;
+
+	udis = (struct usbdevfs_disconnectsignal32 *) arg;
+
+	if (get_user(kdis.signr, &udis->signr) ||
+	    __get_user(uctx, &udis->context))
+		return -EFAULT;
+
+	kdis.context = (void *) (long)uctx;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+	set_fs(old_fs);
+
+	return err;
+}
+
+struct mtd_oob_buf32 {
+	u32 start;
+	u32 length;
+	u32 ptr;	/* unsigned char* */
+};
+
+#define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
+#define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
+
+static inline int 
+mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t 			old_fs 	= get_fs();
+	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
+	struct mtd_oob_buf		karg;
+	u32 tmp;
+	char *ptr;
+	int ret;
+
+	if (get_user(karg.start, &uarg->start) 		||
+	    get_user(karg.length, &uarg->length)	||
+	    get_user(tmp, &uarg->ptr))
+		return -EFAULT;
+
+	ptr = (char *)A(tmp);
+	if (0 >= karg.length) 
+		return -EINVAL;
+
+	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
+	if (NULL == karg.ptr)
+		return -ENOMEM;
+
+	if (copy_from_user(karg.ptr, ptr, karg.length)) {
+		kfree(karg.ptr);
+		return -EFAULT;
+	}
+
+	set_fs(KERNEL_DS);
+	if (MEMREADOOB32 == cmd) 
+		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
+	else if (MEMWRITEOOB32 == cmd)
+		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
+	else
+		ret = -EINVAL;
+	set_fs(old_fs);
+
+	if (0 == ret && cmd == MEMREADOOB32) {
+		ret = copy_to_user(ptr, karg.ptr, karg.length);
+		ret |= put_user(karg.start, &uarg->start);
+		ret |= put_user(karg.length, &uarg->length);
+	}
+
+	kfree(karg.ptr);
+	return ((0 == ret) ? 0 : -EFAULT);
+}	
+
+struct sg_io_hdr_32
+{
+	int interface_id;
+	int dxfer_direction;
+	unsigned char cmd_len;
+	unsigned char mx_sb_len;
+	unsigned short iovec_count;
+	unsigned int dxfer_len;
+	u32 dxferp;
+	u32 cmdp;
+	u32 sbp;
+	unsigned int timeout;
+	unsigned int flags;
+	int pack_id;
+	u32 usr_ptr;
+	unsigned char status;
+	unsigned char masked_status;
+	unsigned char msg_status;
+	unsigned char sb_len_wr;
+	unsigned short host_status;
+	unsigned short driver_status;
+	int resid;
+	unsigned int duration;
+	unsigned int info;
+};
+
+static int do_sg_io(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct sg_io_hdr *sg = kmalloc(sizeof(struct sg_io_hdr), GFP_KERNEL);
+	struct sg_io_hdr_32 *sg_32 = (struct sg_io_hdr_32 *)arg;
+	u32 dxferp_32;
+	u32 cmdp_32;
+	u32 sbp_32;
+	u32 usr_ptr_32;
+	int ret = -EFAULT;
+	int err;
+	mm_segment_t old_fs = get_fs();
+
+	if (!sg)
+		return -ENOMEM;
+
+	memset(sg, 0, sizeof(*sg));
+
+	err = copy_from_user(sg, sg_32, offsetof(struct sg_io_hdr, dxferp));
+	err |= __get_user(dxferp_32, &sg_32->dxferp);
+	err |= __get_user(cmdp_32, &sg_32->cmdp);
+	err |= __get_user(sbp_32, &sg_32->sbp);
+
+	if (err)
+		goto error;
+
+	sg->dxferp = (void *)A(dxferp_32);
+	sg->cmdp = (void *)A(cmdp_32);
+	sg->sbp = (void *)A(sbp_32);
+
+	err = __copy_from_user(&sg->timeout, &sg_32->timeout,
+			       (long)&sg->usr_ptr - (long)&sg->timeout);
+
+	err |= __get_user(usr_ptr_32, &sg_32->usr_ptr);
+
+	if (err)
+		goto error;
+
+	sg->usr_ptr = (void *)A(usr_ptr_32);
+
+	err = __copy_from_user(&sg->status, &sg_32->status,
+			       sizeof(struct sg_io_hdr) -
+			       offsetof(struct sg_io_hdr, status));
+
+	if (err)
+		goto error;
+
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, cmd, (unsigned long)sg);
+	set_fs(old_fs);
+
+	err = copy_to_user(sg_32, sg, offsetof(struct sg_io_hdr, dxferp));
+
+	dxferp_32 = (unsigned long)sg->dxferp;
+	cmdp_32 = (unsigned long)sg->cmdp;
+	sbp_32 = (unsigned long)sg->sbp;
+	err |= __put_user(dxferp_32, &sg_32->dxferp);
+	err |= __put_user(cmdp_32, &sg_32->cmdp);
+	err |= __put_user(sbp_32, &sg_32->sbp);
+
+	if (err) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	err = __copy_to_user(&sg_32->timeout, &sg->timeout,
+			     (long)&sg->usr_ptr - (long)&sg->timeout);
+
+	usr_ptr_32 = (unsigned long)sg->usr_ptr;
+	err |= __put_user(usr_ptr_32, &sg_32->usr_ptr);
+
+	if (err) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	err = __copy_to_user(&sg_32->status, &sg->status,
+			      sizeof(struct sg_io_hdr) -
+			      offsetof(struct sg_io_hdr, status));
+
+	if (err)
+		ret = -EFAULT;
+
+error:
+	kfree(sg);
+	return ret;
+}
+
+struct ioctl_trans {
+	unsigned long cmd;
+	unsigned long handler;
+	unsigned long next;
+};
+
+#define COMPATIBLE_IOCTL(cmd) { cmd, (unsigned long)sys_ioctl, 0 }
+
+#define HANDLE_IOCTL(cmd,handler) { cmd, (unsigned long)handler, 0 }
+
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
+
+static struct ioctl_trans ioctl_translations[] = {
+    /* List here explicitly which ioctl's need translation,
+     * all others default to calling sys_ioctl().
+     */
+/* Big T */
+COMPATIBLE_IOCTL(TCGETA),
+COMPATIBLE_IOCTL(TCSETA),
+COMPATIBLE_IOCTL(TCSETAW),
+COMPATIBLE_IOCTL(TCSETAF),
+COMPATIBLE_IOCTL(TCSBRK),
+COMPATIBLE_IOCTL(TCXONC),
+COMPATIBLE_IOCTL(TCFLSH),
+COMPATIBLE_IOCTL(TCGETS),
+COMPATIBLE_IOCTL(TCSETS),
+COMPATIBLE_IOCTL(TCSETSW),
+COMPATIBLE_IOCTL(TCSETSF),
+COMPATIBLE_IOCTL(TIOCLINUX),
+COMPATIBLE_IOCTL(TIOCSTART),
+/* Little t */
+COMPATIBLE_IOCTL(TIOCGETD),
+COMPATIBLE_IOCTL(TIOCSETD),
+COMPATIBLE_IOCTL(TIOCEXCL),
+COMPATIBLE_IOCTL(TIOCNXCL),
+COMPATIBLE_IOCTL(TIOCCONS),
+COMPATIBLE_IOCTL(TIOCGSOFTCAR),
+COMPATIBLE_IOCTL(TIOCSSOFTCAR),
+COMPATIBLE_IOCTL(TIOCSWINSZ),
+COMPATIBLE_IOCTL(TIOCGWINSZ),
+COMPATIBLE_IOCTL(TIOCMGET),
+COMPATIBLE_IOCTL(TIOCMBIC),
+COMPATIBLE_IOCTL(TIOCMBIS),
+COMPATIBLE_IOCTL(TIOCMSET),
+COMPATIBLE_IOCTL(TIOCPKT),
+COMPATIBLE_IOCTL(TIOCNOTTY),
+COMPATIBLE_IOCTL(TIOCSTI),
+COMPATIBLE_IOCTL(TIOCOUTQ),
+COMPATIBLE_IOCTL(TIOCSPGRP),
+COMPATIBLE_IOCTL(TIOCGPGRP),
+COMPATIBLE_IOCTL(TIOCSCTTY),
+COMPATIBLE_IOCTL(TIOCGPTN),
+COMPATIBLE_IOCTL(TIOCSPTLCK),
+COMPATIBLE_IOCTL(TIOCGSERIAL),
+COMPATIBLE_IOCTL(TIOCSSERIAL),
+COMPATIBLE_IOCTL(TIOCSERGETLSR),
+COMPATIBLE_IOCTL(TIOCSLTC),
+/* Big F */
+COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO),
+COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO),
+COMPATIBLE_IOCTL(FBIOPAN_DISPLAY),
+COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO),
+COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO),
+COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO),
+COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE),
+COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE),
+COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP),
+COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP),
+#if 0
+COMPATIBLE_IOCTL(FBIOBLANK),
+#endif
+/* Little f */
+COMPATIBLE_IOCTL(FIOCLEX),
+COMPATIBLE_IOCTL(FIONCLEX),
+COMPATIBLE_IOCTL(FIOASYNC),
+COMPATIBLE_IOCTL(FIONBIO),
+COMPATIBLE_IOCTL(FIONREAD),  /* This is also TIOCINQ */
+/* 0x00 */
+COMPATIBLE_IOCTL(FIBMAP),
+COMPATIBLE_IOCTL(FIGETBSZ),
+/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ *         Some need translations, these do not.
+ */
+COMPATIBLE_IOCTL(HDIO_GET_IDENTITY),
+COMPATIBLE_IOCTL(HDIO_SET_DMA),
+COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS),
+COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR),
+COMPATIBLE_IOCTL(HDIO_SET_NOWERR),
+COMPATIBLE_IOCTL(HDIO_SET_32BIT),
+COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT),
+COMPATIBLE_IOCTL(HDIO_DRIVE_CMD),
+COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE),
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF),
+COMPATIBLE_IOCTL(HDIO_SET_NICE),
+/* 0x02 -- Floppy ioctls */
+COMPATIBLE_IOCTL(FDMSGON),
+COMPATIBLE_IOCTL(FDMSGOFF),
+COMPATIBLE_IOCTL(FDSETEMSGTRESH),
+COMPATIBLE_IOCTL(FDFLUSH),
+COMPATIBLE_IOCTL(FDWERRORCLR),
+COMPATIBLE_IOCTL(FDSETMAXERRS),
+COMPATIBLE_IOCTL(FDGETMAXERRS),
+COMPATIBLE_IOCTL(FDGETDRVTYP),
+COMPATIBLE_IOCTL(FDEJECT),
+COMPATIBLE_IOCTL(FDCLRPRM),
+COMPATIBLE_IOCTL(FDFMTBEG),
+COMPATIBLE_IOCTL(FDFMTEND),
+COMPATIBLE_IOCTL(FDRESET),
+COMPATIBLE_IOCTL(FDTWADDLE),
+COMPATIBLE_IOCTL(FDFMTTRK),
+COMPATIBLE_IOCTL(FDRAWCMD),
+/* 0x12 */
+COMPATIBLE_IOCTL(BLKROSET),
+COMPATIBLE_IOCTL(BLKROGET),
+COMPATIBLE_IOCTL(BLKRRPART),
+COMPATIBLE_IOCTL(BLKFLSBUF),
+COMPATIBLE_IOCTL(BLKRASET),
+COMPATIBLE_IOCTL(BLKFRASET),
+COMPATIBLE_IOCTL(BLKSECTSET),
+COMPATIBLE_IOCTL(BLKSSZGET),
+COMPATIBLE_IOCTL(BLKBSZGET),
+COMPATIBLE_IOCTL(BLKBSZSET),
+COMPATIBLE_IOCTL(BLKGETSIZE64),
+
+/* RAID */
+COMPATIBLE_IOCTL(RAID_VERSION),
+COMPATIBLE_IOCTL(GET_ARRAY_INFO),
+COMPATIBLE_IOCTL(GET_DISK_INFO),
+COMPATIBLE_IOCTL(PRINT_RAID_DEBUG),
+COMPATIBLE_IOCTL(CLEAR_ARRAY),
+COMPATIBLE_IOCTL(ADD_NEW_DISK),
+COMPATIBLE_IOCTL(HOT_REMOVE_DISK),
+COMPATIBLE_IOCTL(SET_ARRAY_INFO),
+COMPATIBLE_IOCTL(SET_DISK_INFO),
+COMPATIBLE_IOCTL(WRITE_RAID_INFO),
+COMPATIBLE_IOCTL(UNPROTECT_ARRAY),
+COMPATIBLE_IOCTL(PROTECT_ARRAY),
+COMPATIBLE_IOCTL(HOT_ADD_DISK),
+COMPATIBLE_IOCTL(SET_DISK_FAULTY),
+COMPATIBLE_IOCTL(RUN_ARRAY),
+COMPATIBLE_IOCTL(START_ARRAY),
+COMPATIBLE_IOCTL(STOP_ARRAY),
+COMPATIBLE_IOCTL(STOP_ARRAY_RO),
+COMPATIBLE_IOCTL(RESTART_ARRAY_RW),
+/* Big K */
+COMPATIBLE_IOCTL(PIO_FONT),
+COMPATIBLE_IOCTL(GIO_FONT),
+COMPATIBLE_IOCTL(KDSIGACCEPT),
+COMPATIBLE_IOCTL(KDGETKEYCODE),
+COMPATIBLE_IOCTL(KDSETKEYCODE),
+COMPATIBLE_IOCTL(KIOCSOUND),
+COMPATIBLE_IOCTL(KDMKTONE),
+COMPATIBLE_IOCTL(KDGKBTYPE),
+COMPATIBLE_IOCTL(KDSETMODE),
+COMPATIBLE_IOCTL(KDGETMODE),
+COMPATIBLE_IOCTL(KDSKBMODE),
+COMPATIBLE_IOCTL(KDGKBMODE),
+COMPATIBLE_IOCTL(KDSKBMETA),
+COMPATIBLE_IOCTL(KDGKBMETA),
+COMPATIBLE_IOCTL(KDGKBENT),
+COMPATIBLE_IOCTL(KDSKBENT),
+COMPATIBLE_IOCTL(KDGKBSENT),
+COMPATIBLE_IOCTL(KDSKBSENT),
+COMPATIBLE_IOCTL(KDGKBDIACR),
+COMPATIBLE_IOCTL(KDKBDREP),
+COMPATIBLE_IOCTL(KDSKBDIACR),
+COMPATIBLE_IOCTL(KDGKBLED),
+COMPATIBLE_IOCTL(KDSKBLED),
+COMPATIBLE_IOCTL(KDGETLED),
+COMPATIBLE_IOCTL(KDSETLED),
+COMPATIBLE_IOCTL(GIO_SCRNMAP),
+COMPATIBLE_IOCTL(PIO_SCRNMAP),
+COMPATIBLE_IOCTL(GIO_UNISCRNMAP),
+COMPATIBLE_IOCTL(PIO_UNISCRNMAP),
+COMPATIBLE_IOCTL(PIO_FONTRESET),
+COMPATIBLE_IOCTL(PIO_UNIMAPCLR),
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN),
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST),
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI),
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK),
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK),
+COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY),
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE),
+COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE),
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER),
+COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND),
+/* Big V */
+COMPATIBLE_IOCTL(VT_SETMODE),
+COMPATIBLE_IOCTL(VT_GETMODE),
+COMPATIBLE_IOCTL(VT_GETSTATE),
+COMPATIBLE_IOCTL(VT_OPENQRY),
+COMPATIBLE_IOCTL(VT_ACTIVATE),
+COMPATIBLE_IOCTL(VT_WAITACTIVE),
+COMPATIBLE_IOCTL(VT_RELDISP),
+COMPATIBLE_IOCTL(VT_DISALLOCATE),
+COMPATIBLE_IOCTL(VT_RESIZE),
+COMPATIBLE_IOCTL(VT_RESIZEX),
+COMPATIBLE_IOCTL(VT_LOCKSWITCH),
+COMPATIBLE_IOCTL(VT_UNLOCKSWITCH),
+/* Little v, the video4linux ioctls */
+COMPATIBLE_IOCTL(VIDIOCGCAP),
+COMPATIBLE_IOCTL(VIDIOCGCHAN),
+COMPATIBLE_IOCTL(VIDIOCSCHAN),
+COMPATIBLE_IOCTL(VIDIOCGPICT),
+COMPATIBLE_IOCTL(VIDIOCSPICT),
+COMPATIBLE_IOCTL(VIDIOCCAPTURE),
+COMPATIBLE_IOCTL(VIDIOCKEY),
+COMPATIBLE_IOCTL(VIDIOCGAUDIO),
+COMPATIBLE_IOCTL(VIDIOCSAUDIO),
+COMPATIBLE_IOCTL(VIDIOCSYNC),
+COMPATIBLE_IOCTL(VIDIOCMCAPTURE),
+COMPATIBLE_IOCTL(VIDIOCGMBUF),
+COMPATIBLE_IOCTL(VIDIOCGUNIT),
+COMPATIBLE_IOCTL(VIDIOCGCAPTURE),
+COMPATIBLE_IOCTL(VIDIOCSCAPTURE),
+/* BTTV specific... */
+COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256])),
+COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256])),
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)),
+COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])), /* struct bttv_pll_info */
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int)),
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int)),
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)),
+COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)),
+/* Little p (/dev/rtc, /dev/envctrl, etc.) */
+COMPATIBLE_IOCTL(_IOR('p', 20, int[7])), /* RTCGET */
+COMPATIBLE_IOCTL(_IOW('p', 21, int[7])), /* RTCSET */
+COMPATIBLE_IOCTL(RTC_AIE_ON),
+COMPATIBLE_IOCTL(RTC_AIE_OFF),
+COMPATIBLE_IOCTL(RTC_UIE_ON),
+COMPATIBLE_IOCTL(RTC_UIE_OFF),
+COMPATIBLE_IOCTL(RTC_PIE_ON),
+COMPATIBLE_IOCTL(RTC_PIE_OFF),
+COMPATIBLE_IOCTL(RTC_WIE_ON),
+COMPATIBLE_IOCTL(RTC_WIE_OFF),
+COMPATIBLE_IOCTL(RTC_ALM_SET),
+COMPATIBLE_IOCTL(RTC_ALM_READ),
+COMPATIBLE_IOCTL(RTC_RD_TIME),
+COMPATIBLE_IOCTL(RTC_SET_TIME),
+COMPATIBLE_IOCTL(RTC_WKALM_SET),
+COMPATIBLE_IOCTL(RTC_WKALM_RD),
+/* Little m */
+COMPATIBLE_IOCTL(MTIOCTOP),
+/* Socket level stuff */
+COMPATIBLE_IOCTL(FIOSETOWN),
+COMPATIBLE_IOCTL(SIOCSPGRP),
+COMPATIBLE_IOCTL(FIOGETOWN),
+COMPATIBLE_IOCTL(SIOCGPGRP),
+COMPATIBLE_IOCTL(SIOCATMARK),
+COMPATIBLE_IOCTL(SIOCSIFLINK),
+COMPATIBLE_IOCTL(SIOCSIFENCAP),
+COMPATIBLE_IOCTL(SIOCGIFENCAP),
+COMPATIBLE_IOCTL(SIOCSIFBR),
+COMPATIBLE_IOCTL(SIOCGIFBR),
+COMPATIBLE_IOCTL(SIOCSARP),
+COMPATIBLE_IOCTL(SIOCGARP),
+COMPATIBLE_IOCTL(SIOCDARP),
+COMPATIBLE_IOCTL(SIOCSRARP),
+COMPATIBLE_IOCTL(SIOCGRARP),
+COMPATIBLE_IOCTL(SIOCDRARP),
+COMPATIBLE_IOCTL(SIOCADDDLCI),
+COMPATIBLE_IOCTL(SIOCDELDLCI),
+/* SG stuff */
+COMPATIBLE_IOCTL(SG_SET_TIMEOUT),
+COMPATIBLE_IOCTL(SG_GET_TIMEOUT),
+COMPATIBLE_IOCTL(SG_EMULATED_HOST),
+COMPATIBLE_IOCTL(SG_SET_TRANSFORM),
+COMPATIBLE_IOCTL(SG_GET_TRANSFORM),
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE),
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE),
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID),
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA),
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA),
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID),
+COMPATIBLE_IOCTL(SG_GET_PACK_ID),
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING),
+COMPATIBLE_IOCTL(SG_SET_DEBUG),
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE),
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q),
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q),
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM),
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN),
+COMPATIBLE_IOCTL(SG_SCSI_RESET),
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE),
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN),
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN),
+/* PPP stuff */
+COMPATIBLE_IOCTL(PPPIOCGFLAGS),
+COMPATIBLE_IOCTL(PPPIOCSFLAGS),
+COMPATIBLE_IOCTL(PPPIOCGASYNCMAP),
+COMPATIBLE_IOCTL(PPPIOCSASYNCMAP),
+COMPATIBLE_IOCTL(PPPIOCGUNIT),
+COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP),
+COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP),
+COMPATIBLE_IOCTL(PPPIOCGMRU),
+COMPATIBLE_IOCTL(PPPIOCSMRU),
+COMPATIBLE_IOCTL(PPPIOCSMAXCID),
+COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP),
+COMPATIBLE_IOCTL(LPGETSTATUS),
+COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP),
+COMPATIBLE_IOCTL(PPPIOCXFERUNIT),
+COMPATIBLE_IOCTL(PPPIOCGNPMODE),
+COMPATIBLE_IOCTL(PPPIOCSNPMODE),
+COMPATIBLE_IOCTL(PPPIOCGDEBUG),
+COMPATIBLE_IOCTL(PPPIOCSDEBUG),
+COMPATIBLE_IOCTL(PPPIOCNEWUNIT),
+COMPATIBLE_IOCTL(PPPIOCATTACH),
+COMPATIBLE_IOCTL(PPPIOCDETACH),
+COMPATIBLE_IOCTL(PPPIOCSMRRU),
+COMPATIBLE_IOCTL(PPPIOCCONNECT),
+COMPATIBLE_IOCTL(PPPIOCDISCONN),
+COMPATIBLE_IOCTL(PPPIOCATTCHAN),
+COMPATIBLE_IOCTL(PPPIOCGCHAN),
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD),
+COMPATIBLE_IOCTL(PPPOEIOCDFWD),
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE),
+COMPATIBLE_IOCTL(CDROMRESUME),
+COMPATIBLE_IOCTL(CDROMPLAYMSF),
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND),
+COMPATIBLE_IOCTL(CDROMREADCOOKED),
+COMPATIBLE_IOCTL(CDROMREADMODE1),
+COMPATIBLE_IOCTL(CDROMREADMODE2),
+COMPATIBLE_IOCTL(CDROMREADRAW),
+COMPATIBLE_IOCTL(CDROMREADTOCHDR),
+COMPATIBLE_IOCTL(CDROMREADTOCENTRY),
+COMPATIBLE_IOCTL(CDROMSTOP),
+COMPATIBLE_IOCTL(CDROMSTART),
+COMPATIBLE_IOCTL(CDROMEJECT),
+COMPATIBLE_IOCTL(CDROMVOLCTRL),
+COMPATIBLE_IOCTL(CDROMSUBCHNL),
+COMPATIBLE_IOCTL(CDROMEJECT_SW),
+COMPATIBLE_IOCTL(CDROMMULTISESSION),
+COMPATIBLE_IOCTL(CDROM_GET_MCN),
+COMPATIBLE_IOCTL(CDROMRESET),
+COMPATIBLE_IOCTL(CDROMVOLREAD),
+COMPATIBLE_IOCTL(CDROMSEEK),
+COMPATIBLE_IOCTL(CDROMPLAYBLK),
+COMPATIBLE_IOCTL(CDROMCLOSETRAY),
+COMPATIBLE_IOCTL(CDROM_SET_OPTIONS),
+COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS),
+COMPATIBLE_IOCTL(CDROM_SELECT_SPEED),
+COMPATIBLE_IOCTL(CDROM_SELECT_DISC),
+COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED),
+COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS),
+COMPATIBLE_IOCTL(CDROM_DISC_STATUS),
+COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS),
+COMPATIBLE_IOCTL(CDROM_LOCKDOOR),
+COMPATIBLE_IOCTL(CDROM_DEBUG),
+COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY),
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT),
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT),
+COMPATIBLE_IOCTL(DVD_AUTH),
+/* Big L */
+COMPATIBLE_IOCTL(LOOP_SET_FD),
+COMPATIBLE_IOCTL(LOOP_CLR_FD),
+/* Big Q for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC),
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE),
+COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS),
+COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD),
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL),
+COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND),
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME),
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID),
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL),
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE),
+/* Big T for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE),
+COMPATIBLE_IOCTL(SNDCTL_TMR_START),
+COMPATIBLE_IOCTL(SNDCTL_TMR_STOP),
+COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE),
+COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO),
+COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE),
+COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME),
+COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT),
+/* Little m for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME),
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE),
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD),
+/* Big P for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_DSP_RESET),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED),
+COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE),
+COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS),
+COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER),
+COMPATIBLE_IOCTL(SNDCTL_DSP_POST),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE),
+COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR),
+/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
+/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO),
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX),
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY),
+COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE),
+COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE),
+COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS),
+COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS),
+COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER),
+/* Big C for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_COPR_RESET),
+COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD),
+COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA),
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE),
+COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA),
+COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE),
+COMPATIBLE_IOCTL(SNDCTL_COPR_RUN),
+COMPATIBLE_IOCTL(SNDCTL_COPR_HALT),
+COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG),
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG),
+/* Big M for sound/OSS */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO)),
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR)),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE),
+/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
+/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS),
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO)),
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR)),
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE),
+/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
+/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC),
+COMPATIBLE_IOCTL(SOUND_MIXER_INFO),
+COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO),
+COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS),
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1),
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2),
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3),
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4),
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5),
+COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS),
+COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS),
+COMPATIBLE_IOCTL(OSS_GETVERSION),
+/* AUTOFS */
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY),
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL),
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC),
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER),
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE),
+/* DEVFS */
+COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV),
+COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK),
+COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE),
+COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK),
+/* Raw devices */
+COMPATIBLE_IOCTL(RAW_SETBIND),
+COMPATIBLE_IOCTL(RAW_GETBIND),
+/* SMB ioctls which do not need any translations */
+COMPATIBLE_IOCTL(SMB_IOC_NEWCONN),
+/* Little a */
+COMPATIBLE_IOCTL(ATMSIGD_CTRL),
+COMPATIBLE_IOCTL(ATMARPD_CTRL),
+COMPATIBLE_IOCTL(ATMLEC_CTRL),
+COMPATIBLE_IOCTL(ATMLEC_MCAST),
+COMPATIBLE_IOCTL(ATMLEC_DATA),
+COMPATIBLE_IOCTL(ATM_SETSC),
+COMPATIBLE_IOCTL(SIOCSIFATMTCP),
+COMPATIBLE_IOCTL(SIOCMKCLIP),
+COMPATIBLE_IOCTL(ATMARP_MKIP),
+COMPATIBLE_IOCTL(ATMARP_SETENTRY),
+COMPATIBLE_IOCTL(ATMARP_ENCAP),
+COMPATIBLE_IOCTL(ATMTCP_CREATE),
+COMPATIBLE_IOCTL(ATMTCP_REMOVE),
+COMPATIBLE_IOCTL(ATMMPC_CTRL),
+COMPATIBLE_IOCTL(ATMMPC_DATA),
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* 0xfe - lvm */
+COMPATIBLE_IOCTL(VG_SET_EXTENDABLE),
+COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT),
+COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST),
+COMPATIBLE_IOCTL(VG_REMOVE),
+COMPATIBLE_IOCTL(VG_RENAME),
+COMPATIBLE_IOCTL(VG_REDUCE),
+COMPATIBLE_IOCTL(PE_LOCK_UNLOCK),
+COMPATIBLE_IOCTL(PV_FLUSH),
+COMPATIBLE_IOCTL(LVM_LOCK_LVM),
+COMPATIBLE_IOCTL(LVM_GET_IOP_VERSION),
+#ifdef LVM_TOTAL_RESET
+COMPATIBLE_IOCTL(LVM_RESET),
+#endif
+COMPATIBLE_IOCTL(LV_SET_ACCESS),
+COMPATIBLE_IOCTL(LV_SET_STATUS),
+COMPATIBLE_IOCTL(LV_SET_ALLOCATION),
+COMPATIBLE_IOCTL(LE_REMAP),
+COMPATIBLE_IOCTL(LV_BMAP),
+COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE),
+#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC),
+COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID),
+COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC),
+COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK),
+COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK),
+COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL),
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS),
+COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS),
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX),
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX),
+COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX),
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX),
+COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX),
+COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX),
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW),
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW),
+COMPATIBLE_IOCTL(DRM_IOCTL_LOCK),
+COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK),
+COMPATIBLE_IOCTL(DRM_IOCTL_FINISH),
+#endif /* DRM */
+/* elevator */
+COMPATIBLE_IOCTL(BLKELVGET),
+COMPATIBLE_IOCTL(BLKELVSET),
+/* Big W */
+/* WIOC_GETSUPPORT not yet implemented -E */
+COMPATIBLE_IOCTL(WDIOC_GETSTATUS),
+COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS),
+COMPATIBLE_IOCTL(WDIOC_GETTEMP),
+COMPATIBLE_IOCTL(WDIOC_SETOPTIONS),
+COMPATIBLE_IOCTL(WDIOC_KEEPALIVE),
+/* Bluetooth ioctls */
+COMPATIBLE_IOCTL(HCIDEVUP),
+COMPATIBLE_IOCTL(HCIDEVDOWN),
+COMPATIBLE_IOCTL(HCIDEVRESET),
+COMPATIBLE_IOCTL(HCIRESETSTAT),
+COMPATIBLE_IOCTL(HCIGETINFO),
+COMPATIBLE_IOCTL(HCIGETDEVLIST),
+COMPATIBLE_IOCTL(HCISETRAW),
+COMPATIBLE_IOCTL(HCISETSCAN),
+COMPATIBLE_IOCTL(HCISETAUTH),
+COMPATIBLE_IOCTL(HCIINQUIRY),
+COMPATIBLE_IOCTL(PCIIOC_CONTROLLER),
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO),
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM),
+COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE),
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP),
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE),
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION),
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER),
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB),
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE),
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE),
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO),
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO),
+COMPATIBLE_IOCTL(USBDEVFS_RESET),
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT),
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO),
+COMPATIBLE_IOCTL(MEMERASE),
+COMPATIBLE_IOCTL(MEMLOCK),
+COMPATIBLE_IOCTL(MEMUNLOCK),
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT),
+COMPATIBLE_IOCTL(MEMGETREGIONINFO),
+/* NBD */
+COMPATIBLE_IOCTL(NBD_SET_SOCK),
+COMPATIBLE_IOCTL(NBD_SET_BLKSIZE),
+COMPATIBLE_IOCTL(NBD_SET_SIZE),
+COMPATIBLE_IOCTL(NBD_DO_IT),
+COMPATIBLE_IOCTL(NBD_CLEAR_SOCK),
+COMPATIBLE_IOCTL(NBD_CLEAR_QUE),
+COMPATIBLE_IOCTL(NBD_PRINT_DEBUG),
+COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS),
+COMPATIBLE_IOCTL(NBD_DISCONNECT),
+/* Remove *PRIVATE in 2.5 */
+COMPATIBLE_IOCTL(SIOCDEVPRIVATE),
+COMPATIBLE_IOCTL(SIOCDEVPRIVATE+1),
+COMPATIBLE_IOCTL(SIOCDEVPRIVATE+2),
+COMPATIBLE_IOCTL(SIOCGMIIPHY),
+COMPATIBLE_IOCTL(SIOCGMIIREG),
+COMPATIBLE_IOCTL(SIOCSMIIREG),
+/* And these ioctls need translation */
+HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob),
+HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob),
+#ifdef CONFIG_NET
+HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32),
+#endif
+HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf),
+HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc),
+HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc),
+HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc),
+HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc),
+HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl),
+HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl),
+HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl),
+HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl),
+HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl),
+HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl),
+HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl),
+HANDLE_IOCTL(SIOCADDRT, routing_ioctl),
+HANDLE_IOCTL(SIOCDELRT, routing_ioctl),
+/* Note SIOCRTMSG is no longer, so this is safe and
+ * the user would have seen just an -EINVAL anyways. */
+HANDLE_IOCTL(SIOCRTMSG, ret_einval),
+HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp),
+HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo),
+HANDLE_IOCTL(BLKRAGET, w_long),
+HANDLE_IOCTL(BLKGETSIZE, w_long),
+HANDLE_IOCTL(0x1260, broken_blkgetsize),
+HANDLE_IOCTL(BLKFRAGET, w_long),
+HANDLE_IOCTL(BLKSECTGET, w_long),
+HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans),
+HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans),
+HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans),
+HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans),
+HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans),
+HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans),
+HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans),
+HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans),
+HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans),
+HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans),
+HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans),
+HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans),
+HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans),
+HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans),
+HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans),
+HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans),
+HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans),
+HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans),
+HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans),
+HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans),
+HANDLE_IOCTL(LOOP_SET_STATUS, loop_status),
+HANDLE_IOCTL(LOOP_GET_STATUS, loop_status),
+HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout),
+#ifdef CONFIG_VT
+HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl),
+HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl),
+HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl),
+HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl),
+HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl),
+HANDLE_IOCTL(FBIOGET_FSCREENINFO, do_fbioget_fscreeninfo_ioctl),
+HANDLE_IOCTL(FBIOGETCMAP, do_fbiogetcmap_ioctl),
+HANDLE_IOCTL(FBIOPUTCMAP, do_fbioputcmap_ioctl),
+#endif
+HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
+HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
+HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
+HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl),
+HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl),
+HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl),
+/* One SMB ioctl needs translations. */
+HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid),
+HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl),
+HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl),
+HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl),
+HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl),
+HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl),
+HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl),
+HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl),
+HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl),
+HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl),
+HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl),
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl),
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl),
+HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl),
+HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl),
+HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl),
+HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl),
+HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl),
+HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl),
+HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl),
+HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl),
+HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl),
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl),
+HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl),
+HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl),
+#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version),
+HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique),
+HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique),
+HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap),
+HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs),
+HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs),
+HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs),
+HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma),
+HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx),
+#endif /* DRM */
+HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control),
+HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk),
+/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
+HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
+HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
+HANDLE_IOCTL(SG_IO, do_sg_io),
+};
+
+unsigned long ioctl32_hash_table[1024];
+
+static inline unsigned long ioctl32_hash(unsigned long cmd)
+{
+	return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
+}
+
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
+{
+	unsigned long hash;
+	struct ioctl_trans *t;
+
+	hash = ioctl32_hash (trans->cmd);
+	if (!ioctl32_hash_table[hash])
+		ioctl32_hash_table[hash] = (long)trans;
+	else {
+		t = (struct ioctl_trans *)ioctl32_hash_table[hash];
+		while (t->next)
+			t = (struct ioctl_trans *)(long)t->next;
+		trans->next = 0;
+		t->next = (long)trans;
+	}
+}
+
+static int __init init_sys32_ioctl(void)
+{
+        int i, size = sizeof(ioctl_translations) / sizeof(struct ioctl_trans);
+        for (i=0; i < size ;i++)
+                ioctl32_insert_translation(&ioctl_translations[i]);
+	return 0;
+}
+
+__initcall(init_sys32_ioctl);
+
+static struct ioctl_trans *additional_ioctls;
+
+/* Always call these with kernel lock held! */
+
+int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
+{
+	int i;
+	if (!additional_ioctls) {
+		additional_ioctls = module_map(PAGE_SIZE);
+		if (!additional_ioctls)
+			return -ENOMEM;
+		memset(additional_ioctls, 0, PAGE_SIZE);
+	}
+	for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++)
+		if (!additional_ioctls[i].cmd)
+			break;
+	if (i == PAGE_SIZE/sizeof(struct ioctl_trans))
+		return -ENOMEM;
+	additional_ioctls[i].cmd = cmd;
+	if (!handler)
+		additional_ioctls[i].handler = (long)sys_ioctl;
+	else
+		additional_ioctls[i].handler = (long)handler;
+	ioctl32_insert_translation(&additional_ioctls[i]);
+	return 0;
+}
+
+int unregister_ioctl32_conversion(unsigned int cmd)
+{
+	unsigned long hash = ioctl32_hash(cmd);
+	struct ioctl_trans *t, *t1;
+
+	t = (struct ioctl_trans *)ioctl32_hash_table[hash];
+	if (!t) return -EINVAL;
+	if (t->cmd == cmd && t >= additional_ioctls &&
+	    (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+		ioctl32_hash_table[hash] = t->next;
+		t->cmd = 0;
+		return 0;
+	} else while (t->next) {
+		t1 = (struct ioctl_trans *)t->next;
+		if (t1->cmd == cmd && t1 >= additional_ioctls &&
+		    (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+			t1->cmd = 0;
+			t->next = t1->next;
+			return 0;
+		}
+		t = t1;
+	}
+	return -EINVAL;
+}
+
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct file * filp;
+	int error = -EBADF;
+	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	struct ioctl_trans *t;
+
+	filp = fget(fd);
+	if (!filp)
+		goto out2;
+
+	if (!filp->f_op || !filp->f_op->ioctl) {
+		error = sys_ioctl (fd, cmd, arg);
+		goto out;
+	}
+
+	t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)];
+
+	while (t && t->cmd != cmd)
+		t = (struct ioctl_trans *)t->next;
+	if (t) {
+		handler = (void *)t->handler;
+		error = handler(fd, cmd, arg, filp);
+	} else {
+		static int count = 0;
+		if (++count <= 20)
+			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
+			       "cmd(%08x) arg(%08x)\n",
+			       current->comm, current->pid,
+			       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		error = -EINVAL;
+	}
+out:
+	fput(filp);
+out2:
+	return error;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/irq.c linux-2.4.19-pre5/arch/ppc64/kernel/irq.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/irq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/irq.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,972 @@
+/*
+ * 
+ *
+ *  arch/ppc/kernel/irq.c
+ *
+ *  Derived from arch/i386/kernel/irq.c
+ *    Copyright (C) 1992 Linus Torvalds
+ *  Adapted from arch/i386 by Gary Thomas
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Cort Dougan
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ * 
+ * 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 file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/threads.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <linux/random.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/cache.h>
+#include <asm/prom.h>
+#include <asm/ptrace.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/machdep.h>
+
+#include "local_irq.h"
+
+atomic_t ipi_recv;
+atomic_t ipi_sent;
+void enable_irq(unsigned int irq_nr);
+void disable_irq(unsigned int irq_nr);
+
+#ifdef CONFIG_SMP
+extern void iSeries_smp_message_recv( struct pt_regs * );
+#endif
+
+volatile unsigned char *chrp_int_ack_special;
+static void register_irq_proc (unsigned int irq);
+
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+	{ [0 ... NR_IRQS-1] = { 0, NULL, NULL, 0, SPIN_LOCK_UNLOCKED}};
+	
+int ppc_spurious_interrupts = 0;
+struct irqaction *ppc_irq_action[NR_IRQS];
+unsigned long lpEvent_count = 0;
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *regs);
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern int xmon_dabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
+#ifdef CONFIG_XMON
+extern void (*debugger)(struct pt_regs *regs);
+extern int (*debugger_bpt)(struct pt_regs *regs);
+extern int (*debugger_sstep)(struct pt_regs *regs);
+extern int (*debugger_iabr_match)(struct pt_regs *regs);
+extern int (*debugger_dabr_match)(struct pt_regs *regs);
+extern void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif
+
+/* 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.
+ * this needs to be removed.
+ * -- Cort
+ */
+#define IRQ_KMALLOC_ENTRIES 8
+static int cache_bitmask = 0;
+static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES];
+extern int mem_init_done;
+
+void *irq_kmalloc(size_t size, int pri)
+{
+	unsigned int i;
+	if ( mem_init_done )
+		return kmalloc(size,pri);
+	for ( i = 0; i < IRQ_KMALLOC_ENTRIES ; i++ )
+		if ( ! ( cache_bitmask & (1<<i) ) ) {
+			cache_bitmask |= (1<<i);
+			return (void *)(&malloc_cache[i]);
+		}
+	return 0;
+}
+
+void irq_kfree(void *ptr)
+{
+	unsigned int i;
+	for ( i = 0 ; i < IRQ_KMALLOC_ENTRIES ; i++ )
+		if ( ptr == &malloc_cache[i] ) {
+			cache_bitmask &= ~(1<<i);
+			return;
+		}
+	kfree(ptr);
+}
+
+int
+setup_irq(unsigned int irq, struct irqaction * new)
+{
+	int shared = 0;
+	unsigned long flags;
+	struct irqaction *old, **p;
+	irq_desc_t *desc = irq_desc + irq;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+		rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&desc->lock,flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+		desc->depth = 0;
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+		unmask_irq(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	register_irq_proc(irq);
+	return 0;
+}
+
+/* This could be promoted to a real free_irq() ... */
+static int
+do_free_irq(int irq, void* dev_id)
+{
+	irq_desc_t *desc;
+	struct irqaction **p;
+	unsigned long flags;
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != dev_id)
+				continue;
+
+			/* Found it - now remove it from the list of entries */
+			*pp = action->next;
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				mask_irq(irq);
+			}
+			spin_unlock_irqrestore(&desc->lock,flags);
+
+#ifdef CONFIG_SMP
+			/* Wait to make sure it's not being used on another CPU */
+			while (desc->status & IRQ_INPROGRESS)
+				barrier();
+#endif
+			irq_kfree(action);
+			return 0;
+		}
+		printk("Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		break;
+	}
+	return -ENOENT;
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+	unsigned long irqflags, const char * devname, void *dev_id)
+{
+	struct irqaction *action;
+	int retval;
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+	if (!handler)
+		/* We could implement really free_irq() instead of that... */
+		return do_free_irq(irq, dev_id);
+	
+	action = (struct irqaction *)
+		irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action) {
+		printk(KERN_ERR "irq_kmalloc() failed for irq %d !\n", irq);
+		return -ENOMEM;
+	}
+	
+	action->handler = handler;
+	action->flags = irqflags;					
+	action->mask = 0;
+	action->name = devname;
+	action->dev_id = dev_id;
+	action->next = NULL;
+	
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+		
+	return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+	request_irq(irq, NULL, 0, NULL, dev_id);
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock. 
+ */
+ 
+/**
+ *	disable_irq_nosync - disable an irq without waiting
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+ void disable_irq_nosync(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	if (!desc->depth++) {
+		if (!(desc->status & IRQ_PER_CPU))
+			desc->status |= IRQ_DISABLED;
+		mask_irq(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. That is for two disables you need two enables. This
+ *	function waits for any pending IRQ handlers for this interrupt
+ *	to complete before returning. If you use this function while
+ *	holding a resource the IRQ handler may need you will deadlock.
+ *
+ *	This function may be called - with care - from IRQ context.
+ */
+ 
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+
+	if (!local_irq_count(smp_processor_id())) {
+		do {
+			barrier();
+		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+	}
+}
+
+/**
+ *	enable_irq - enable interrupt handling on an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Re-enables the processing of interrupts on this IRQ line
+ *	providing no disable_irq calls are now in effect.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void enable_irq(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	switch (desc->depth) {
+	case 1: {
+		unsigned int status = desc->status & ~IRQ_DISABLED;
+		desc->status = status;
+		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+			desc->status = status | IRQ_REPLAY;
+			hw_resend_irq(desc->handler,irq);
+		}
+		unmask_irq(irq);
+		/* fall-through */
+	}
+	default:
+		desc->depth--;
+		break;
+	case 0:
+		printk("enable_irq(%u) unbalanced\n", irq);
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/* one would think this function has one foot in the grave */
+int get_irq_list(char *buf)
+{
+   int i, len = 0, j;
+   struct irqaction * action;
+
+   len += sprintf(buf+len, "           ");
+   for (j=0; j<smp_num_cpus; j++)
+       len += sprintf(buf+len, "CPU%d       ",j);
+   *(char *)(buf+len++) = '\n';
+
+   for (i = 0 ; i < NR_IRQS ; i++) {
+       action = irq_desc[i].action;
+       if ( !action || !action->handler )
+           continue;
+       len += sprintf(buf+len, "%3d: ", i);
+#ifdef CONFIG_SMP
+       for (j = 0; j < smp_num_cpus; j++)
+           len += sprintf(buf+len, "%10u ",
+               kstat.irqs[cpu_logical_map(j)][i]);
+#else
+       len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+#endif /* CONFIG_SMP */
+if ( irq_desc[i].handler )
+len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
+else
+len += sprintf(buf+len, "  None      ");
+len += sprintf(buf+len, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge  ");
+len += sprintf(buf+len, "    %s",action->name);
+for (action=action->next; action; action = action->next) {
+len += sprintf(buf+len, ", %s", action->name);
+}
+len += sprintf(buf+len, "\n");
+}
+#ifdef CONFIG_SMP
+/* should this be per processor send/receive? */
+len += sprintf(buf+len, "IPI (recv/sent): %10u/%u\n",
+atomic_read(&ipi_recv), atomic_read(&ipi_sent));
+#endif
+len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
+return len;
+}
+
+
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i, j;
+	struct irqaction * action;
+
+	seq_printf(p, "           ");
+	for (j=0; j<smp_num_cpus; j++)
+		seq_printf(p, "CPU%d       ",j);
+	seq_putc(p, '\n');
+
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = irq_desc[i].action;
+		if (!action || !action->handler)
+			continue;
+		seq_printf(p, "%3d: ", i);		
+#ifdef CONFIG_SMP
+		for (j = 0; j < smp_num_cpus; j++)
+			seq_printf(p, "%10u ",
+				kstat.irqs[cpu_logical_map(j)][i]);
+#else		
+		seq_printf(p, "%10u ", kstat_irqs(i));
+#endif /* CONFIG_SMP */
+		if (irq_desc[i].handler)		
+			seq_printf(p, " %s ", irq_desc[i].handler->typename );
+		else
+			seq_printf(p, "  None      ");
+		seq_printf(p, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge  ");
+		seq_printf(p, "    %s",action->name);
+		for (action=action->next; action; action = action->next)
+			seq_printf(p, ", %s", action->name);
+		seq_putc(p, '\n');
+	}
+#ifdef CONFIG_SMP
+	/* should this be per processor send/receive? */
+	seq_printf(p, "IPI (recv/sent): %10u/%u\n",
+		       atomic_read(&ipi_recv), atomic_read(&ipi_sent));
+#endif		
+	seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);
+	return 0;
+}
+
+static inline void
+handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action)
+{
+	int status = 0;
+
+	if (!(action->flags & SA_INTERRUPT))
+		__sti();
+
+	do {
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	__cli();
+}
+
+/*
+ * 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;
+	int cpu = smp_processor_id();
+	irq_desc_t *desc = irq_desc + irq;
+
+	kstat.irqs[cpu][irq]++;
+	spin_lock(&desc->lock);
+	ack_irq(irq);	
+	/*
+	   REPLAY is when Linux resends an IRQ that was dropped earlier
+	   WAITING is used by probe to mark irqs that are being tested
+	   */
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+	if (!(status & IRQ_PER_CPU))
+		status |= IRQ_PENDING; /* we _want_ to handle it */
+
+	/*
+	 * If the IRQ is disabled for whatever reason, we cannot
+	 * use the action we have.
+	 */
+	action = NULL;
+	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		if (!action || !action->handler) {
+			ppc_spurious_interrupts++;
+			printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq);
+			/* We can't call disable_irq here, it would deadlock */
+			if (!desc->depth)
+				desc->depth = 1;
+			desc->status |= IRQ_DISABLED;
+			/* This is not a real spurrious interrupt, we
+			 * have to eoi it, so we jump to out
+			 */
+			mask_irq(irq);
+			goto out;
+		}
+		status &= ~IRQ_PENDING; /* we commit to handling */
+		if (!(status & IRQ_PER_CPU))
+			status |= IRQ_INPROGRESS; /* we are handling it */
+	}
+	desc->status = status;
+
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	   Since we set PENDING, if another processor is handling
+	   a different instance of this same irq, the other processor
+	   will take care of it.
+	 */
+	if (!action)
+		goto out;
+
+
+	/*
+	 * Edge triggered interrupts need to remember
+	 * pending events.
+	 * This applies to any hw interrupts that allow a second
+	 * instance of the same irq to arrive while we are in do_IRQ
+	 * or in the handler. But the code here only handles the _second_
+	 * instance of the irq, not the third or fourth. So it is mostly
+	 * useful for irq hardware that does not mask cleanly in an
+	 * SMP environment.
+	 */
+	for (;;) {
+		spin_unlock(&desc->lock);
+		handle_irq_event(irq, regs, action);
+		spin_lock(&desc->lock);
+		
+		if (!(desc->status & IRQ_PENDING))
+			break;
+		desc->status &= ~IRQ_PENDING;
+	}
+	desc->status &= ~IRQ_INPROGRESS;
+out:
+	/*
+	 * The ->end() handler has to deal with interrupts which got
+	 * disabled while the handler was running.
+	 */
+	if (irq_desc[irq].handler) {
+		if (irq_desc[irq].handler->end)
+			irq_desc[irq].handler->end(irq);
+		else if (irq_desc[irq].handler->enable)
+			irq_desc[irq].handler->enable(irq);
+	}
+	spin_unlock(&desc->lock);
+}
+
+int do_IRQ(struct pt_regs *regs, int isfake)
+{
+	int cpu = smp_processor_id();
+	int irq;
+	struct Paca * paca;
+	struct ItLpQueue * lpq;
+
+	/* if(cpu) udbg_printf("Entering do_IRQ\n");  */
+
+        irq_enter(cpu);
+
+	if ( _machine != _MACH_iSeries ) {
+	
+		/* every arch is required to have a get_irq -- Cort */
+		irq = ppc_md.get_irq( regs );
+
+		if ( irq >= 0 ) {
+			ppc_irq_dispatch_handler( regs, irq );
+			if (ppc_md.post_irq)
+				ppc_md.post_irq( regs, irq );
+		} else {
+			/* -2 means ignore, already handled */
+			if (irq != -2) {
+				printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+					irq, regs->nip);
+				ppc_spurious_interrupts++;
+			}
+		}
+	}
+	/* if on iSeries partition */
+	else {
+		paca = (struct Paca *)mfspr(SPRG3);
+#ifdef CONFIG_SMP
+		if ( paca->xLpPaca.xIntDword.xFields.xIpiCnt ) {
+			paca->xLpPaca.xIntDword.xFields.xIpiCnt = 0;
+			iSeries_smp_message_recv( regs );
+		}
+#endif /* CONFIG_SMP */
+		lpq = paca->lpQueuePtr;
+		if ( lpq && ItLpQueue_isLpIntPending( lpq ) )
+			lpEvent_count += ItLpQueue_process( lpq, regs );
+	}
+		
+        irq_exit(cpu);
+
+	if ( _machine == _MACH_iSeries ) {
+		if ( paca->xLpPaca.xIntDword.xFields.xDecrInt ) {
+			paca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+			/* Signal a fake decrementer interrupt */
+			timer_interrupt( regs );
+		}
+	}
+
+	if (softirq_pending(cpu))
+		do_softirq();
+
+	return 1; /* lets ret_from_int know we can do checks */
+}
+
+unsigned long probe_irq_on (void)
+{
+	return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+	return 0;
+}
+
+unsigned int probe_irq_mask(unsigned long irqs)
+{
+	return 0;
+}
+
+void __init init_IRQ(void)
+{
+	static int once = 0;
+
+	if ( once )
+		return;
+	else
+		once++;
+	
+	ppc_md.init_IRQ();
+	if(ppc_md.init_ras_IRQ) ppc_md.init_ras_IRQ(); 
+}
+
+#ifdef CONFIG_SMP
+unsigned char global_irq_holder = NO_PROC_ID;
+
+static void show(char * str)
+{
+	int cpu = smp_processor_id();
+	int i;
+
+	printk("\n%s, CPU %d:\n", str, cpu);
+	printk("irq:  %d [ ", irqs_running());
+	for (i = 0; i < smp_num_cpus; i++)
+		printk("%u ", __brlock_array[i][BR_GLOBALIRQ_LOCK]);
+	printk("]\nbh:   %d [ ",
+		(spin_is_locked(&global_bh_lock) ? 1 : 0));
+	for (i = 0; i < smp_num_cpus; i++)
+		printk("%u ", local_bh_count(i));
+	printk("]\n");
+}
+
+#define MAXCOUNT 10000000
+
+void synchronize_irq(void)
+{
+	if (irqs_running()) {
+		cli();
+		sti();
+	}
+}
+
+static inline void get_irqlock(int cpu)
+{
+        int count;
+
+        if ((unsigned char)cpu == global_irq_holder)
+                return;
+
+        count = MAXCOUNT;
+again:
+        br_write_lock(BR_GLOBALIRQ_LOCK);
+        for (;;) {
+                spinlock_t *lock;
+
+                if (!irqs_running() &&
+                    (local_bh_count(smp_processor_id()) || !spin_is_locked(&global_bh_lock)))
+                        break;
+
+                br_write_unlock(BR_GLOBALIRQ_LOCK);
+                lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock;
+                while (irqs_running() ||
+                       spin_is_locked(lock) ||
+                       (!local_bh_count(smp_processor_id()) && spin_is_locked(&global_bh_lock))) {
+                        if (!--count) {
+                                show("get_irqlock");
+                                count = (~0 >> 1);
+                        }
+                        __sti();
+                        barrier();
+                        __cli();
+                }
+                goto again;
+        }
+
+        global_irq_holder = cpu;
+}
+
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
+void __global_cli(void)
+{
+	unsigned long flags;
+	
+	__save_flags(flags);
+	if (flags & (1UL << 15)) {
+		int cpu = smp_processor_id();
+		__cli();
+		if (!local_irq_count(cpu))
+			get_irqlock(cpu);
+	}
+}
+
+void __global_sti(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!local_irq_count(cpu))
+		release_irqlock(cpu);
+	__sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+	int retval;
+	int local_enabled;
+	unsigned long flags;
+
+	__save_flags(flags);
+	local_enabled = (flags >> 15) & 1;
+	/* default to local */
+	retval = 2 + local_enabled;
+
+	/* check for global flags if we're not in an interrupt */
+	if (!local_irq_count(smp_processor_id())) {
+		if (local_enabled)
+			retval = 1;
+		if (global_irq_holder == (unsigned char) smp_processor_id())
+			retval = 0;
+	}
+	return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+	switch (flags) {
+	case 0:
+		__global_cli();
+		break;
+	case 1:
+		__global_sti();
+		break;
+	case 2:
+		__cli();
+		break;
+	case 3:
+		__sti();
+		break;
+	default:
+		printk("global_restore_flags: %016lx caller %p\n",
+			flags, __builtin_return_address(0));
+	}
+}
+
+#endif /* CONFIG_SMP */
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+#ifdef CONFIG_IRQ_ALL_CPUS
+unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff};
+#else  /* CONFIG_IRQ_ALL_CPUS */
+unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0x00000000};
+#endif /* CONFIG_IRQ_ALL_CPUS */
+
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08x\n", irq_affinity[(int)(long)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+		unsigned long count, unsigned long *ret)
+{
+	unsigned char hexnum [HEX_DIGITS];
+	unsigned long value;
+	int i;
+
+	if (!count)
+		return -EINVAL;
+	if (count > HEX_DIGITS)
+		count = HEX_DIGITS;
+	if (copy_from_user(hexnum, buffer, count))
+		return -EFAULT;
+
+	/*
+	 * Parse the first 8 characters as a hex string, any non-hex char
+	 * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+	 */
+	value = 0;
+
+	for (i = 0; i < count; i++) {
+		unsigned int c = hexnum[i];
+
+		switch (c) {
+			case '0' ... '9': c -= '0'; break;
+			case 'a' ... 'f': c -= 'a'-10; break;
+			case 'A' ... 'F': c -= 'A'-10; break;
+		default:
+			goto out;
+		}
+		value = (value << 4) | c;
+	}
+out:
+	*ret = value;
+	return 0;
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	int irq = (int)(long) data, full_count = count, err;
+	unsigned long new_value;
+
+	if (!irq_desc[irq].handler->set_affinity)
+		return -EIO;
+
+	err = parse_hex_value(buffer, count, &new_value);
+
+/* Why is this disabled ? --BenH */
+#if 0/*CONFIG_SMP*/
+	/*
+	 * Do not allow disabling IRQs completely - it's a too easy
+	 * way to make the system unusable accidentally :-) At least
+	 * one online CPU still has to be targeted.
+	 */
+	if (!(new_value & cpu_online_map))
+		return -EINVAL;
+#endif
+
+	irq_affinity[irq] = new_value;
+	irq_desc[irq].handler->set_affinity(irq, new_value);
+
+	return full_count;
+}
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	unsigned long *mask = (unsigned long *) data;
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	unsigned long *mask = (unsigned long *) data, full_count = count, err;
+	unsigned long new_value;
+
+	err = parse_hex_value(buffer, count, &new_value);
+	if (err)
+		return err;
+
+	*mask = new_value;
+
+#ifdef CONFIG_PPC_ISERIES
+	{
+		unsigned i;
+		for (i=0; i<maxPacas; ++i) {
+			if ( xPaca[i].prof_buffer && (new_value & 1) )
+				xPaca[i].prof_enabled = 1;
+			else
+				xPaca[i].prof_enabled = 0;
+			new_value >>= 1;
+		}
+	}
+#endif
+
+	return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+	struct proc_dir_entry *entry;
+	char name [MAX_NAMELEN];
+
+	if (!root_irq_dir || (irq_desc[irq].handler == NULL))
+		return;
+
+	memset(name, 0, MAX_NAMELEN);
+	sprintf(name, "%d", irq);
+
+	/* create /proc/irq/1234 */
+	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+	/* create /proc/irq/1234/smp_affinity */
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+	entry->nlink = 1;
+	entry->data = (void *)(long)irq;
+	entry->read_proc = irq_affinity_read_proc;
+	entry->write_proc = irq_affinity_write_proc;
+
+	smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+	struct proc_dir_entry *entry;
+	int i;
+
+	/* create /proc/irq */
+	root_irq_dir = proc_mkdir("irq", 0);
+
+	/* create /proc/irq/prof_cpu_mask */
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+	entry->nlink = 1;
+	entry->data = (void *)&prof_cpu_mask;
+	entry->read_proc = prof_cpu_mask_read_proc;
+	entry->write_proc = prof_cpu_mask_write_proc;
+
+	/*
+	 * Create entries for all existing IRQs.
+	 */
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].handler == NULL)
+			continue;
+		register_irq_proc(i);
+	}
+}
+
+void no_action(int irq, void *dev, struct pt_regs *regs)
+{
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/lmb.c linux-2.4.19-pre5/arch/ppc64/kernel/lmb.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/lmb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/lmb.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,373 @@
+/*
+ *
+ * Procedures for interfacing to Open Firmware.
+ *
+ * Peter Bergner, IBM Corp.	June 2001.
+ * Copyright (C) 2001 Peter Bergner.
+ * 
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/types.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/lmb.h>
+#include <asm/abs_addr.h>
+#include <asm/bitops.h>
+#include <asm/udbg.h>
+
+extern unsigned long klimit;
+extern unsigned long reloc_offset(void);
+
+
+static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long, unsigned long);
+
+struct lmb lmb = {
+	0,
+	{0,0,0,0,{{0,0,0}}},
+	{0,0,0,0,{{0,0,0}}}
+};
+
+
+/* Assumption: base addr of region 1 < base addr of region 2 */
+static void
+lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
+{
+	unsigned long i;
+
+	rgn->region[r1].size += rgn->region[r2].size;
+	for (i=r2; i < rgn->cnt-1 ;i++) {
+		rgn->region[i].base = rgn->region[i+1].base;
+		rgn->region[i].physbase = rgn->region[i+1].physbase;
+		rgn->region[i].size = rgn->region[i+1].size;
+		rgn->region[i].type = rgn->region[i+1].type;
+	}
+	rgn->cnt--;
+}
+
+
+/* This routine called with relocation disabled. */
+void
+lmb_init(void)
+{
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+
+	/* Create a dummy zero size LMB which will get coalesced away later.
+	 * This simplifies the lmb_add() code below...
+	 */
+	_lmb->memory.region[0].base = 0;
+	_lmb->memory.region[0].size = 0;
+	_lmb->memory.region[0].type = LMB_MEMORY_AREA;
+	_lmb->memory.cnt = 1;
+
+	/* Ditto. */
+	_lmb->reserved.region[0].base = 0;
+	_lmb->reserved.region[0].size = 0;
+	_lmb->reserved.region[0].type = LMB_MEMORY_AREA;
+	_lmb->reserved.cnt = 1;
+}
+
+/* This routine called with relocation disabled. */
+void
+lmb_analyze(void)
+{
+	unsigned long i, physbase = 0;
+	unsigned long mem_size = 0;
+	unsigned long io_size = 0;
+	unsigned long size_mask = 0;
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+
+	for (i=0; i < _lmb->memory.cnt ;i++) {
+		unsigned long lmb_type = _lmb->memory.region[i].type;
+		unsigned long lmb_size;
+
+		if ( lmb_type != LMB_MEMORY_AREA )
+			continue;
+
+		lmb_size = _lmb->memory.region[i].size;
+
+#ifdef CONFIG_MSCHUNKS
+		_lmb->memory.region[i].physbase = physbase;
+		physbase += lmb_size;
+#else
+		_lmb->memory.region[i].physbase = _lmb->memory.region[i].base;
+#endif
+		mem_size += lmb_size;
+		size_mask |= lmb_size;
+	}
+
+	for (i=0; i < _lmb->memory.cnt ;i++) {
+		unsigned long lmb_type = _lmb->memory.region[i].type;
+		unsigned long lmb_size;
+
+		if ( lmb_type != LMB_IO_AREA )
+			continue;
+
+		lmb_size = _lmb->memory.region[i].size;
+
+#ifdef CONFIG_MSCHUNKS
+		_lmb->memory.region[i].physbase = physbase;
+		physbase += lmb_size;
+#else
+		_lmb->memory.region[i].physbase = _lmb->memory.region[i].base;
+#endif
+		io_size += lmb_size;
+		size_mask |= lmb_size;
+	}
+
+	_lmb->memory.size = mem_size;
+	_lmb->memory.iosize = io_size;
+	_lmb->memory.lcd_size = (1UL << cnt_trailing_zeros(size_mask));
+}
+
+/* This routine called with relocation disabled. */
+long
+lmb_add(unsigned long base, unsigned long size)
+{
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	struct lmb_region *_rgn = &(_lmb->memory);
+
+	return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
+
+}
+
+/* This routine called with relocation disabled. */
+long
+lmb_add_io(unsigned long base, unsigned long size)
+{
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	struct lmb_region *_rgn = &(_lmb->memory);
+
+	return lmb_add_region(_rgn, base, size, LMB_IO_AREA);
+
+}
+
+long
+lmb_reserve(unsigned long base, unsigned long size)
+{
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	struct lmb_region *_rgn = &(_lmb->reserved);
+
+	return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
+}
+
+/* This routine called with relocation disabled. */
+static long
+lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size,
+		unsigned long type)
+{
+	unsigned long i, coalesced = 0;
+	long adjacent;
+
+	/* First try and coalesce this LMB with another. */
+	for (i=0; i < rgn->cnt ;i++) {
+		unsigned long rgnbase = rgn->region[i].base;
+		unsigned long rgnsize = rgn->region[i].size;
+		unsigned long rgntype = rgn->region[i].type;
+
+		if ( rgntype != type )
+			continue;
+
+		adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
+		if ( adjacent > 0 ) {
+			rgn->region[i].base -= size;
+			rgn->region[i].physbase -= size;
+			rgn->region[i].size += size;
+			coalesced++;
+			break;
+		}
+		else if ( adjacent < 0 ) {
+			rgn->region[i].size += size;
+			coalesced++;
+			break;
+		}
+	}
+
+	if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) {
+		lmb_coalesce_regions(rgn, i, i+1);
+		coalesced++;
+	}
+
+	if ( coalesced ) {
+		return coalesced;
+	} else if ( rgn->cnt >= MAX_LMB_REGIONS ) {
+		return -1;
+	}
+
+	/* Couldn't coalesce the LMB, so add it to the sorted table. */
+	for (i=rgn->cnt-1; i >= 0 ;i--) {
+		if (base < rgn->region[i].base) {
+			rgn->region[i+1].base = rgn->region[i].base;
+			rgn->region[i+1].physbase = rgn->region[i].physbase;
+			rgn->region[i+1].size = rgn->region[i].size;
+			rgn->region[i+1].type = rgn->region[i].type;
+		}  else {
+			rgn->region[i+1].base = base;
+			rgn->region[i+1].physbase = lmb_abs_to_phys(base);
+			rgn->region[i+1].size = size;
+			rgn->region[i+1].type = type;
+			break;
+		}
+	}
+	rgn->cnt++;
+
+	return 0;
+}
+
+long
+lmb_overlaps_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
+{
+	unsigned long i;
+
+	for (i=0; i < rgn->cnt ;i++) {
+		unsigned long rgnbase = rgn->region[i].base;
+		unsigned long rgnsize = rgn->region[i].size;
+		if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) {
+			break;
+		}
+	}
+
+	return (i < rgn->cnt) ? i : -1;
+}
+
+
+unsigned long
+lmb_alloc(unsigned long size, unsigned long align)
+{
+	long i, j;
+	unsigned long base;
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	struct lmb_region *_mem = &(_lmb->memory);
+	struct lmb_region *_rsv = &(_lmb->reserved);
+
+	for (i=_mem->cnt-1; i >= 0 ;i--) {
+		unsigned long lmbbase = _mem->region[i].base;
+		unsigned long lmbsize = _mem->region[i].size;
+		unsigned long lmbtype = _mem->region[i].type;
+
+		if ( lmbtype != LMB_MEMORY_AREA )
+			continue;
+
+		base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+
+		while ( (lmbbase <= base) &&
+			((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {
+			base = _ALIGN_DOWN(_rsv->region[j].base-size, align);
+		}
+
+		if ( (base != 0) && (lmbbase <= base) )
+			break;
+	}
+
+	if ( i < 0 )
+		return 0;
+
+	lmb_add_region(_rsv, base, size, LMB_MEMORY_AREA);
+
+	return base;
+}
+
+unsigned long
+lmb_phys_mem_size(void)
+{
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	return _lmb->memory.size;
+}
+
+unsigned long
+lmb_end_of_DRAM(void)
+{
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	struct lmb_region *_mem = &(_lmb->memory);
+	unsigned long idx = _mem->cnt-1;
+
+	for(idx=_mem->cnt-1; idx >= 0 ;idx--) {
+		unsigned long lastbase, lastsize;
+		if ( _mem->region[idx].type != LMB_MEMORY_AREA )
+			continue;
+#ifdef CONFIG_MSCHUNKS
+		return (_mem->region[idx].physbase + _mem->region[idx].size);
+#else
+		return (_mem->region[idx].base + _mem->region[idx].size);
+#endif /* CONFIG_MSCHUNKS */
+	}
+
+	return 0;
+}
+
+
+unsigned long
+lmb_abs_to_phys(unsigned long aa)
+{
+	unsigned long i, pa = aa;
+	unsigned long offset = reloc_offset();
+	struct lmb *_lmb = PTRRELOC(&lmb);
+	struct lmb_region *_mem = &(_lmb->memory);
+
+	for (i=0; i < _mem->cnt ;i++) {
+		unsigned long lmbbase = _mem->region[i].base;
+		unsigned long lmbsize = _mem->region[i].size;
+		if ( lmb_addrs_overlap(aa,1,lmbbase,lmbsize) ) {
+			pa = _mem->region[i].physbase + (aa - lmbbase);
+			break;
+		}
+	}
+
+	return pa;
+}
+
+void
+lmb_dump(char *str)
+{
+	unsigned long i;
+
+	udbg_printf("\nlmb_dump: %s\n", str);
+	udbg_printf("    debug                       = %s\n",
+		(lmb.debug) ? "TRUE" : "FALSE");
+	udbg_printf("    memory.cnt                  = %d\n",
+		lmb.memory.cnt);
+	udbg_printf("    memory.size                 = 0x%lx\n",
+		lmb.memory.size);
+	udbg_printf("    memory.lcd_size             = 0x%lx\n",
+		lmb.memory.lcd_size);
+	for (i=0; i < lmb.memory.cnt ;i++) {
+		udbg_printf("    memory.region[%d].base       = 0x%lx\n",
+			i, lmb.memory.region[i].base);
+		udbg_printf("                      .physbase = 0x%lx\n",
+			lmb.memory.region[i].physbase);
+		udbg_printf("                      .size     = 0x%lx\n",
+			lmb.memory.region[i].size);
+		udbg_printf("                      .type     = 0x%lx\n",
+			lmb.memory.region[i].type);
+	}
+
+	udbg_printf("\n");
+	udbg_printf("    reserved.cnt                = %d\n",
+		lmb.reserved.cnt);
+	udbg_printf("    reserved.size               = 0x%lx\n",
+		lmb.reserved.size);
+	udbg_printf("    reserved.lcd_size           = 0x%lx\n",
+		lmb.reserved.lcd_size);
+	for (i=0; i < lmb.reserved.cnt ;i++) {
+		udbg_printf("    reserved.region[%d].base     = 0x%lx\n",
+			i, lmb.reserved.region[i].base);
+		udbg_printf("                      .physbase = 0x%lx\n",
+			lmb.reserved.region[i].physbase);
+		udbg_printf("                      .size     = 0x%lx\n",
+			lmb.reserved.region[i].size);
+		udbg_printf("                      .type     = 0x%lx\n",
+			lmb.reserved.region[i].type);
+	}
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/local_irq.h linux-2.4.19-pre5/arch/ppc64/kernel/local_irq.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/local_irq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/local_irq.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,26 @@
+/*
+ *      c 2001 PowerPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#ifndef _PPC_KERNEL_LOCAL_IRQ_H
+#define _PPC_KERNEL_LOCAL_IRQ_H
+
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+
+#define NR_MASK_WORDS	((NR_IRQS + 63) / 64)
+
+extern int ppc_spurious_interrupts;
+extern int ppc_second_irq;
+extern struct irqaction *ppc_irq_action[NR_IRQS];
+
+#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/mf.c linux-2.4.19-pre5/arch/ppc64/kernel/mf.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/mf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/mf.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,1202 @@
+/*
+  * mf.c
+  * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
+  *
+  * This modules exists as an interface between a Linux secondary partition
+  * running on an iSeries and the primary partition's Virtual Service
+  * Processor (VSP) object.  The VSP has final authority over powering on/off
+  * all partitions in the iSeries.  It also provides miscellaneous low-level
+  * machine facility type operations.
+  *
+  * 
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+  */
+
+#include <asm/iSeries/mf.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/nvram.h>
+#include <asm/time.h>
+#include <asm/iSeries/ItSpCommArea.h>
+#include <asm/iSeries/mf_proc.h>
+#include <asm/iSeries/iSeries_proc.h>
+#include <asm/uaccess.h>
+#include <linux/pci.h>
+
+extern struct pci_dev * iSeries_vio_dev;
+
+/*
+ * This is the structure layout for the Machine Facilites LPAR event
+ * flows.
+ */
+struct VspCmdData;
+struct CeMsgData;
+union SafeCast
+{
+	u64 ptrAsU64;
+	void *ptr;
+};
+
+
+typedef void (*CeMsgCompleteHandler)( void *token, struct CeMsgData *vspCmdRsp );
+
+struct CeMsgCompleteData
+{
+	CeMsgCompleteHandler xHdlr;
+	void *xToken;
+};
+
+struct VspRspData
+{
+	struct semaphore *xSemaphore;
+	struct VspCmdData *xResponse;
+};
+
+struct IoMFLpEvent
+{
+	struct HvLpEvent xHvLpEvent;
+
+	u16 xSubtypeRc;
+	u16 xRsvd1;
+	u32 xRsvd2;
+
+	union
+	{
+
+		struct AllocData
+		{
+			u16 xSize;
+			u16 xType;
+			u32 xCount;
+			u16 xRsvd3;
+			u8 xRsvd4;
+			HvLpIndex xTargetLp;
+		} xAllocData;
+
+		struct CeMsgData
+		{
+			u8 xCEMsg[12];
+			char xReserved[4];
+			struct CeMsgCompleteData *xToken;
+		} xCEMsgData;
+
+		struct VspCmdData
+		{
+			union SafeCast xTokenUnion;
+			u16 xCmd;
+			HvLpIndex xLpIndex;
+			u8 xRc;
+			u32 xReserved1;
+
+			union VspCmdSubData
+			{
+				struct
+				{
+					u64 xState;
+				} xGetStateOut;
+
+				struct
+				{
+					u64 xIplType;
+				} xGetIplTypeOut, xFunction02SelectIplTypeIn;
+
+				struct
+				{
+					u64 xIplMode;
+				} xGetIplModeOut, xFunction02SelectIplModeIn;
+
+				struct
+				{
+					u64 xPage[4];
+				} xGetSrcHistoryIn;
+
+				struct
+				{
+					u64 xFlag;
+				} xGetAutoIplWhenPrimaryIplsOut,
+					xSetAutoIplWhenPrimaryIplsIn,
+					xWhiteButtonPowerOffIn,
+					xFunction08FastPowerOffIn,
+					xIsSpcnRackPowerIncompleteOut;
+
+				struct
+				{
+					u64 xToken;
+					u64 xAddressType;
+					u64 xSide;
+					u32 xTransferLength;
+					u32 xOffset;
+				} xSetKernelImageIn,
+					xGetKernelImageIn,
+					xSetKernelCmdLineIn,
+					xGetKernelCmdLineIn;
+
+				struct
+				{
+					u32 xTransferLength;
+				} xGetKernelImageOut,xGetKernelCmdLineOut;
+
+
+				u8 xReserved2[80];
+
+			} xSubData;
+		} xVspCmd;
+	} xUnion;
+};
+
+
+/*
+ * All outgoing event traffic is kept on a FIFO queue.  The first
+ * pointer points to the one that is outstanding, and all new
+ * requests get stuck on the end.  Also, we keep a certain number of
+ * preallocated stack elements so that we can operate very early in
+ * the boot up sequence (before kmalloc is ready).
+ */
+struct StackElement
+{
+	struct StackElement * next;
+	struct IoMFLpEvent event;
+	MFCompleteHandler hdlr;
+	char dmaData[72];
+	unsigned dmaDataLength;
+	unsigned remoteAddress;
+};
+static spinlock_t spinlock;
+static struct StackElement * head = NULL;
+static struct StackElement * tail = NULL;
+static struct StackElement * avail = NULL;
+static struct StackElement prealloc[16];
+
+/*
+ * Put a stack element onto the available queue, so it can get reused.
+ * Attention! You must have the spinlock before calling!
+ */
+void free( struct StackElement * element )
+{
+	if ( element != NULL )
+	{
+		element->next = avail;
+		avail = element;
+	}
+}
+
+/*
+ * Enqueue the outbound event onto the stack.  If the queue was
+ * empty to begin with, we must also issue it via the Hypervisor
+ * interface.  There is a section of code below that will touch
+ * the first stack pointer without the protection of the spinlock.
+ * This is OK, because we know that nobody else will be modifying
+ * the first pointer when we do this.
+ */
+static int signalEvent( struct StackElement * newElement )
+{
+	int rc = 0;
+	unsigned long flags;
+	int go = 1;
+	struct StackElement * element;
+	HvLpEvent_Rc hvRc;
+
+	/* enqueue the event */
+	if ( newElement != NULL )
+	{
+		spin_lock_irqsave( &spinlock, flags );
+		if ( head == NULL )
+			head = newElement;
+		else {
+			go = 0;
+			tail->next = newElement;
+		}
+		newElement->next = NULL;
+		tail = newElement;
+		spin_unlock_irqrestore( &spinlock, flags );
+	}
+
+	/* send the event */
+	while ( go )
+	{
+		go = 0;
+
+		/* any DMA data to send beforehand? */
+		if ( head->dmaDataLength > 0 )
+			HvCallEvent_dmaToSp( head->dmaData, head->remoteAddress, head->dmaDataLength, HvLpDma_Direction_LocalToRemote );
+
+		hvRc = HvCallEvent_signalLpEvent(&head->event.xHvLpEvent);
+		if ( hvRc != HvLpEvent_Rc_Good )
+		{
+			printk( KERN_ERR "mf.c: HvCallEvent_signalLpEvent() failed with %d\n", (int)hvRc );
+
+			spin_lock_irqsave( &spinlock, flags );
+			element = head;
+			head = head->next;
+			if ( head != NULL )
+				go = 1;
+			spin_unlock_irqrestore( &spinlock, flags );
+
+			if ( element == newElement )
+				rc = -EIO;
+			else {
+				if ( element->hdlr != NULL )
+				{
+					union SafeCast mySafeCast;
+					mySafeCast.ptrAsU64 = element->event.xHvLpEvent.xCorrelationToken;
+					(*element->hdlr)( mySafeCast.ptr, -EIO );
+				}
+			}
+
+			spin_lock_irqsave( &spinlock, flags );
+			free( element );
+			spin_unlock_irqrestore( &spinlock, flags );
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * Allocate a new StackElement structure, and initialize it.
+ */
+static struct StackElement * newStackElement( void )
+{
+	struct StackElement * newElement = NULL;
+	HvLpIndex primaryLp = HvLpConfig_getPrimaryLpIndex();
+	unsigned long flags;
+
+	if ( newElement == NULL )
+	{
+		spin_lock_irqsave( &spinlock, flags );
+		if ( avail != NULL )
+		{
+			newElement = avail;
+			avail = avail->next;
+		}
+		spin_unlock_irqrestore( &spinlock, flags );
+	}
+
+	if ( newElement == NULL )
+		newElement = kmalloc(sizeof(struct StackElement),GFP_ATOMIC);
+
+	if ( newElement == NULL )
+	{
+		printk( KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", sizeof(struct StackElement) );
+		return NULL;
+	}
+
+	memset( newElement, 0, sizeof(struct StackElement) );
+	newElement->event.xHvLpEvent.xFlags.xValid = 1;
+	newElement->event.xHvLpEvent.xFlags.xAckType = HvLpEvent_AckType_ImmediateAck;
+	newElement->event.xHvLpEvent.xFlags.xAckInd = HvLpEvent_AckInd_DoAck;
+	newElement->event.xHvLpEvent.xFlags.xFunction = HvLpEvent_Function_Int;
+	newElement->event.xHvLpEvent.xType = HvLpEvent_Type_MachineFac;
+	newElement->event.xHvLpEvent.xSourceLp = HvLpConfig_getLpIndex();
+	newElement->event.xHvLpEvent.xTargetLp = primaryLp;
+	newElement->event.xHvLpEvent.xSizeMinus1 = sizeof(newElement->event)-1;
+	newElement->event.xHvLpEvent.xRc = HvLpEvent_Rc_Good;
+	newElement->event.xHvLpEvent.xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primaryLp,HvLpEvent_Type_MachineFac);
+	newElement->event.xHvLpEvent.xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primaryLp,HvLpEvent_Type_MachineFac);
+
+	return newElement;
+}
+
+static int signalVspInstruction( struct VspCmdData *vspCmd )
+{
+	struct StackElement * newElement = newStackElement();
+	int rc = 0;
+	struct VspRspData response;
+	DECLARE_MUTEX_LOCKED(Semaphore);
+	response.xSemaphore = &Semaphore;
+	response.xResponse = vspCmd;
+
+	if ( newElement == NULL )
+		rc = -ENOMEM;
+	else {
+		newElement->event.xHvLpEvent.xSubtype = 6;
+		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('V'<<8)+('I'<<0);
+		newElement->event.xUnion.xVspCmd.xTokenUnion.ptr = &response;
+		newElement->event.xUnion.xVspCmd.xCmd = vspCmd->xCmd;
+		newElement->event.xUnion.xVspCmd.xLpIndex = HvLpConfig_getLpIndex();
+		newElement->event.xUnion.xVspCmd.xRc = 0xFF;
+		newElement->event.xUnion.xVspCmd.xReserved1 = 0;
+		memcpy(&(newElement->event.xUnion.xVspCmd.xSubData),&(vspCmd->xSubData), sizeof(vspCmd->xSubData));
+		mb();
+
+		rc = signalEvent(newElement);
+	}
+
+	if (rc == 0)
+	{
+		down(&Semaphore);
+	}
+
+	return rc;
+}
+
+
+/*
+ * Send a 12-byte CE message to the primary partition VSP object
+ */
+static int signalCEMsg( char * ceMsg, void * token )
+{
+	struct StackElement * newElement = newStackElement();
+	int rc = 0;
+
+	if ( newElement == NULL )
+		rc = -ENOMEM;
+	else {
+		newElement->event.xHvLpEvent.xSubtype = 0;
+		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('C'<<8)+('E'<<0);
+		memcpy( newElement->event.xUnion.xCEMsgData.xCEMsg, ceMsg, 12 );
+		newElement->event.xUnion.xCEMsgData.xToken = token;
+		rc = signalEvent(newElement);
+	}
+
+	return rc;
+}
+
+/*
+ * Send a 12-byte CE message and DMA data to the primary partition VSP object
+ */
+static int dmaAndSignalCEMsg( char * ceMsg, void * token, void * dmaData, unsigned dmaDataLength, unsigned remoteAddress )
+{
+	struct StackElement * newElement = newStackElement();
+	int rc = 0;
+
+	if ( newElement == NULL )
+		rc = -ENOMEM;
+	else {
+		newElement->event.xHvLpEvent.xSubtype = 0;
+		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('C'<<8)+('E'<<0);
+		memcpy( newElement->event.xUnion.xCEMsgData.xCEMsg, ceMsg, 12 );
+		newElement->event.xUnion.xCEMsgData.xToken = token;
+		memcpy( newElement->dmaData, dmaData, dmaDataLength );
+		newElement->dmaDataLength = dmaDataLength;
+		newElement->remoteAddress = remoteAddress;
+		rc = signalEvent(newElement);
+	}
+
+	return rc;
+}
+
+/*
+ * Initiate a nice (hopefully) shutdown of Linux.  We simply are
+ * going to try and send the init process a SIGINT signal.  If
+ * this fails (why?), we'll simply force it off in a not-so-nice
+ * manner.
+ */
+static int shutdown( void )
+{
+	int rc = kill_proc(1,SIGINT,1);
+
+	if ( rc )
+	{
+		printk( KERN_ALERT "mf.c: SIGINT to init failed (%d), hard shutdown commencing\n", rc );
+		mf_powerOff();
+	}
+	else
+		printk( KERN_ALERT "mf.c: init has been successfully notified to proceed with shutdown\n" );
+
+	return rc;
+}
+
+/*
+ * The primary partition VSP object is sending us a new
+ * event flow.  Handle it...
+ */
+static void intReceived( struct IoMFLpEvent * event )
+{
+	int freeIt = 0;
+	struct StackElement * two = NULL;
+	/* ack the interrupt */
+	event->xHvLpEvent.xRc = HvLpEvent_Rc_Good;
+	HvCallEvent_ackLpEvent( &event->xHvLpEvent );
+
+    /* process interrupt */
+	switch( event->xHvLpEvent.xSubtype )
+	{
+	case 0:	/* CE message */
+		switch( event->xUnion.xCEMsgData.xCEMsg[3] )
+		{
+		case 0x5B:	/* power control notification */
+			if ( (event->xUnion.xCEMsgData.xCEMsg[5]&0x20) != 0 )
+			{
+				printk( KERN_ALERT "mf.c: Commencing partition shutdown\n" );
+				if ( shutdown() == 0 )
+					signalCEMsg( "\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
+			}
+			break;
+		case 0xC0:	/* get time */
+			{
+				if ( (head != NULL) && ( head->event.xUnion.xCEMsgData.xCEMsg[3] == 0x40 ) )
+				{
+					freeIt = 1;
+					if ( head->event.xUnion.xCEMsgData.xToken != 0 )
+					{
+						CeMsgCompleteHandler xHdlr = head->event.xUnion.xCEMsgData.xToken->xHdlr;
+						void * token = head->event.xUnion.xCEMsgData.xToken->xToken;
+
+						if (xHdlr != NULL)
+							(*xHdlr)( token, &(event->xUnion.xCEMsgData) );
+					}
+				}
+			}
+			break;
+		}
+
+		/* remove from queue */
+		if ( freeIt == 1 )
+		{
+			unsigned long flags;
+			spin_lock_irqsave( &spinlock, flags );
+			if ( head != NULL )
+			{
+				struct StackElement *oldHead = head;
+				head = head->next;
+				two = head;
+				free( oldHead );
+			}
+			spin_unlock_irqrestore( &spinlock, flags );
+		}
+
+		/* send next waiting event */
+		if ( two != NULL )
+			signalEvent( NULL );
+		break;
+	case 1:	/* IT sys shutdown */
+		printk( KERN_ALERT "mf.c: Commencing system shutdown\n" );
+		shutdown();
+		break;
+	}
+}
+
+/*
+ * The primary partition VSP object is acknowledging the receipt
+ * of a flow we sent to them.  If there are other flows queued
+ * up, we must send another one now...
+ */
+static void ackReceived( struct IoMFLpEvent * event )
+{
+	unsigned long flags;
+	struct StackElement * two = NULL;
+	unsigned long freeIt = 0;
+
+    /* handle current event */
+	if ( head != NULL )
+	{
+		switch( event->xHvLpEvent.xSubtype )
+		{
+		case 0:     /* CE msg */
+			if ( event->xUnion.xCEMsgData.xCEMsg[3] == 0x40 )
+			{
+				if ( event->xUnion.xCEMsgData.xCEMsg[2] != 0 )
+				{
+					freeIt = 1;
+					if ( head->event.xUnion.xCEMsgData.xToken != 0 )
+					{
+						CeMsgCompleteHandler xHdlr = head->event.xUnion.xCEMsgData.xToken->xHdlr;
+						void * token = head->event.xUnion.xCEMsgData.xToken->xToken;
+
+						if (xHdlr != NULL)
+							(*xHdlr)( token, &(event->xUnion.xCEMsgData) );
+					}
+				}
+			} else {
+				freeIt = 1;
+			}
+			break;
+		case 4:	/* allocate */
+		case 5:	/* deallocate */
+			if ( head->hdlr != NULL )
+			{
+				union SafeCast mySafeCast;
+				mySafeCast.ptrAsU64 = event->xHvLpEvent.xCorrelationToken;
+				(*head->hdlr)( mySafeCast.ptr, event->xUnion.xAllocData.xCount );
+			}
+			freeIt = 1;
+			break;
+		case 6:
+			{
+				struct VspRspData *rsp = (struct VspRspData *)event->xUnion.xVspCmd.xTokenUnion.ptr;
+
+				if (rsp != NULL)
+				{
+					if (rsp->xResponse != NULL)
+						memcpy(rsp->xResponse, &(event->xUnion.xVspCmd), sizeof(event->xUnion.xVspCmd));
+					if (rsp->xSemaphore != NULL)
+						up(rsp->xSemaphore);
+				} else {
+					printk( KERN_ERR "mf.c: no rsp\n");
+				}
+				freeIt = 1;
+			}
+			break;
+		}
+	}
+	else
+		printk( KERN_ERR "mf.c: stack empty for receiving ack\n" );
+
+    /* remove from queue */
+	spin_lock_irqsave( &spinlock, flags );
+	if (( head != NULL ) && ( freeIt == 1 ))
+	{
+		struct StackElement *oldHead = head;
+		head = head->next;
+		two = head;
+		free( oldHead );
+	} 
+	spin_unlock_irqrestore( &spinlock, flags );
+
+    /* send next waiting event */
+	if ( two != NULL )
+		signalEvent( NULL );
+}
+
+/*
+ * This is the generic event handler we are registering with
+ * the Hypervisor.  Ensure the flows are for us, and then
+ * parse it enough to know if it is an interrupt or an
+ * acknowledge.
+ */
+static void hvHandler( struct HvLpEvent * event, struct pt_regs * regs )
+{
+	if ( (event != NULL) && (event->xType == HvLpEvent_Type_MachineFac) )
+	{
+		switch( event->xFlags.xFunction )
+		{
+		case HvLpEvent_Function_Ack:
+			ackReceived( (struct IoMFLpEvent *)event );
+			break;
+		case HvLpEvent_Function_Int:
+			intReceived( (struct IoMFLpEvent *)event );
+			break;
+		default:
+			printk( KERN_ERR "mf.c: non ack/int event received\n" );
+			break;
+		}
+	}
+	else
+		printk( KERN_ERR "mf.c: alien event received\n" );
+}
+
+/*
+ * Global kernel interface to allocate and seed events into the
+ * Hypervisor.
+ */
+void mf_allocateLpEvents( HvLpIndex targetLp,
+			  HvLpEvent_Type type,
+			  unsigned size,
+			  unsigned count,
+			  MFCompleteHandler hdlr,
+			  void * userToken )
+{
+	struct StackElement * newElement = newStackElement();
+	int rc = 0;
+
+	if ( newElement == NULL )
+		rc = -ENOMEM;
+	else {
+		union SafeCast mine;
+		mine.ptr = userToken;
+		newElement->event.xHvLpEvent.xSubtype = 4;
+		newElement->event.xHvLpEvent.xCorrelationToken = mine.ptrAsU64;
+		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('M'<<8)+('A'<<0);
+		newElement->event.xUnion.xAllocData.xTargetLp = targetLp;
+		newElement->event.xUnion.xAllocData.xType = type;
+		newElement->event.xUnion.xAllocData.xSize = size;
+		newElement->event.xUnion.xAllocData.xCount = count;
+		newElement->hdlr = hdlr;
+		rc = signalEvent(newElement);
+	}
+
+	if ( (rc != 0) && (hdlr != NULL) )
+		(*hdlr)( userToken, rc );
+}
+
+/*
+ * Global kernel interface to unseed and deallocate events already in
+ * Hypervisor.
+ */
+void mf_deallocateLpEvents( HvLpIndex targetLp,
+			    HvLpEvent_Type type,
+			    unsigned count,
+			    MFCompleteHandler hdlr,
+			    void * userToken )
+{
+	struct StackElement * newElement = newStackElement();
+	int rc = 0;
+
+	if ( newElement == NULL )
+		rc = -ENOMEM;
+	else {
+		union SafeCast mine;
+		mine.ptr = userToken;
+		newElement->event.xHvLpEvent.xSubtype = 5;
+		newElement->event.xHvLpEvent.xCorrelationToken = mine.ptrAsU64;
+		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('M'<<8)+('D'<<0);
+		newElement->event.xUnion.xAllocData.xTargetLp = targetLp;
+		newElement->event.xUnion.xAllocData.xType = type;
+		newElement->event.xUnion.xAllocData.xCount = count;
+		newElement->hdlr = hdlr;
+		rc = signalEvent(newElement);
+	}
+
+	if ( (rc != 0) && (hdlr != NULL) )
+		(*hdlr)( userToken, rc );
+}
+
+/*
+ * Global kernel interface to tell the VSP object in the primary
+ * partition to power this partition off.
+ */
+void mf_powerOff( void )
+{
+	printk( KERN_ALERT "mf.c: Down it goes...\n" );
+	signalCEMsg( "\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
+	for (;;);
+}
+
+/*
+ * Global kernel interface to tell the VSP object in the primary
+ * partition to reboot this partition.
+ */
+void mf_reboot( void )
+{
+	printk( KERN_ALERT "mf.c: Preparing to bounce...\n" );
+	signalCEMsg( "\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
+	for (;;);
+}
+
+/*
+ * Display a single word SRC onto the VSP control panel.
+ */
+void mf_displaySrc( u32 word )
+{
+	u8 ce[12];
+
+	memcpy( ce, "\x00\x00\x00\x4A\x00\x00\x00\x01\x00\x00\x00\x00", 12 );
+	ce[8] = word>>24;
+	ce[9] = word>>16;
+	ce[10] = word>>8;
+	ce[11] = word;
+	signalCEMsg( ce, NULL );
+}
+
+/*
+ * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
+ */
+void mf_displayProgress( u16 value )
+{
+	u8 ce[12];
+	u8 src[72];
+
+	memcpy( ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12 );
+	memcpy( src,
+		"\x01\x00\x00\x01"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"\x00\x00\x00\x00"
+		"PROGxxxx"
+		"                        ",
+		72 );
+	src[6] = value>>8;
+	src[7] = value&255;
+	src[44] = "0123456789ABCDEF"[(value>>12)&15];
+	src[45] = "0123456789ABCDEF"[(value>>8)&15];
+	src[46] = "0123456789ABCDEF"[(value>>4)&15];
+	src[47] = "0123456789ABCDEF"[value&15];
+	dmaAndSignalCEMsg( ce, NULL, src, sizeof(src), 9*64*1024 );
+}
+
+/*
+ * Clear the VSP control panel.  Used to "erase" an SRC that was
+ * previously displayed.
+ */
+void mf_clearSrc( void )
+{
+	signalCEMsg( "\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
+}
+
+/*
+ * Initialization code here.
+ */
+void mf_init( void )
+{
+	int i;
+
+    /* initialize */
+	spin_lock_init( &spinlock );
+	for ( i = 0; i < sizeof(prealloc)/sizeof(*prealloc); ++i )
+		free( &prealloc[i] );
+	HvLpEvent_registerHandler( HvLpEvent_Type_MachineFac, &hvHandler );
+
+	/* virtual continue ack */
+	signalCEMsg( "\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
+
+	/* initialization complete */
+	printk( KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n" );
+
+	iSeries_proc_callback(&mf_proc_init);
+}
+
+void mf_setSide(char side)
+{
+	int rc = 0;
+	u64 newSide = 0;
+	struct VspCmdData myVspCmd;
+
+	memset(&myVspCmd, 0, sizeof(myVspCmd));
+	if (side == 'A')
+		newSide = 0;
+	else if (side == 'B')
+		newSide = 1;
+	else if (side == 'C')
+		newSide = 2; 
+	else
+		newSide = 3;
+
+	myVspCmd.xSubData.xFunction02SelectIplTypeIn.xIplType = newSide;
+	myVspCmd.xCmd = 10;
+
+	rc = signalVspInstruction(&myVspCmd);
+}
+
+char mf_getSide(void)
+{
+	char returnValue = ' ';
+	int rc = 0;
+	struct VspCmdData myVspCmd;
+
+	memset(&myVspCmd, 0, sizeof(myVspCmd));
+	myVspCmd.xCmd = 2;
+	myVspCmd.xSubData.xFunction02SelectIplTypeIn.xIplType = 0;
+	mb();
+	rc = signalVspInstruction(&myVspCmd);
+
+	if (rc != 0)
+	{
+		return returnValue;
+	} else {
+		if (myVspCmd.xRc == 0)
+		{
+			if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 0)
+				returnValue = 'A';
+			else if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 1)
+				returnValue = 'B';
+			else if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 2)
+				returnValue = 'C';
+			else
+				returnValue = 'D';
+		}
+	}
+
+	return returnValue;
+}
+
+void mf_getSrcHistory(char *buffer, int size)
+{
+    /*    struct IplTypeReturnStuff returnStuff;
+     struct StackElement * newElement = newStackElement();
+     int rc = 0;
+     char *pages[4];
+
+     pages[0] = kmalloc(4096, GFP_ATOMIC);
+     pages[1] = kmalloc(4096, GFP_ATOMIC);
+     pages[2] = kmalloc(4096, GFP_ATOMIC);
+     pages[3] = kmalloc(4096, GFP_ATOMIC);
+     if (( newElement == NULL ) || (pages[0] == NULL) || (pages[1] == NULL) || (pages[2] == NULL) || (pages[3] == NULL))
+     rc = -ENOMEM;
+     else
+     {
+     returnStuff.xType = 0;
+     returnStuff.xRc = 0;
+     returnStuff.xDone = 0;
+     newElement->event.xHvLpEvent.xSubtype = 6;
+     newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('V'<<8)+('I'<<0);
+     newElement->event.xUnion.xVspCmd.xEvent = &returnStuff;
+     newElement->event.xUnion.xVspCmd.xCmd = 4;
+     newElement->event.xUnion.xVspCmd.xLpIndex = HvLpConfig_getLpIndex();
+     newElement->event.xUnion.xVspCmd.xRc = 0xFF;
+     newElement->event.xUnion.xVspCmd.xReserved1 = 0;
+     newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[0] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[0]));
+     newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[1] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[1]));
+     newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[2] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[2]));
+     newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[3] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[3]));
+     mb();
+     rc = signalEvent(newElement);
+     }
+
+     if (rc != 0)
+     {
+     return;
+     }
+     else
+     {
+     while (returnStuff.xDone != 1)
+     {
+     udelay(10);
+     }
+
+     if (returnStuff.xRc == 0)
+     {
+     memcpy(buffer, pages[0], size);
+     }
+     }
+
+     kfree(pages[0]);
+     kfree(pages[1]);
+     kfree(pages[2]);
+     kfree(pages[3]);*/
+}
+
+void mf_setCmdLine(const char *cmdline, int size, u64 side)
+{
+	struct VspCmdData myVspCmd;
+	int rc = 0;
+	dma_addr_t dma_addr = 0;
+	char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr);
+
+	if (page == NULL) {
+		printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n");
+		return;
+	}
+
+	copy_from_user(page, cmdline, size);
+
+	memset(&myVspCmd, 0, sizeof(myVspCmd));
+	myVspCmd.xCmd = 31;
+	myVspCmd.xSubData.xSetKernelCmdLineIn.xToken = dma_addr;
+	myVspCmd.xSubData.xSetKernelCmdLineIn.xAddressType = HvLpDma_AddressType_TceIndex;
+	myVspCmd.xSubData.xSetKernelCmdLineIn.xSide = side;
+	myVspCmd.xSubData.xSetKernelCmdLineIn.xTransferLength = size;
+	mb();
+	rc = signalVspInstruction(&myVspCmd);
+
+	pci_free_consistent(iSeries_vio_dev, size, page, dma_addr);
+}
+
+int mf_getCmdLine(char *cmdline, int *size, u64 side)
+{
+	struct VspCmdData myVspCmd;
+	int rc = 0;
+	int len = *size;
+	dma_addr_t dma_addr = pci_map_single(iSeries_vio_dev, cmdline, *size, PCI_DMA_FROMDEVICE);
+
+	memset(cmdline, 0, *size);
+	memset(&myVspCmd, 0, sizeof(myVspCmd));
+	myVspCmd.xCmd = 33;
+	myVspCmd.xSubData.xGetKernelCmdLineIn.xToken = dma_addr;
+	myVspCmd.xSubData.xGetKernelCmdLineIn.xAddressType = HvLpDma_AddressType_TceIndex;
+	myVspCmd.xSubData.xGetKernelCmdLineIn.xSide = side;
+	myVspCmd.xSubData.xGetKernelCmdLineIn.xTransferLength = *size;
+	mb();
+	rc = signalVspInstruction(&myVspCmd);
+
+	if ( ! rc ) {
+
+		if (myVspCmd.xRc == 0)
+		{
+			len = myVspCmd.xSubData.xGetKernelCmdLineOut.xTransferLength;
+		}
+		/* else
+			{
+			memcpy(cmdline, "Bad cmdline", 11);
+			}
+		*/
+	}
+
+	pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE);
+
+	return len;
+}
+
+
+int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side)
+{
+	struct VspCmdData myVspCmd;
+	int rc = 0;
+
+	dma_addr_t dma_addr = 0;
+
+	char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr);
+
+	if (page == NULL) {
+		printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
+		return -ENOMEM;
+	}
+
+	copy_from_user(page, buffer, size);
+	memset(&myVspCmd, 0, sizeof(myVspCmd));
+
+	myVspCmd.xCmd = 30;
+	myVspCmd.xSubData.xGetKernelImageIn.xToken = dma_addr;
+	myVspCmd.xSubData.xGetKernelImageIn.xAddressType = HvLpDma_AddressType_TceIndex;
+	myVspCmd.xSubData.xGetKernelImageIn.xSide = side;
+	myVspCmd.xSubData.xGetKernelImageIn.xOffset = offset;
+	myVspCmd.xSubData.xGetKernelImageIn.xTransferLength = size;
+	mb();
+	rc = signalVspInstruction(&myVspCmd);
+
+	if (rc == 0)
+	{
+		if (myVspCmd.xRc == 0)
+		{
+			rc = 0;
+		} else {
+			rc = -ENOMEM;
+		}
+	}
+
+	pci_free_consistent(iSeries_vio_dev, size, page, dma_addr);
+
+	return rc;
+}
+
+int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
+{
+	struct VspCmdData myVspCmd;
+	int rc = 0;
+	int len = *size;
+
+	dma_addr_t dma_addr = pci_map_single(iSeries_vio_dev, buffer, *size, PCI_DMA_FROMDEVICE);
+
+	memset(buffer, 0, len);
+
+	memset(&myVspCmd, 0, sizeof(myVspCmd));
+	myVspCmd.xCmd = 32;
+	myVspCmd.xSubData.xGetKernelImageIn.xToken = dma_addr;
+	myVspCmd.xSubData.xGetKernelImageIn.xAddressType = HvLpDma_AddressType_TceIndex;
+	myVspCmd.xSubData.xGetKernelImageIn.xSide = side;
+	myVspCmd.xSubData.xGetKernelImageIn.xOffset = offset;
+	myVspCmd.xSubData.xGetKernelImageIn.xTransferLength = len;
+	mb();
+	rc = signalVspInstruction(&myVspCmd);
+
+	if (rc == 0)
+	{
+		if (myVspCmd.xRc == 0)
+		{
+			*size = myVspCmd.xSubData.xGetKernelImageOut.xTransferLength;
+		} else {
+			rc = -ENOMEM;
+		}
+	}
+
+	pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE);
+
+	return rc;
+}
+
+int mf_setRtcTime(unsigned long time)
+{
+	struct rtc_time tm;
+
+	to_tm(time, &tm);
+
+	return mf_setRtc( &tm );
+}
+
+struct RtcTimeData
+{
+	struct semaphore *xSemaphore;
+	struct CeMsgData xCeMsg;
+	int xRc;
+};
+
+void getRtcTimeComplete(void * token, struct CeMsgData *ceMsg)
+{
+	struct RtcTimeData *rtc = (struct RtcTimeData *)token;
+
+	memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg));
+
+	rtc->xRc = 0;
+	up(rtc->xSemaphore);
+}
+
+static unsigned long lastsec = 1;
+
+int mf_getRtcTime(unsigned long *time)
+{
+/*    unsigned long usec, tsec; */
+	
+	u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart));
+	u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1);
+	int year = 1970;
+	int year1 = ( dataWord1 >> 24 ) & 0x000000FF;
+	int year2 = ( dataWord1 >> 16 ) & 0x000000FF;
+	int sec = ( dataWord1 >> 8 ) & 0x000000FF;
+	int min = dataWord1 & 0x000000FF;
+	int hour = ( dataWord2 >> 24 ) & 0x000000FF;
+	int day = ( dataWord2 >> 8 ) & 0x000000FF;
+	int mon = dataWord2 & 0x000000FF;
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year1);
+	BCD_TO_BIN(year2);
+	year = year1 * 100 + year2;
+
+	*time = mktime(year, mon, day, hour, min, sec);
+
+	*time += ( jiffies / HZ );
+    
+	/* Now THIS is a nasty hack!
+	 * It ensures that the first two calls to mf_getRtcTime get different
+	 * answers.  That way the loop in init_time (time.c) will not think
+	 * the clock is stuck.
+	 */
+	if ( lastsec ) {
+		*time -= lastsec;
+		--lastsec;
+	}
+    
+	return 0;
+
+}
+
+int mf_getRtc( struct rtc_time * tm )
+{
+
+	struct CeMsgCompleteData ceComplete;
+	struct RtcTimeData rtcData;
+	int rc = 0;
+	DECLARE_MUTEX_LOCKED(Semaphore);
+
+	memset(&ceComplete, 0, sizeof(ceComplete));
+	memset(&rtcData, 0, sizeof(rtcData));
+
+	rtcData.xSemaphore = &Semaphore;
+
+	ceComplete.xHdlr = &getRtcTimeComplete;
+	ceComplete.xToken = (void *)&rtcData;
+
+	rc = signalCEMsg( "\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00", &ceComplete );
+
+	if ( rc == 0 )
+	{
+		down(&Semaphore);
+
+		if ( rtcData.xRc == 0)
+		{
+			if ( ( rtcData.xCeMsg.xCEMsg[2] == 0xa9 ) ||
+			     ( rtcData.xCeMsg.xCEMsg[2] == 0xaf ) ) {
+				/* TOD clock is not set */
+				tm->tm_sec = 1;
+				tm->tm_min = 1;
+				tm->tm_hour = 1;
+				tm->tm_mday = 10;
+				tm->tm_mon = 8;
+				tm->tm_year = 71;
+				mf_setRtc( tm );
+			}
+			{
+				u32 dataWord1 = *((u32 *)(rtcData.xCeMsg.xCEMsg+4));
+				u32 dataWord2 = *((u32 *)(rtcData.xCeMsg.xCEMsg+8));
+				u8 year = (dataWord1 >> 16 ) & 0x000000FF;
+				u8 sec = ( dataWord1 >> 8 ) & 0x000000FF;
+				u8 min = dataWord1 & 0x000000FF;
+				u8 hour = ( dataWord2 >> 24 ) & 0x000000FF;
+				u8 day = ( dataWord2 >> 8 ) & 0x000000FF;
+				u8 mon = dataWord2 & 0x000000FF;
+
+				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 <= 69 )
+					year += 100;
+	    
+				tm->tm_sec = sec;
+				tm->tm_min = min;
+				tm->tm_hour = hour;
+				tm->tm_mday = day;
+				tm->tm_mon = mon;
+				tm->tm_year = year;
+			}
+		} else {
+			rc = rtcData.xRc;
+			tm->tm_sec = 0;
+			tm->tm_min = 0;
+			tm->tm_hour = 0;
+			tm->tm_mday = 15;
+			tm->tm_mon = 5;
+			tm->tm_year = 52;
+
+		}
+		tm->tm_wday = 0;
+		tm->tm_yday = 0;
+		tm->tm_isdst = 0;
+
+	}
+
+	return rc;
+
+}
+
+int mf_setRtc(struct rtc_time * tm)
+{
+	char ceTime[12] = "\x00\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00";
+	int rc = 0;
+	u8 day, mon, hour, min, sec, y1, y2;
+	unsigned year;
+    
+	year = 1900 + tm->tm_year;
+	y1 = year / 100;
+	y2 = year % 100;
+    
+	sec = tm->tm_sec;
+	min = tm->tm_min;
+	hour = tm->tm_hour;
+	day = tm->tm_mday;
+	mon = tm->tm_mon + 1;
+	    
+	BIN_TO_BCD(sec);
+	BIN_TO_BCD(min);
+	BIN_TO_BCD(hour);
+	BIN_TO_BCD(mon);
+	BIN_TO_BCD(day);
+	BIN_TO_BCD(y1);
+	BIN_TO_BCD(y2);
+
+	ceTime[4] = y1;
+	ceTime[5] = y2;
+	ceTime[6] = sec;
+	ceTime[7] = min;
+	ceTime[8] = hour;
+	ceTime[10] = day;
+	ceTime[11] = mon;
+   
+	rc = signalCEMsg( ceTime, NULL );
+
+	return rc;
+}
+
+
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/mf_proc.c linux-2.4.19-pre5/arch/ppc64/kernel/mf_proc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/mf_proc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/mf_proc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,301 @@
+/*
+ * mf_proc.c
+ * Copyright (C) 2001 Kyle A. Lucke  IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _MF_PROC_H
+#include <asm/iSeries/mf_proc.h>
+#endif
+#ifndef MF_H_INCLUDED
+#include <asm/iSeries/mf.h>
+#endif
+#include <asm/uaccess.h>
+
+static struct proc_dir_entry *mf_proc_root = NULL;
+
+int proc_mf_dump_cmdline
+(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+int proc_mf_dump_vmlinux
+(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+int proc_mf_dump_side
+(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+int proc_mf_change_side
+(struct file *file, const char *buffer, unsigned long count, void *data);
+
+int proc_mf_dump_src
+(char *page, char **start, off_t off, int count, int *eof, void *data);
+int proc_mf_change_src (struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_mf_change_cmdline(struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_mf_change_vmlinux(struct file *file, const char *buffer, unsigned long count, void *data);
+
+
+void mf_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+	struct proc_dir_entry *ent = NULL;
+	struct proc_dir_entry *mf_a = NULL;
+	struct proc_dir_entry *mf_b = NULL;
+	struct proc_dir_entry *mf_c = NULL;
+	struct proc_dir_entry *mf_d = NULL;
+
+	mf_proc_root = proc_mkdir("mf", iSeries_proc);
+	if (!mf_proc_root) return;
+
+	mf_a = proc_mkdir("A", mf_proc_root);
+	if (!mf_a) return;
+
+	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_a);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)0;
+	ent->read_proc = proc_mf_dump_cmdline;
+	ent->write_proc = proc_mf_change_cmdline;
+
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_a);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)0;
+	ent->read_proc = proc_mf_dump_vmlinux;
+	ent->write_proc = proc_mf_change_vmlinux;
+
+	mf_b = proc_mkdir("B", mf_proc_root);
+	if (!mf_b) return;
+
+	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_b);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)1;
+	ent->read_proc = proc_mf_dump_cmdline;
+	ent->write_proc = proc_mf_change_cmdline;
+
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_b);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)1;
+	ent->read_proc = proc_mf_dump_vmlinux;
+	ent->write_proc = proc_mf_change_vmlinux;
+
+	mf_c = proc_mkdir("C", mf_proc_root);
+	if (!mf_c) return;
+
+	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_c);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)2;
+	ent->read_proc = proc_mf_dump_cmdline;
+	ent->write_proc = proc_mf_change_cmdline;
+
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR|S_IWUSR, mf_c);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)2;
+	ent->read_proc = proc_mf_dump_vmlinux;
+	ent->write_proc = proc_mf_change_vmlinux;
+
+	mf_d = proc_mkdir("D", mf_proc_root);
+	if (!mf_d) return;
+
+
+	ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf_d);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)3;
+	ent->read_proc = proc_mf_dump_cmdline;
+	ent->write_proc = proc_mf_change_cmdline;
+
+	ent = create_proc_entry("vmlinux", S_IFREG|S_IRUSR, mf_d);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)3;
+	ent->read_proc = proc_mf_dump_vmlinux;
+	ent->write_proc = NULL;
+
+	ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)0;
+	ent->read_proc = proc_mf_dump_side;
+	ent->write_proc = proc_mf_change_side;
+
+	ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+	if (!ent) return;
+	ent->nlink = 1;
+	ent->data = (void *)0;
+	ent->read_proc = proc_mf_dump_src;
+	ent->write_proc = proc_mf_change_src;
+}
+
+int proc_mf_dump_cmdline
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int		len = count;
+	char *p;
+    
+	len = mf_getCmdLine(page, &len, (u64)data);
+   
+	p = page + len - 1;
+	while ( p > page ) {
+		if ( (*p == 0) || (*p == ' ') )
+			--p;
+		else
+			break;
+	}
+	if ( *p != '\n' ) {
+		++p;
+		*p = '\n';
+	}
+	++p;
+	*p = 0;
+	len = p - page;
+    
+	len -= off;			
+	if (len < count) {		
+		*eof = 1;		
+		if (len <= 0)		
+			return 0;	
+	} else				
+		len = count;		
+	*start = page + off;		
+	return len;			
+}
+
+int proc_mf_dump_vmlinux
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int sizeToGet = count;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0)
+	{
+		if (sizeToGet != 0)
+		{
+			*start = page + off;
+			printk("mf_proc.c: got count %d off %d\n", sizeToGet, (int)off);
+			return sizeToGet;
+		} else {
+			printk("mf_proc.c: eof\n");
+			*eof = 1;
+			return 0;
+		}
+	} else {
+		printk("mf_proc.c: eof\n");
+		*eof = 1;
+		return 0;
+	}
+}
+
+
+int proc_mf_dump_side
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int		len = 0;
+
+	char mf_current_side = mf_getSide();
+	len = sprintf(page, "%c\n", mf_current_side);
+
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;			
+}
+
+int proc_mf_change_side(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if ((*buffer != 'A') &&
+	    (*buffer != 'B') &&
+	    (*buffer != 'C') &&
+	    (*buffer != 'D'))
+	{
+		printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
+		return -EINVAL;
+	}
+
+	mf_setSide(*buffer);
+
+	return count;			
+}
+
+int proc_mf_dump_src
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int		len = 0;
+	mf_getSrcHistory(page, count);
+	len = count;
+	len -= off;			
+	if (len < count) {		
+		*eof = 1;		
+		if (len <= 0)		
+			return 0;	
+	} else				
+		len = count;		
+	*start = page + off;		
+	return len;			
+}
+
+int proc_mf_change_src(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if ((count < 4) && (count != 1))
+	{
+		printk(KERN_ERR "mf_proc: invalid src\n");
+		return -EINVAL;
+	}
+
+	if ((count == 1) && ((*buffer) == '\0'))
+	{
+		mf_clearSrc();
+	} else {
+		mf_displaySrc(*(u32 *)buffer);
+	}
+
+	return count;			
+}
+
+int proc_mf_change_cmdline(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	mf_setCmdLine(buffer, count, (u64)data);
+
+	return count;			
+}
+
+int proc_mf_change_vmlinux(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	mf_setVmlinuxChunk(buffer, count, file->f_pos, (u64)data);
+	file->f_pos += count;
+
+	return count;			
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/misc.S linux-2.4.19-pre5/arch/ppc64/kernel/misc.S
--- linux-2.4.19-pre4/arch/ppc64/kernel/misc.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/misc.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,948 @@
+/*
+ *  arch/ppc/kernel/misc.S
+ *
+ *  
+ *
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
+ * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) 
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include "ppc_asm.h"
+
+	.text
+
+/*
+ * 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
+1:	mflr	r3
+	LOADADDR(r4,1b)
+	sub	r3,r4,r3
+	mtlr	r0
+	blr
+
+_GLOBAL(get_msr)
+	mfmsr	r3
+	blr
+
+_GLOBAL(get_dar)
+	mfdar	r3
+	blr
+
+_GLOBAL(get_srr0)
+	mfsrr0  r3
+	blr
+
+_GLOBAL(get_srr1)
+	mfsrr1  r3
+	blr
+	
+_GLOBAL(get_sp)
+	mr	r3,r1
+	blr
+		
+#ifdef CONFIG_PPC_ISERIES
+/* unsigned long __no_use_save_flags(void) */
+_GLOBAL(__no_use_save_flags)
+	mfspr	r4,SPRG3
+	lbz	r3,PACAPROCENABLED(r4)
+	blr
+
+/* void __no_use_restore_flags(unsigned long flags) */	
+_GLOBAL(__no_use_restore_flags)
+/*
+ * Just set/clear the MSR_EE bit through restore/flags but do not
+ * change anything else.  This is needed by the RT system and makes
+ * sense anyway.
+ *    -- Cort
+ */
+	mfspr	r6,SPRG3
+	lbz	r5,PACAPROCENABLED(r6)
+	 /* Check if things are setup the way we want _already_. */
+	cmpw	0,r3,r5
+	beqlr
+	/* are we enabling interrupts? */
+	cmpi	0,r3,0
+	stb	r3,PACAPROCENABLED(r6)
+	beqlr
+	/* Check pending interrupts */
+	CHECKANYINT(r4,r5)
+	beqlr
+
+	/* 
+	 * Handle pending interrupts in interrupt context
+	 */
+	li	r0,0x5555
+	sc
+	blr
+
+_GLOBAL(__no_use_cli)
+	mfspr	r5,SPRG3
+	lbz	r3,PACAPROCENABLED(r5)
+	li	r4,0
+	stb	r4,PACAPROCENABLED(r5)
+	blr			/* Done */
+
+_GLOBAL(__no_use_sti)
+	mfspr	r6,SPRG3
+	li	r3,1
+	stb	r3,PACAPROCENABLED(r6)
+
+	/* Check for pending interrupts
+	 *   A decrementer, IPI or PMC interrupt may have occurred
+	 *   while we were in the hypervisor (which enables)
+	 */
+	CHECKANYINT(r4,r5)
+	beqlr
+
+	/* 
+	 * Handle pending interrupts in interrupt context
+	 */
+	li	r0,0x5555
+	sc	
+	blr
+#endif
+/*
+ * Flush instruction cache.
+ */
+_GLOBAL(flush_instruction_cache)
+
+/*
+ * This is called by kgdb code
+ * and should probably go away
+ * to be replaced by invalidating
+ * the cache lines that are actually
+ * modified
+ */
+	/* use invalidate-all bit in HID0
+	 *  - is this consistent across all 64-bit cpus?  -- paulus */
+	mfspr	r3,HID0
+	ori	r3,r3,HID0_ICFI
+	mtspr	HID0,r3
+	sync
+	isync
+	blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ *
+ *   flush all bytes from start through stop-1 inclusive
+ */
+
+_GLOBAL(flush_icache_range)
+
+/*
+ * Flush the data cache to memory 
+ * 
+ * Different systems have different cache line sizes
+ * and in some cases i-cache and d-cache line sizes differ from
+ * each other.
+ */
+	LOADADDR(r10,naca)		/* Get Naca address */
+	ld	r10,0(r10)
+	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get cache line size */
+	addi	r5,r7,-1
+	andc	r6,r3,r5		/* round low to line bdy */
+	subf	r8,r6,r4		/* compute length */
+	add	r8,r8,r5		/* ensure we get enough */
+	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
+	srw.	r8,r8,r9		/* compute line count */
+	beqlr				/* nothing to do? */
+	mtctr	r8
+1:	dcbst	0,r6
+	add	r6,r6,r7
+	bdnz	1b
+	sync
+
+/* Now invalidate the instruction cache */
+	
+	lhz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
+	addi	r5,r7,-1
+	andc	r6,r3,r5		/* round low to line bdy */
+	subf	r8,r6,r4		/* compute length */
+	add	r8,r8,r5
+	lhz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
+	srw.	r8,r8,r9		/* compute line count */
+	beqlr				/* nothing to do? */
+	mtctr	r8
+2:	icbi	0,r6
+	add	r6,r6,r7
+	bdnz	2b
+	isync
+	blr
+	
+/*
+ * Like above, but only do the D-cache.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ *
+ *    flush all bytes from start to stop-1 inclusive
+ */
+_GLOBAL(flush_dcache_range)
+
+/*
+ * Flush the data cache to memory 
+ * 
+ * Different systems have different cache line sizes
+ */
+	LOADADDR(r10,naca)		/* Get Naca address */
+	ld	r10,0(r10)
+	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
+	addi	r5,r7,-1
+	andc	r6,r3,r5		/* round low to line bdy */
+	subf	r8,r6,r4		/* compute length */
+	add	r8,r8,r5		/* ensure we get enough */
+	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
+	srw.	r8,r8,r9		/* compute line count */
+	beqlr				/* nothing to do? */
+	mtctr	r8
+0:	dcbst	0,r6
+	add	r6,r6,r7
+	bdnz	0b
+	sync
+	blr
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ *	void __flush_dcache_icache(void *page)
+ */
+_GLOBAL(__flush_dcache_icache)
+/*
+ * Flush the data cache to memory 
+ * 
+ * Different systems have different cache line sizes
+ */
+
+/* Flush the dcache */
+	LOADADDR(r7,naca)
+	ld	r7,0(r7)
+	clrrdi	r3,r3,12           	    /* Page align */
+	lhz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
+	lhz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
+	mr	r6,r3
+	mtctr	r4
+0:	dcbst	0,r6
+	add	r6,r6,r5
+	bdnz	0b
+	sync
+
+/* Now invalidate the icache */	
+
+	lhz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
+	lhz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
+	mtctr	r4
+1:	icbi	0,r3
+	add	r3,r3,r5
+	bdnz	1b
+	isync
+	blr
+	
+/*
+ * Copy a whole page.  Assumes a 4096B page size.
+ */
+_GLOBAL(copy_page)
+	clrrdi	r3,r3,12           	    /* Page align */
+	clrrdi	r4,r4,12           	    /* Page align */
+	li	r5,256
+	mtctr	r5
+	addi	r3,r3,-8
+	addi	r4,r4,-8
+
+1:      ld 	r6,8(r4)
+        ldu	r7,16(r4)
+	std     r6,8(r3) 
+	stdu    r7,16(r3) 
+	bdnz+	1b
+	blr  
+
+/*
+ * I/O string operations
+ *
+ * insb(port, buf, len)
+ * outsb(port, buf, len)
+ * insw(port, buf, len)
+ * outsw(port, buf, len)
+ * insl(port, buf, len)
+ * outsl(port, buf, len)
+ * insw_ns(port, buf, len)
+ * outsw_ns(port, buf, len)
+ * insl_ns(port, buf, len)
+ * outsl_ns(port, buf, len)
+ *
+ * The *_ns versions don't do byte-swapping.
+ */
+_GLOBAL(_insb)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,1
+	blelr-
+00:	lbz	r5,0(r3)
+	eieio
+	stbu	r5,1(r4)
+	bdnz	00b
+	blr
+
+_GLOBAL(_outsb)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,1
+	blelr-
+00:	lbzu	r5,1(r4)
+	stb	r5,0(r3)
+	eieio
+	bdnz	00b
+	blr	
+
+_GLOBAL(_insw)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,2
+	blelr-
+00:	lhbrx	r5,0,r3
+	eieio
+	sthu	r5,2(r4)
+	bdnz	00b
+	blr
+
+_GLOBAL(_outsw)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,2
+	blelr-
+00:	lhzu	r5,2(r4)
+	eieio
+	sthbrx	r5,0,r3	
+	bdnz	00b
+	blr	
+
+_GLOBAL(_insl)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,4
+	blelr-
+00:	lwbrx	r5,0,r3
+	eieio
+	stwu	r5,4(r4)
+	bdnz	00b
+	blr
+
+_GLOBAL(_outsl)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,4
+	blelr-
+00:	lwzu	r5,4(r4)
+	stwbrx	r5,0,r3
+	eieio
+	bdnz	00b
+	blr	
+
+_GLOBAL(ide_insw)
+_GLOBAL(_insw_ns)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,2
+	blelr-
+00:	lhz	r5,0(r3)
+	eieio
+	sthu	r5,2(r4)
+	bdnz	00b
+	blr
+
+_GLOBAL(ide_outsw)
+_GLOBAL(_outsw_ns)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,2
+	blelr-
+00:	lhzu	r5,2(r4)
+	sth	r5,0(r3)
+	eieio
+	bdnz	00b
+	blr	
+
+_GLOBAL(_insl_ns)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,4
+	blelr-
+00:	lwz	r5,0(r3)
+	eieio
+	stwu	r5,4(r4)
+	bdnz	00b
+	blr
+
+_GLOBAL(_outsl_ns)
+	cmpwi	0,r5,0
+	mtctr	r5
+	subi	r4,r4,4
+	blelr-
+00:	lwzu	r5,4(r4)
+	stw	r5,0(r3)
+	eieio
+	bdnz	00b
+	blr	
+
+/*
+ * Extended precision shifts
+ *
+ * R3/R4 has 64 bit value
+ * R5    has shift count
+ * result in R3/R4
+ *
+ *  ashrdi3:     XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ
+ *  ashldi3:     XXXYYY/ZZZAAA -> YYYZZZ/AAA000
+ *  lshrdi3:     XXXYYY/ZZZAAA -> 000XXX/YYYZZZ
+ */
+/* MIKEC: These may no longer be needed...what does gcc expect ? */
+	
+_GLOBAL(__ashrdi3)
+	li	r6,32
+	sub	r6,r6,r5
+	slw	r7,r3,r6	/* isolate YYY */
+	srw	r4,r4,r5	/* isolate ZZZ */
+	or	r4,r4,r7	/* YYYZZZ */
+	sraw	r3,r3,r5	/* SSSXXX */
+	blr
+
+_GLOBAL(__ashldi3)
+	li	r6,32
+	sub	r6,r6,r5
+	srw	r7,r4,r6	/* isolate ZZZ */
+	slw	r4,r4,r5	/* AAA000 */
+	slw	r3,r3,r5	/* YYY--- */
+	or	r3,r3,r7	/* YYYZZZ */
+	blr
+
+_GLOBAL(__lshrdi3)
+	li	r6,32
+	sub	r6,r6,r5
+	slw	r7,r3,r6        /* isolate YYY */
+	srw	r4,r4,r5        /* isolate ZZZ */
+	or	r4,r4,r7        /* YYYZZZ */
+	srw	r3,r3,r5        /* 000XXX */
+	blr
+
+_GLOBAL(abs)
+	cmpi	0,r3,0
+	bge	10f
+	neg	r3,r3
+10:	blr
+
+_GLOBAL(_get_SP)
+	mr	r3,r1		/* Close enough */
+	blr
+	
+_GLOBAL(_get_PVR)
+	mfspr	r3,PVR
+	blr
+
+_GLOBAL(_get_PIR)
+	mfspr	r3,PIR
+	blr
+
+_GLOBAL(_get_HID0)
+	mfspr	r3,HID0
+	blr
+
+_GLOBAL(cvt_fd)
+	lfd	0,-4(r5)	/* load up fpscr value */
+	mtfsf	0xff,0
+	lfs	0,0(r3)
+	stfd	0,0(r4)
+	mffs	0		/* save new fpscr value */
+	stfd	0,-4(r5)
+	blr
+
+_GLOBAL(cvt_df)
+	lfd	0,-4(r5)	/* load up fpscr value */
+	mtfsf	0xff,0
+	lfd	0,0(r3)
+	stfs	0,0(r4)
+	mffs	0		/* save new fpscr value */
+	stfd	0,-4(r5)
+	blr
+
+/*
+ * Create a kernel thread
+ *   kernel_thread(fn, arg, flags)
+ */
+_GLOBAL(kernel_thread)
+	mr	r6,r3		/* function */
+	ori	r3,r5,CLONE_VM	/* flags */
+	li	r0,__NR_clone
+	sc
+	cmpi	0,r3,0		/* parent or child? */
+	bnelr			/* return if parent */
+
+	li	r0,0		/* clear out p->thread.regs */
+	std	r0,THREAD+PT_REGS(r13)	/* since we don't have user ctx */
+	li	r0,RUN_FLAG		/* Run light on */
+	std	r0,THREAD+THREAD_FLAGS(r13)
+
+	ld	r2,8(r6)
+	ld	r6,0(r6)
+	mtlr	r6              /* fn addr in lr */
+	mr	r3,r4	        /* load arg and call fn */
+	blrl
+	li	r0,__NR_exit	/* exit after child exits */
+        li	r3,0
+	sc
+
+#ifdef CONFIG_BINFMT_ELF32
+/* Why isn't this a) automatic, b) written in 'C'? */	
+	.data
+	.align 8
+_GLOBAL(sys_call_table32)
+	.llong .sys_ni_syscall	/* 0  -  old "setup()" system call */
+	.llong .sys32_exit
+	.llong .sys32_fork
+	.llong .sys_read
+	.llong .sys_write
+	.llong .sys32_open		/* 5 */
+	.llong .sys_close
+	.llong .sys32_waitpid
+	.llong .sys32_creat
+	.llong .sys_link
+	.llong .sys_unlink      	/* 10 */
+	.llong .sys32_execve
+	.llong .sys_chdir
+	.llong .sys32_time
+	.llong .sys32_mknod
+	.llong .sys32_chmod		/* 15 */
+	.llong .sys_lchown
+	.llong .sys_ni_syscall			/* old break syscall holder */
+	.llong .sys32_stat
+	.llong .sys32_lseek
+	.llong .sys_getpid              /* 20 */
+	.llong .sys32_mount
+	.llong .sys_oldumount
+	.llong .sys_setuid
+	.llong .sys_getuid
+	.llong .ppc64_sys32_stime       /* 25 */
+	.llong .sys32_ptrace
+	.llong .sys_alarm
+	.llong .sys32_fstat
+	.llong .sys32_pause
+	.llong .sys32_utime		/* 30 */
+	.llong .sys_ni_syscall			/* old stty syscall holder */
+	.llong .sys_ni_syscall			/* old gtty syscall holder */
+	.llong .sys32_access
+	.llong .sys32_nice
+	.llong .sys_ni_syscall	/* 35 */	/* old ftime syscall holder */
+	.llong .sys_sync
+	.llong .sys32_kill
+	.llong .sys_rename
+	.llong .sys32_mkdir
+	.llong .sys_rmdir		/* 40 */
+	.llong .sys_dup
+	.llong .sys_pipe
+	.llong .sys32_times
+	.llong .sys_ni_syscall			/* old prof syscall holder */
+	.llong .sys_brk		/* 45 */
+	.llong .sys_setgid
+	.llong .sys_getgid
+	.llong .sys_signal
+	.llong .sys_geteuid
+	.llong .sys_getegid  	/* 50 */
+	.llong .sys_acct
+	.llong .sys32_umount			/* recycled never used phys() */
+	.llong .sys_ni_syscall			/* old lock syscall holder */
+	.llong .sys32_ioctl
+	.llong .sys32_fcntl		/* 55 */
+	.llong .sys_ni_syscall			/* old mpx syscall holder */
+	.llong .sys32_setpgid
+	.llong .sys_ni_syscall			/* old ulimit syscall holder */
+	.llong .sys_olduname
+	.llong .sys32_umask		/* 60 */
+	.llong .sys_chroot
+	.llong .sys_ustat
+	.llong .sys_dup2
+	.llong .sys_getppid
+	.llong .sys_getpgrp	        /* 65 */
+	.llong .sys_setsid
+	.llong .sys32_sigaction
+	.llong .sys_sgetmask
+	.llong .sys32_ssetmask
+	.llong .sys_setreuid	        /* 70 */
+	.llong .sys_setregid
+	.llong .sys_sigsuspend
+	.llong .sys32_sigpending
+	.llong .sys32_sethostname
+	.llong .sys32_setrlimit	        /* 75 */
+	.llong .sys32_old_getrlimit
+	.llong .sys32_getrusage
+	.llong .sys32_gettimeofday
+	.llong .sys32_settimeofday
+	.llong .sys32_getgroups	        /* 80 */
+	.llong .sys32_setgroups
+	.llong .ppc32_select
+	.llong .sys_symlink
+	.llong .sys32_lstat
+	.llong .sys32_readlink	        /* 85 */
+	.llong .sys_uselib
+	.llong .sys32_swapon
+	.llong .sys32_reboot
+	.llong .old32_readdir
+	.llong .sys32_mmap		/* 90 */
+	.llong .sys_munmap
+	.llong .sys_truncate
+	.llong .sys_ftruncate
+	.llong .sys_fchmod
+	.llong .sys_fchown              /* 95 */
+	.llong .sys32_getpriority
+	.llong .sys32_setpriority
+	.llong .sys_ni_syscall			/* old profil syscall holder */
+	.llong .sys32_statfs
+	.llong .sys32_fstatfs	/* 100 */
+	.llong .sys32_ioperm
+	.llong .sys32_socketcall
+	.llong .sys32_syslog
+	.llong .sys32_setitimer
+	.llong .sys32_getitimer	/* 105 */
+	.llong .sys32_newstat
+	.llong .sys32_newlstat
+	.llong .sys32_newfstat
+	.llong .sys_uname
+	.llong .sys32_iopl		/* 110 */
+	.llong .sys_vhangup
+	.llong .sys_ni_syscall	/* old 'idle' syscall */
+	.llong .sys32_vm86
+	.llong .sys32_wait4
+	.llong .sys_swapoff	/* 115 */
+	.llong .sys32_sysinfo
+	.llong .sys32_ipc
+	.llong .sys_fsync
+	.llong .ppc32_sigreturn
+	.llong .sys32_clone		/* 120 */
+	.llong .sys32_setdomainname
+	.llong .ppc64_newuname
+	.llong .sys32_modify_ldt
+	.llong .sys32_adjtimex
+	.llong .sys_mprotect	/* 125 */
+	.llong .sys32_sigprocmask
+	.llong .sys32_create_module
+	.llong .sys32_init_module
+	.llong .sys32_delete_module
+	.llong .sys32_get_kernel_syms	/* 130 */
+	.llong .sys32_quotactl
+	.llong .sys32_getpgid
+	.llong .sys_fchdir
+	.llong .sys32_bdflush
+	.llong .sys32_sysfs		/* 135 */
+	.llong .sys32_personality
+	.llong .sys_ni_syscall	        /* for afs_syscall */
+	.llong .sys_setfsuid
+	.llong .sys_setfsgid
+	.llong .sys_llseek	        /* 140 */
+        .llong .sys32_getdents
+	.llong .ppc32_select
+	.llong .sys_flock
+	.llong .sys32_msync
+	.llong .sys32_readv		/* 145 */
+	.llong .sys32_writev
+	.llong .sys32_getsid
+	.llong .sys_fdatasync
+	.llong .sys32_sysctl
+	.llong .sys_mlock		/* 150 */
+	.llong .sys_munlock
+	.llong .sys32_mlockall
+	.llong .sys_munlockall
+	.llong .sys32_sched_setparam
+	.llong .sys32_sched_getparam	/* 155 */
+	.llong .sys32_sched_setscheduler
+	.llong .sys32_sched_getscheduler
+	.llong .sys_sched_yield
+	.llong .sys32_sched_get_priority_max
+	.llong .sys32_sched_get_priority_min  /* 160 */
+	.llong .sys32_sched_rr_get_interval
+	.llong .sys32_nanosleep
+	.llong .sys32_mremap
+	.llong .sys_setresuid
+	.llong .sys_getresuid	        /* 165 */
+	.llong .sys32_query_module
+	.llong .sys_poll
+	.llong .sys32_nfsservctl
+	.llong .sys_setresgid
+	.llong .sys_getresgid	        /* 170 */
+	.llong .sys32_prctl
+	.llong .ppc32_rt_sigreturn
+	.llong .sys32_rt_sigaction
+	.llong .sys32_rt_sigprocmask
+	.llong .sys32_rt_sigpending     /* 175 */
+	.llong .sys32_rt_sigtimedwait
+	.llong .sys32_rt_sigqueueinfo
+	.llong .sys32_rt_sigsuspend
+	.llong .sys32_pread
+	.llong .sys32_pwrite	        /* 180 */
+	.llong .sys_chown
+	.llong .sys_getcwd
+	.llong .sys_capget
+	.llong .sys_capset
+	.llong .sys32_sigaltstack	        /* 185 */
+	.llong .sys32_sendfile
+	.llong .sys_ni_syscall		/* streams1 */
+	.llong .sys_ni_syscall		/* streams2 */
+	.llong .sys32_vfork
+	.llong .sys32_getrlimit	        /* 190 */
+	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
+	.llong .sys32_truncate64	/* 193 - truncate64 */
+	.llong .sys32_ftruncate64	/* 194 - ftruncate64 */
+	.llong .sys_stat64      	/* 195 - stat64 */
+	.llong .sys_lstat64     	/* 196 - lstat64 */
+	.llong .sys_fstat64		/* 197 - fstat64 */
+	.llong .sys32_pciconfig_read  	/* 198 */
+	.llong .sys32_pciconfig_write  	/* 199 */
+	.llong .sys_pciconfig_iobase 	/* 200 */
+	.llong .sys_ni_syscall		/* 201 - reserved - MacOnLinux - new */
+	.llong .sys_getdents64		/* 202 */
+	.llong .sys_pivot_root		/* 203 */
+	.llong .sys32_fcntl64		/* 204 */
+	.llong .sys_madvise		/* 205 */
+	.llong .sys_mincore		/* 206 */
+	.rept NR_syscalls-206
+		.llong .sys_ni_syscall
+	.endr
+#endif
+	.data
+	.align 8
+_GLOBAL(sys_call_table)
+	.llong .sys_ni_syscall	/* 0  -  old "setup()" system call */
+	.llong .sys_exit
+	.llong .sys_fork
+	.llong .sys_read
+	.llong .sys_write
+	.llong .sys_open		/* 5 */
+	.llong .sys_close
+	.llong .sys_waitpid
+	.llong .sys_creat
+	.llong .sys_link
+	.llong .sys_unlink	/* 10 */
+	.llong .sys_execve
+	.llong .sys_chdir
+	.llong .sys64_time
+	.llong .sys_mknod
+	.llong .sys_chmod		/* 15 */
+	.llong .sys_lchown
+	.llong .sys_ni_syscall			/* old break syscall holder */
+	.llong .sys_stat
+	.llong .sys_lseek
+	.llong .sys_getpid	/* 20 */
+	.llong .sys_mount
+	.llong .sys_oldumount
+	.llong .sys_setuid
+	.llong .sys_getuid
+	.llong .ppc64_sys_stime		/* 25 */
+	.llong .sys_ptrace
+	.llong .sys_alarm
+	.llong .sys_fstat
+	.llong .sys_pause
+	.llong .sys_utime		/* 30 */
+	.llong .sys_ni_syscall			/* old stty syscall holder */
+	.llong .sys_ni_syscall			/* old gtty syscall holder */
+	.llong .sys_access
+	.llong .sys_nice
+	.llong .sys_ni_syscall	/* 35 */	/* old ftime syscall holder */
+	.llong .sys_sync
+	.llong .sys_kill
+	.llong .sys_rename
+	.llong .sys_mkdir
+	.llong .sys_rmdir		/* 40 */
+	.llong .sys_dup
+	.llong .sys_pipe
+	.llong .sys_times
+	.llong .sys_ni_syscall			/* old prof syscall holder */
+	.llong .sys_brk		/* 45 */
+	.llong .sys_setgid
+	.llong .sys_getgid
+	.llong .sys_signal
+	.llong .sys_geteuid
+	.llong .sys_getegid	/* 50 */
+	.llong .sys_acct
+	.llong .sys_umount			/* recycled never used phys() */
+	.llong .sys_ni_syscall			/* old lock syscall holder */
+	.llong .sys_ioctl
+	.llong .sys_fcntl		/* 55 */
+	.llong .sys_ni_syscall			/* old mpx syscall holder */
+	.llong .sys_setpgid
+	.llong .sys_ni_syscall			/* old ulimit syscall holder */
+	.llong .sys_olduname
+	.llong .sys_umask		/* 60 */
+	.llong .sys_chroot
+	.llong .sys_ustat
+	.llong .sys_dup2
+	.llong .sys_getppid
+	.llong .sys_getpgrp	/* 65 */
+	.llong .sys_setsid
+	.llong .sys_sigaction
+	.llong .sys_sgetmask
+	.llong .sys_ssetmask
+	.llong .sys_setreuid	/* 70 */
+	.llong .sys_setregid
+	.llong .sys_sigsuspend
+	.llong .sys_sigpending
+	.llong .sys_sethostname
+	.llong .sys_setrlimit	/* 75 */
+	.llong .sys_old_getrlimit
+	.llong .sys_getrusage
+	.llong .sys_gettimeofday
+	.llong .sys_settimeofday
+	.llong .sys_getgroups	/* 80 */
+	.llong .sys_setgroups
+	.llong .sys_select
+	.llong .sys_symlink
+	.llong .sys_lstat
+	.llong .sys_readlink	/* 85 */
+	.llong .sys_uselib
+	.llong .sys_swapon
+	.llong .sys_reboot
+	.llong .old_readdir
+	.llong .sys_mmap	/* 90 */
+	.llong .sys_munmap
+	.llong .sys_truncate
+	.llong .sys_ftruncate
+	.llong .sys_fchmod
+	.llong .sys_fchown	/* 95 */
+	.llong .sys_getpriority
+	.llong .sys_setpriority
+	.llong .sys_ni_syscall			/* old profil syscall holder */
+	.llong .sys_statfs
+	.llong .sys_fstatfs	/* 100 */
+	.llong .sys_ioperm
+	.llong .sys_socketcall
+	.llong .sys_syslog
+	.llong .sys_setitimer
+	.llong .sys_getitimer	/* 105 */
+	.llong .sys_newstat
+	.llong .sys_newlstat
+	.llong .sys_newfstat
+	.llong .sys_uname
+	.llong .sys_iopl		/* 110 */
+	.llong .sys_vhangup
+	.llong .sys_ni_syscall	/* old 'idle' syscall */
+	.llong .sys_vm86
+	.llong .sys_wait4
+	.llong .sys_swapoff	/* 115 */
+	.llong .sys_sysinfo
+	.llong .sys_ipc
+	.llong .sys_fsync
+	.llong .ppc64_sigreturn
+	.llong .sys_clone		/* 120 */
+	.llong .sys_setdomainname
+	.llong .ppc64_newuname
+	.llong .sys_modify_ldt
+	.llong .sys_adjtimex
+	.llong .sys_mprotect	/* 125 */
+	.llong .sys_sigprocmask
+	.llong .sys_create_module
+	.llong .sys_init_module
+	.llong .sys_delete_module
+	.llong .sys_get_kernel_syms	/* 130 */
+	.llong .sys_quotactl
+	.llong .sys_getpgid
+	.llong .sys_fchdir
+	.llong .sys_bdflush
+	.llong .sys_sysfs		/* 135 */
+	.llong .sys_personality
+	.llong .sys_ni_syscall	        /* for afs_syscall */
+	.llong .sys_setfsuid
+	.llong .sys_setfsgid
+	.llong .sys_llseek	        /* 140 */
+        .llong .sys_getdents
+	.llong .sys_select
+	.llong .sys_flock
+	.llong .sys_msync
+	.llong .sys_readv		/* 145 */
+	.llong .sys_writev
+	.llong .sys_getsid
+	.llong .sys_fdatasync
+	.llong .sys_sysctl
+	.llong .sys_mlock		/* 150 */
+	.llong .sys_munlock
+	.llong .sys_mlockall
+	.llong .sys_munlockall
+	.llong .sys_sched_setparam
+	.llong .sys_sched_getparam	/* 155 */
+	.llong .sys_sched_setscheduler
+	.llong .sys_sched_getscheduler
+	.llong .sys_sched_yield
+	.llong .sys_sched_get_priority_max
+	.llong .sys_sched_get_priority_min  /* 160 */
+	.llong .sys_sched_rr_get_interval
+	.llong .sys_nanosleep
+	.llong .sys_mremap
+	.llong .sys_setresuid
+	.llong .sys_getresuid	        /* 165 */
+	.llong .sys_query_module
+	.llong .sys_poll
+	.llong .sys_nfsservctl
+	.llong .sys_setresgid
+	.llong .sys_getresgid	        /* 170 */
+	.llong .sys_prctl
+	.llong .ppc64_rt_sigreturn
+	.llong .sys_rt_sigaction
+	.llong .sys_rt_sigprocmask	
+	.llong .sys_rt_sigpending	/* 175 */
+	.llong .sys_rt_sigtimedwait
+	.llong .sys_rt_sigqueueinfo
+	.llong .sys_rt_sigsuspend
+	.llong .sys_pread
+	.llong .sys_pwrite	        /* 180 */
+	.llong .sys_chown
+	.llong .sys_getcwd
+	.llong .sys_capget
+	.llong .sys_capset
+	.llong .sys_sigaltstack	        /* 185 */
+	.llong .sys_sendfile
+	.llong .sys_ni_syscall		/* streams1 */
+	.llong .sys_ni_syscall		/* streams2 */
+	.llong .sys_vfork
+	.llong .sys_getrlimit	        /* 190 */
+	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
+	.llong .sys_ni_syscall		/* 193 - reserved - truncate64 */
+	.llong .sys_ni_syscall		/* 194 - reserved - ftruncate64 */
+	.llong .sys_ni_syscall		/* 195 - reserved - stat64 */
+	.llong .sys_ni_syscall		/* 196 - reserved - lstat64 */
+	.llong .sys_ni_syscall		/* 197 - reserved - fstat64 */
+	.llong .sys_pciconfig_read	/* 198 */
+	.llong .sys_pciconfig_write 	/* 199 */
+	.llong .sys_pciconfig_iobase 	/* 200 */
+	.llong .sys_ni_syscall		/* 201 - reserved - MacOnLinux - new */
+	.llong .sys_getdents64		/* 202 */
+	.llong .sys_pivot_root		/* 203 */
+	.llong .sys_ni_syscall		/* 204 */
+	.llong .sys_madvise		/* 205 */
+	.llong .sys_mincore		/* 206 */
+	.rept NR_syscalls-206
+	.llong .sys_ni_syscall
+	.endr
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/mk_defs.c linux-2.4.19-pre5/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/mk_defs.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/mk_defs.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,159 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ *
+ * 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 <stddef.h>
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+
+#include <asm/Naca.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+
+#define DEFINE(sym, val) \
+	        asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
+
+int
+main(void)
+{
+	DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
+	DEFINE(THREAD, offsetof(struct task_struct, thread));
+	DEFINE(MM, offsetof(struct task_struct, mm));
+	DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
+	DEFINE(KSP, offsetof(struct thread_struct, ksp));
+
+        DEFINE(PACA, offsetof(struct Naca, paca));
+        DEFINE(PACA_SIZE, sizeof(struct Paca));
+
+        DEFINE(DCACHEL1LINESIZE, offsetof(struct Naca, dCacheL1LineSize));
+        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct Naca, dCacheL1LogLineSize));
+        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct Naca, dCacheL1LinesPerPage));
+
+        DEFINE(ICACHEL1LINESIZE, offsetof(struct Naca, iCacheL1LineSize));
+        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct Naca, iCacheL1LogLineSize));
+        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct Naca, iCacheL1LinesPerPage));
+	DEFINE(SLBSIZE, offsetof(struct Naca, slb_size));
+
+        DEFINE(PACAPACAINDEX, offsetof(struct Paca, xPacaIndex));
+        DEFINE(PACAPROCSTART, offsetof(struct Paca, xProcStart));
+        DEFINE(PACAKSAVE, offsetof(struct Paca, xKsave));
+	DEFINE(PACACURRENT, offsetof(struct Paca, xCurrent));
+        DEFINE(PACASAVEDMSR, offsetof(struct Paca, xSavedMsr));
+        DEFINE(PACASTABREAL, offsetof(struct Paca, xStab_data.real));
+        DEFINE(PACASTABVIRT, offsetof(struct Paca, xStab_data.virt));
+	DEFINE(PACASTABRR, offsetof(struct Paca, xStab_data.next_round_robin));
+        DEFINE(PACAR1, offsetof(struct Paca, xR1));
+        DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr));
+	DEFINE(PACATOC, offsetof(struct Paca, xTOC));
+	DEFINE(PACAEXCSP, offsetof(struct Paca, exception_sp));
+	DEFINE(PACAHRDWINTSTACK, offsetof(struct Paca, xHrdIntStack));
+	DEFINE(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled));
+	DEFINE(PACAHRDWINTCOUNT, offsetof(struct Paca, xHrdIntCount));
+	DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr));
+	DEFINE(PACAPROFENABLED, offsetof(struct Paca, prof_enabled));
+	DEFINE(PACAPROFLEN, offsetof(struct Paca, prof_len));
+	DEFINE(PACAPROFSHIFT, offsetof(struct Paca, prof_shift));
+	DEFINE(PACAPROFBUFFER, offsetof(struct Paca, prof_buffer));
+	DEFINE(PACAPROFSTEXT, offsetof(struct Paca, prof_stext));
+	DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca));
+        DEFINE(LPPACA, offsetof(struct Paca, xLpPaca));
+        DEFINE(PACAREGSAV, offsetof(struct Paca, xRegSav));
+        DEFINE(PACAEXC, offsetof(struct Paca, exception_stack));
+        DEFINE(PACAGUARD, offsetof(struct Paca, guard));
+        DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
+        DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
+	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
+	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
+        DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
+        DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
+        DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
+	DEFINE(PROMENTRY, offsetof(struct prom_t, entry));
+
+	DEFINE(RTASBASE, offsetof(struct rtas_t, base));
+	DEFINE(RTASENTRY, offsetof(struct rtas_t, entry));
+	DEFINE(RTASSIZE, offsetof(struct rtas_t, size));
+
+	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
+	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+	DEFINE(PT_TRACESYS, PT_TRACESYS);
+	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
+	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
+	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
+	DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags));
+	DEFINE(PPC_FLAG_32BIT, PPC_FLAG_32BIT);
+	/* Interrupt register frame */
+	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
+	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+        /* 288 = # of volatile regs, int & fp, for leaf routines */
+        /* which do not stack a frame.  See the PPC64 ABI.       */
+        DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
+	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
+        DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+        DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+	/* Note: these symbols include _ because they overlap with special
+	 * register names
+	 */
+	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+	DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
+	DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
+
+	/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
+	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
+	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
+
+	DEFINE(CLONE_VM, CLONE_VM);
+
+	return 0;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/open_pic.c linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/open_pic.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,828 @@
+/*
+ *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#include <asm/machdep.h>
+
+#include "local_irq.h"
+#include "open_pic.h"
+#include "open_pic_defs.h"
+#include "i8259.h"
+#include <asm/ppcdebug.h>
+
+void* OpenPIC_Addr;
+static volatile struct OpenPIC *OpenPIC = NULL;
+u_int OpenPIC_NumInitSenses __initdata = 0;
+u_char *OpenPIC_InitSenses __initdata = NULL;
+extern int use_of_interrupt_tree;
+
+void find_ISUs(void);
+
+static u_int NumProcessors;
+static u_int NumSources;
+static int NumISUs;
+static int open_pic_irq_offset;
+static volatile unsigned char* chrp_int_ack_special;
+static int broken_ipi_registers;
+
+OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
+
+static void openpic_end_irq(unsigned int irq_nr);
+static void openpic_ack_irq(unsigned int irq_nr);
+static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
+
+struct hw_interrupt_type open_pic = {
+	" OpenPIC  ",
+	NULL,
+	NULL,
+	openpic_enable_irq,
+	openpic_disable_irq,
+	openpic_ack_irq,
+	openpic_end_irq,
+	openpic_set_affinity
+};
+
+#ifdef CONFIG_SMP
+static void openpic_end_ipi(unsigned int irq_nr);
+static void openpic_ack_ipi(unsigned int irq_nr);
+static void openpic_enable_ipi(unsigned int irq_nr);
+static void openpic_disable_ipi(unsigned int irq_nr);
+
+struct hw_interrupt_type open_pic_ipi = {
+	" OpenPIC  ",
+	NULL,
+	NULL,
+	openpic_enable_ipi,
+	openpic_disable_ipi,
+	openpic_ack_ipi,
+	openpic_end_ipi,
+	0
+};
+#endif /* CONFIG_SMP */
+
+unsigned int openpic_vec_ipi;
+unsigned int openpic_vec_timer;
+unsigned int openpic_vec_spurious;
+
+/*
+ *  Accesses to the current processor's openpic registers
+ */
+#ifdef CONFIG_SMP
+#define THIS_CPU		Processor[cpu]
+#define DECL_THIS_CPU		int cpu = hard_smp_processor_id()
+#define CHECK_THIS_CPU		check_arg_cpu(cpu)
+#else
+#define THIS_CPU		Processor[hard_smp_processor_id()]
+#define DECL_THIS_CPU
+#define CHECK_THIS_CPU
+#endif /* CONFIG_SMP */
+
+#if 1
+#define check_arg_ipi(ipi) \
+    if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
+	printk(KERN_ERR "open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
+#define check_arg_timer(timer) \
+    if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
+	printk(KERN_ERR "open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
+#define check_arg_vec(vec) \
+    if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
+	printk(KERN_ERR "open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
+#define check_arg_pri(pri) \
+    if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
+	printk(KERN_ERR "open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
+/*
+ * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
+ * data has probably been corrupted and we're going to panic or deadlock later
+ * anyway --Troy
+ */
+extern unsigned long* _get_SP(void);
+#define check_arg_irq(irq) \
+    if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
+      printk(KERN_ERR "open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
+      print_backtrace(_get_SP()); }
+#define check_arg_cpu(cpu) \
+    if (cpu < 0 || cpu >= OPENPIC_MAX_PROCESSORS){ \
+	printk(KERN_ERR "open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
+	print_backtrace(_get_SP()); }
+#else
+#define check_arg_ipi(ipi)	do {} while (0)
+#define check_arg_timer(timer)	do {} while (0)
+#define check_arg_vec(vec)	do {} while (0)
+#define check_arg_pri(pri)	do {} while (0)
+#define check_arg_irq(irq)	do {} while (0)
+#define check_arg_cpu(cpu)	do {} while (0)
+#endif
+
+#define GET_ISU(source)	ISU[(source) >> 4][(source) & 0xf]
+
+void __init openpic_init_IRQ(void)
+{
+        struct device_node *np;
+        int i;
+        unsigned int *addrp;
+        unsigned char* chrp_int_ack_special = 0;
+        unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
+        int nmi_irq = -1;
+#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
+        struct device_node *kbd;
+#endif
+
+        if (!(np = find_devices("pci"))
+            || !(addrp = (unsigned int *)
+                 get_property(np, "8259-interrupt-acknowledge", NULL)))
+                printk(KERN_ERR "Cannot find pci to get ack address\n");
+        else
+		chrp_int_ack_special = (unsigned char *)
+			__ioremap(addrp[prom_n_addr_cells(np)-1], 1, _PAGE_NO_CACHE);
+        /* hydra still sets OpenPIC_InitSenses to a static set of values */
+        if (OpenPIC_InitSenses == NULL) {
+                prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
+                OpenPIC_InitSenses = init_senses;
+                OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
+        }
+        openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
+        for ( i = 0 ; i < NUM_8259_INTERRUPTS  ; i++ )
+                irq_desc[i].handler = &i8259_pic;
+        i8259_init();
+}
+
+static inline u_int openpic_read(volatile u_int *addr)
+{
+	u_int val;
+
+	val = in_le32(addr);
+	return val;
+}
+
+static inline void openpic_write(volatile u_int *addr, u_int val)
+{
+	out_le32(addr, val);
+}
+
+static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
+{
+	u_int val = openpic_read(addr);
+	return val & mask;
+}
+
+static inline void openpic_writefield(volatile u_int *addr, u_int mask,
+			       u_int field)
+{
+	u_int val = openpic_read(addr);
+	openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
+{
+	openpic_writefield(addr, mask, 0);
+}
+
+static inline void openpic_setfield(volatile u_int *addr, u_int mask)
+{
+	openpic_writefield(addr, mask, mask);
+}
+
+static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
+				    u_int field)
+{
+	unsigned int loops = 100000;
+
+	openpic_setfield(addr, OPENPIC_MASK);
+	while (openpic_read(addr) & OPENPIC_ACTIVITY) {
+		if (!loops--) {
+			printk(KERN_ERR "openpic_safe_writefield timeout\n");
+			break;
+		}
+	}
+	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
+#ifdef CONFIG_SMP
+static u_int openpic_read_IPI(volatile u_int* addr)
+{
+        u_int val = 0;
+
+	if (broken_ipi_registers)
+		/* yes this is right ... bug, feature, you decide! -- tgall */
+		val = in_be32(addr);
+	else
+		val = in_le32(addr);
+
+        return val;
+}
+
+static void openpic_test_broken_IPI(void)
+{
+	u_int t;
+
+	openpic_write(&OpenPIC->Global.IPI_Vector_Priority(0), OPENPIC_MASK);
+	t = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(0));
+	if (t == le32_to_cpu(OPENPIC_MASK)) {
+		printk(KERN_INFO "OpenPIC reversed IPI registers detected\n");
+		broken_ipi_registers = 1;
+	}
+}
+
+/* because of the power3 be / le above, this is needed */
+static inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
+{
+        u_int  val = openpic_read_IPI(addr);
+        openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
+{
+        openpic_writefield_IPI(addr, mask, 0);
+}
+
+static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
+{
+        openpic_writefield_IPI(addr, mask, mask);
+}
+
+static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
+{
+	unsigned int loops = 100000;
+
+        openpic_setfield_IPI(addr, OPENPIC_MASK);
+
+        /* wait until it's not in use */
+        /* BenH: Is this code really enough ? I would rather check the result
+         *       and eventually retry ...
+         */
+        while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY) {
+		if (!loops--) {
+			printk(KERN_ERR "openpic_safe_writefield timeout\n");
+			break;
+		}
+	}
+
+        openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK);
+}
+#endif /* CONFIG_SMP */
+
+void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
+			 int programmer_switch_irq)
+{
+	u_int t, i;
+	u_int timerfreq;
+	const char *version;
+
+	if (!OpenPIC_Addr) {
+		printk(KERN_INFO "No OpenPIC found !\n");
+		return;
+	}
+	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
+
+	ppc_md.progress("openpic enter",0x122);
+
+	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
+	case 1:
+		version = "1.0";
+		break;
+	case 2:
+		version = "1.2";
+		break;
+	case 3:
+		version = "1.3";
+		break;
+	default:
+		version = "?";
+		break;
+	}
+	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
+	NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+		      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+	printk(KERN_INFO "OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
+	       version, NumProcessors, NumSources, OpenPIC);
+	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+	if (timerfreq)
+		printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHz\n",
+		       timerfreq / 1000000, timerfreq % 1000000);
+
+	if (!main_pic)
+		return;
+
+	open_pic_irq_offset = offset;
+	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
+
+	find_ISUs();
+
+	/* Initialize timer interrupts */
+	ppc_md.progress("openpic timer",0x3ba);
+	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+		/* Disabled, Priority 0 */
+		openpic_inittimer(i, 0, openpic_vec_timer+i);
+		/* No processor */
+		openpic_maptimer(i, 0);
+	}
+
+#ifdef CONFIG_SMP
+	/* Initialize IPI interrupts */
+	ppc_md.progress("openpic ipi",0x3bb);
+	openpic_test_broken_IPI();
+	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
+		/* Disabled, Priority 10..13 */
+		openpic_initipi(i, 10+i, openpic_vec_ipi+i);
+		/* IPIs are per-CPU */
+		irq_desc[openpic_vec_ipi+i].status |= IRQ_PER_CPU;
+		irq_desc[openpic_vec_ipi+i].handler = &open_pic_ipi;
+	}
+#endif
+
+	/* Initialize external interrupts */
+	ppc_md.progress("openpic ext",0x3bc);
+
+	openpic_set_priority(0xf);
+
+	/* SIOint (8259 cascade) is special */
+	if (offset) {
+		openpic_initirq(0, 8, offset, 1, 1);
+		openpic_mapirq(0, 1<<get_hard_smp_processor_id(0));
+	}
+
+	/* Init all external sources */
+	for (i = 1; i < NumSources; i++) {
+		int pri, sense;
+
+		/* the bootloader may have left it enabled (bad !) */
+		openpic_disable_irq(i+offset);
+
+		pri = (i == programmer_switch_irq)? 9: 8;
+		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
+		if (sense)
+			irq_desc[i+offset].status = IRQ_LEVEL;
+
+		/* Enabled, Priority 8 or 9 */
+		openpic_initirq(i, pri, i+offset, !sense, sense);
+		/* Processor 0 */
+		openpic_mapirq(i, 1<<get_hard_smp_processor_id(0));
+	}
+
+	/* Init descriptors */
+	for (i = offset; i < NumSources + offset; i++)
+		irq_desc[i].handler = &open_pic;
+
+	/* Initialize the spurious interrupt */
+	ppc_md.progress("openpic spurious",0x3bd);
+	openpic_set_spurious(openpic_vec_spurious);
+
+	/* Initialize the cascade */
+	if (offset) {
+		if (request_irq(offset, no_action, SA_INTERRUPT,
+				"82c59 cascade", NULL))
+			printk(KERN_ERR "Unable to get OpenPIC IRQ 0 for cascade\n");
+	}
+	openpic_set_priority(0);
+	openpic_disable_8259_pass_through();
+
+	ppc_md.progress("openpic exit",0x222);
+}
+
+void openpic_setup_ISU(int isu_num, unsigned long addr)
+{
+	if (isu_num >= OPENPIC_MAX_ISU)
+		return;
+	ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE);
+	if (isu_num >= NumISUs)
+		NumISUs = isu_num + 1;
+}
+
+void find_ISUs(void)
+{
+        /* Use /interrupt-controller/reg and
+         * /interrupt-controller/interrupt-ranges from OF device tree
+	 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
+	 * as a result
+	 * -- tgall
+         */
+
+	/* basically each ISU is a bus, and this assumes that
+	 * open_pic_isu_count interrupts per bus are possible 
+	 * ISU == Interrupt Source
+	 */
+	NumSources = NumISUs * 0x10;
+	openpic_vec_ipi = NumSources + open_pic_irq_offset;
+	openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI; 
+	openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS;
+}
+
+static inline void openpic_reset(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+}
+
+static inline void openpic_enable_8259_pass_through(void)
+{
+	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
+			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+static void openpic_disable_8259_pass_through(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+/*
+ *  Find out the current interrupt
+ */
+static u_int openpic_irq(void)
+{
+	u_int vec;
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
+				OPENPIC_VECTOR_MASK);
+	return vec;
+}
+
+static void openpic_eoi(void)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+	/* Handle PCI write posting */
+	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
+}
+
+
+static inline u_int openpic_get_priority(void)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
+}
+
+static void openpic_set_priority(u_int pri)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	check_arg_pri(pri);
+	openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+}
+
+/*
+ *  Get/set the spurious vector
+ */
+static inline u_int openpic_get_spurious(void)
+{
+	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
+				 OPENPIC_VECTOR_MASK);
+}
+
+static void openpic_set_spurious(u_int vec)
+{
+	check_arg_vec(vec);
+	openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+			   vec);
+}
+
+/*
+ * Convert a cpu mask from logical to physical cpu numbers.
+ */
+static inline u32 physmask(u32 cpumask)
+{
+	int i;
+	u32 mask = 0;
+
+	for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1)
+		mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
+	return mask;
+}
+
+void openpic_init_processor(u_int cpumask)
+{
+	openpic_write(&OpenPIC->Global.Processor_Initialization,
+		      physmask(cpumask));
+}
+
+#ifdef CONFIG_SMP
+/*
+ *  Initialize an interprocessor interrupt (and disable it)
+ *
+ *  ipi: OpenPIC interprocessor interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
+static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
+{
+	check_arg_ipi(ipi);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+/*
+ *  Send an IPI to one or more CPUs
+ *  
+ *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
+ *  and not a system-wide interrupt number
+ */
+void openpic_cause_IPI(u_int ipi, u_int cpumask)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	check_arg_ipi(ipi);
+	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
+		      physmask(cpumask));
+}
+
+void openpic_request_IPIs(void)
+{
+	int i;
+	
+	/*
+	 * Make sure this matches what is defined in smp.c for 
+	 * smp_message_{pass|recv}() or what shows up in 
+	 * /proc/interrupts will be wrong!!! --Troy */
+	
+	if (OpenPIC == NULL)
+		return;
+
+	request_irq(openpic_vec_ipi,
+		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
+	request_irq(openpic_vec_ipi+1,
+		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
+	request_irq(openpic_vec_ipi+2,
+		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
+	request_irq(openpic_vec_ipi+3,
+		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
+
+	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
+		openpic_enable_ipi(openpic_vec_ipi+i);
+}
+
+/*
+ * Do per-cpu setup for SMP systems.
+ *
+ * Get IPI's working and start taking interrupts.
+ *   -- Cort
+ */
+static spinlock_t openpic_setup_lock __initdata = SPIN_LOCK_UNLOCKED;
+
+void __init do_openpic_setup_cpu(void)
+{
+#ifdef CONFIG_IRQ_ALL_CPUS
+ 	int i;
+	u32 msk = 1 << hard_smp_processor_id();
+#endif
+
+	spin_lock(&openpic_setup_lock);
+
+#ifdef CONFIG_IRQ_ALL_CPUS
+ 	/* let the openpic know we want intrs. default affinity
+ 	 * is 0xffffffff until changed via /proc
+ 	 * That's how it's done on x86. If we want it differently, then
+ 	 * we should make sure we also change the default values of irq_affinity
+ 	 * in irq.c.
+ 	 */
+ 	for (i = 0; i < NumSources ; i++)
+		openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
+#endif /* CONFIG_IRQ_ALL_CPUS */
+ 	openpic_set_priority(0);
+
+	spin_unlock(&openpic_setup_lock);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ *  Initialize a timer interrupt (and disable it)
+ *
+ *  timer: OpenPIC timer number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
+static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
+{
+	check_arg_timer(timer);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+/*
+ *  Map a timer interrupt to one or more CPUs
+ */
+static void __init openpic_maptimer(u_int timer, u_int cpumask)
+{
+	check_arg_timer(timer);
+	openpic_write(&OpenPIC->Global.Timer[timer].Destination,
+		      physmask(cpumask));
+}
+
+
+/*
+ *
+ * All functions below take an offset'ed irq argument
+ *
+ */
+
+
+/*
+ *  Enable/disable an external interrupt source
+ *
+ *  Externally called, irq is an offseted system-wide interrupt number
+ */
+static void openpic_enable_irq(u_int irq)
+{
+	unsigned int loops = 100000;
+	check_arg_irq(irq);
+
+	openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		if (!loops--) {
+			printk(KERN_ERR "openpic_enable_irq timeout\n");
+			break;
+		}
+
+		mb(); /* sync is probably useless here */
+	} while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
+			OPENPIC_MASK));
+}
+
+static void openpic_disable_irq(u_int irq)
+{
+	u32 vp;
+	unsigned int loops = 100000;
+	
+	check_arg_irq(irq);
+
+	openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		if (!loops--) {
+			printk(KERN_ERR "openpic_disable_irq timeout\n");
+			break;
+		}
+
+		mb();  /* sync is probably useless here */
+		vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
+    			OPENPIC_MASK | OPENPIC_ACTIVITY);
+	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
+}
+
+#ifdef CONFIG_SMP
+/*
+ *  Enable/disable an IPI interrupt source
+ *  
+ *  Externally called, irq is an offseted system-wide interrupt number
+ */
+void openpic_enable_ipi(u_int irq)
+{
+	irq -= openpic_vec_ipi;
+	check_arg_ipi(irq);
+	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
+
+}
+void openpic_disable_ipi(u_int irq)
+{
+   /* NEVER disable an IPI... that's just plain wrong! */
+}
+
+#endif
+
+/*
+ *  Initialize an interrupt source (and disable it!)
+ *
+ *  irq: OpenPIC interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ *  pol: polarity (1 for positive, 0 for negative)
+ *  sense: 1 for level, 0 for edge
+ */
+static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+{
+	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
+				(pol ? OPENPIC_POLARITY_POSITIVE :
+			    		OPENPIC_POLARITY_NEGATIVE) |
+				(sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
+}
+
+/*
+ *  Map an interrupt source to one or more CPUs
+ */
+static void openpic_mapirq(u_int irq, u_int physmask)
+{
+	openpic_write(&GET_ISU(irq).Destination, physmask);
+}
+
+/*
+ *  Set the sense for an interrupt source (and disable it!)
+ *
+ *  sense: 1 for level, 0 for edge
+ */
+static inline void openpic_set_sense(u_int irq, int sense)
+{
+	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
+				OPENPIC_SENSE_LEVEL,
+				(sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+
+/* No spinlocks, should not be necessary with the OpenPIC
+ * (1 register = 1 interrupt and we have the desc lock).
+ */
+static void openpic_ack_irq(unsigned int irq_nr)
+{
+}
+
+static void openpic_end_irq(unsigned int irq_nr)
+{
+	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
+		openpic_eoi();
+}
+
+static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
+{
+	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
+}
+
+#ifdef CONFIG_SMP
+static void openpic_ack_ipi(unsigned int irq_nr)
+{
+}
+
+static void openpic_end_ipi(unsigned int irq_nr)
+{
+	/* IPIs are marked IRQ_PER_CPU. This has the side effect of
+	 * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
+	 * applying to them. We EOI them late to avoid re-entering.
+	 * however, I'm wondering if we could simply let them have the
+	 * SA_INTERRUPT flag and let them execute with all interrupts OFF.
+	 * This would have the side effect of either running cross-CPU
+	 * functions with interrupts off, or we can re-enable them explicitely
+	 * with a __sti() in smp_call_function_interrupt(), since
+	 * smp_call_function() is protected by a spinlock.
+	 * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU
+	 * function calls IPI at all but that would make a special case.
+	 */
+	openpic_eoi();
+}
+
+static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	smp_message_recv(cpl-openpic_vec_ipi, regs);
+}
+
+#endif /* CONFIG_SMP */
+
+int openpic_get_irq(struct pt_regs *regs)
+{
+	extern int i8259_irq(int cpu);
+
+	int irq = openpic_irq();
+
+	/* Management of the cascade should be moved out of here */
+        if (open_pic_irq_offset && irq == open_pic_irq_offset)
+        {
+                /*
+                 * This magic address generates a PCI IACK cycle.
+                 */
+		if ( chrp_int_ack_special )
+			irq = *chrp_int_ack_special;
+		else
+			irq = i8259_irq( smp_processor_id() );
+		openpic_eoi();
+        }
+	if (irq == openpic_vec_spurious)
+		irq = -1;
+	return irq;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/open_pic.h linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/open_pic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/open_pic.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,45 @@
+/*
+ *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ *  
+ */
+
+#ifndef _PPC64_KERNEL_OPEN_PIC_H
+#define _PPC64_KERNEL_OPEN_PIC_H
+
+#include <linux/config.h>
+
+#define OPENPIC_SIZE	0x40000
+
+/* OpenPIC IRQ controller structure */
+extern struct hw_interrupt_type open_pic;
+
+/* OpenPIC IPI controller structure */
+#ifdef CONFIG_SMP
+extern struct hw_interrupt_type open_pic_ipi;
+#endif /* CONFIG_SMP */
+
+extern u_int OpenPIC_NumInitSenses;
+extern u_char *OpenPIC_InitSenses;
+extern void* OpenPIC_Addr;
+
+/* Exported functions */
+extern void openpic_init(int, int, unsigned char *, int);
+extern void openpic_request_IPIs(void);
+extern void do_openpic_setup_cpu(void);
+extern int openpic_get_irq(struct pt_regs *regs);
+extern void openpic_init_processor(u_int cpumask);
+extern void openpic_setup_ISU(int isu_num, unsigned long addr);
+extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
+
+extern inline int openpic_to_irq(int irq)
+{
+	return irq += NUM_8259_INTERRUPTS;
+}
+/*extern int open_pic_irq_offset;*/
+#endif /* _PPC64_KERNEL_OPEN_PIC_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/open_pic_defs.h linux-2.4.19-pre5/arch/ppc64/kernel/open_pic_defs.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/open_pic_defs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/open_pic_defs.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,318 @@
+/*
+ *  linux/openpic.h -- OpenPIC definitions
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This file is based on the following documentation:
+ *
+ *	The Open Programmable Interrupt Controller (PIC)
+ *	Register Interface Specification Revision 1.2
+ *
+ *	Issue Date: October 1995
+ *
+ *	Issued jointly by Advanced Micro Devices and Cyrix Corporation
+ *
+ *	AMD is a registered trademark of Advanced Micro Devices, Inc.
+ *	Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
+ *	All Rights Reserved.
+ *
+ *  To receive a copy of this documentation, send an email to openpic@amd.com.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#ifndef _LINUX_OPENPIC_H
+#define _LINUX_OPENPIC_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+/*
+ *  OpenPIC supports up to 2048 interrupt sources and up to 32 processors
+ */
+
+#define OPENPIC_MAX_SOURCES	2048
+#define OPENPIC_MAX_PROCESSORS	32
+#define OPENPIC_MAX_ISU		32
+
+#define OPENPIC_NUM_TIMERS	4
+#define OPENPIC_NUM_IPI		4
+#define OPENPIC_NUM_PRI		16
+#define OPENPIC_NUM_VECTORS	OPENPIC_MAX_SOURCES
+
+/*
+ *  OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
+ */
+
+typedef struct _OpenPIC_Reg {
+	u_int Reg;					/* Little endian! */
+	char Pad[0xc];
+} OpenPIC_Reg;
+
+
+/*
+ *  Per Processor Registers
+ */
+
+typedef struct _OpenPIC_Processor {
+	/*
+	 *  Private Shadow Registers (for SLiC backwards compatibility)
+	 */
+	u_int IPI0_Dispatch_Shadow;			/* Write Only */
+	char Pad1[0x4];
+	u_int IPI0_Vector_Priority_Shadow;		/* Read/Write */
+	char Pad2[0x34];
+	/*
+	 *  Interprocessor Interrupt Command Ports
+	 */
+	OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI];	/* Write Only */
+	/*
+	 *  Current Task Priority Register
+	 */
+	OpenPIC_Reg _Current_Task_Priority;		/* Read/Write */
+	char Pad3[0x10];
+	/*
+	 *  Interrupt Acknowledge Register
+	 */
+	OpenPIC_Reg _Interrupt_Acknowledge;		/* Read Only */
+	/*
+	 *  End of Interrupt (EOI) Register
+	 */
+	OpenPIC_Reg _EOI;				/* Read/Write */
+	char Pad5[0xf40];
+} OpenPIC_Processor;
+
+
+    /*
+     *  Timer Registers
+     */
+
+typedef struct _OpenPIC_Timer {
+	OpenPIC_Reg _Current_Count;			/* Read Only */
+	OpenPIC_Reg _Base_Count;			/* Read/Write */
+	OpenPIC_Reg _Vector_Priority;			/* Read/Write */
+	OpenPIC_Reg _Destination;			/* Read/Write */
+} OpenPIC_Timer;
+
+
+    /*
+     *  Global Registers
+     */
+
+typedef struct _OpenPIC_Global {
+	/*
+	 *  Feature Reporting Registers
+	 */
+	OpenPIC_Reg _Feature_Reporting0;		/* Read Only */
+	OpenPIC_Reg _Feature_Reporting1;		/* Future Expansion */
+	/*
+	 *  Global Configuration Registers
+	 */
+	OpenPIC_Reg _Global_Configuration0;		/* Read/Write */
+	OpenPIC_Reg _Global_Configuration1;		/* Future Expansion */
+	/*
+	 *  Vendor Specific Registers
+	 */
+	OpenPIC_Reg _Vendor_Specific[4];
+	/*
+	 *  Vendor Identification Register
+	 */
+	OpenPIC_Reg _Vendor_Identification;		/* Read Only */
+	/*
+	 *  Processor Initialization Register
+	 */
+	OpenPIC_Reg _Processor_Initialization;		/* Read/Write */
+	/*
+	 *  IPI Vector/Priority Registers
+	 */
+	OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */
+	/*
+	 *  Spurious Vector Register
+	 */
+	OpenPIC_Reg _Spurious_Vector;			/* Read/Write */
+	/*
+	 *  Global Timer Registers
+	 */
+	OpenPIC_Reg _Timer_Frequency;			/* Read/Write */
+	OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
+	char Pad1[0xee00];
+} OpenPIC_Global;
+
+
+    /*
+     *  Interrupt Source Registers
+     */
+
+typedef struct _OpenPIC_Source {
+	OpenPIC_Reg _Vector_Priority;			/* Read/Write */
+	OpenPIC_Reg _Destination;			/* Read/Write */
+} OpenPIC_Source, *OpenPIC_SourcePtr;
+
+
+    /*
+     *  OpenPIC Register Map
+     */
+
+struct OpenPIC {
+	char Pad1[0x1000];
+	/*
+	 *  Global Registers
+	 */
+	OpenPIC_Global Global;
+	/*
+	 *  Interrupt Source Configuration Registers
+	 */
+	OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
+	/*
+	 *  Per Processor Registers
+	 */
+	OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
+};
+
+extern volatile struct OpenPIC *OpenPIC;
+
+
+/*
+ *  Current Task Priority Register
+ */
+
+#define OPENPIC_CURRENT_TASK_PRIORITY_MASK	0x0000000f
+
+/*
+ *  Who Am I Register
+ */
+
+#define OPENPIC_WHO_AM_I_ID_MASK		0x0000001f
+
+/*
+ *  Feature Reporting Register 0
+ */
+
+#define OPENPIC_FEATURE_LAST_SOURCE_MASK	0x07ff0000
+#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT	16
+#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK	0x00001f00
+#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT	8
+#define OPENPIC_FEATURE_VERSION_MASK		0x000000ff
+
+/*
+ *  Global Configuration Register 0
+ */
+
+#define OPENPIC_CONFIG_RESET			0x80000000
+#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE	0x20000000
+#define OPENPIC_CONFIG_BASE_MASK		0x000fffff
+
+/*
+ *  Vendor Identification Register
+ */
+
+#define OPENPIC_VENDOR_ID_STEPPING_MASK		0x00ff0000
+#define OPENPIC_VENDOR_ID_STEPPING_SHIFT	16
+#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK	0x0000ff00
+#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT	8
+#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK	0x000000ff
+
+/*
+ *  Vector/Priority Registers
+ */
+
+#define OPENPIC_MASK				0x80000000
+#define OPENPIC_ACTIVITY			0x40000000	/* Read Only */
+#define OPENPIC_PRIORITY_MASK			0x000f0000
+#define OPENPIC_PRIORITY_SHIFT			16
+#define OPENPIC_VECTOR_MASK			0x000007ff
+
+
+/*
+ *  Interrupt Source Registers
+ */
+
+#define OPENPIC_POLARITY_POSITIVE		0x00800000
+#define OPENPIC_POLARITY_NEGATIVE		0x00000000
+#define OPENPIC_POLARITY_MASK			0x00800000
+#define OPENPIC_SENSE_LEVEL			0x00400000
+#define OPENPIC_SENSE_EDGE			0x00000000
+#define OPENPIC_SENSE_MASK			0x00400000
+
+
+/*
+ *  Timer Registers
+ */
+
+#define OPENPIC_COUNT_MASK			0x7fffffff
+#define OPENPIC_TIMER_TOGGLE			0x80000000
+#define OPENPIC_TIMER_COUNT_INHIBIT		0x80000000
+
+
+/*
+ *  Aliases to make life simpler
+ */
+
+/* Per Processor Registers */
+#define IPI_Dispatch(i)			_IPI_Dispatch[i].Reg
+#define Current_Task_Priority		_Current_Task_Priority.Reg
+#define Interrupt_Acknowledge		_Interrupt_Acknowledge.Reg
+#define EOI				_EOI.Reg
+
+/* Global Registers */
+#define Feature_Reporting0		_Feature_Reporting0.Reg
+#define Feature_Reporting1		_Feature_Reporting1.Reg
+#define Global_Configuration0		_Global_Configuration0.Reg
+#define Global_Configuration1		_Global_Configuration1.Reg
+#define Vendor_Specific(i)		_Vendor_Specific[i].Reg
+#define Vendor_Identification		_Vendor_Identification.Reg
+#define Processor_Initialization	_Processor_Initialization.Reg
+#define IPI_Vector_Priority(i)		_IPI_Vector_Priority[i].Reg
+#define Spurious_Vector			_Spurious_Vector.Reg
+#define Timer_Frequency			_Timer_Frequency.Reg
+
+/* Timer Registers */
+#define Current_Count			_Current_Count.Reg
+#define Base_Count			_Base_Count.Reg
+#define Vector_Priority			_Vector_Priority.Reg
+#define Destination			_Destination.Reg
+
+/* Interrupt Source Registers */
+#define Vector_Priority			_Vector_Priority.Reg
+#define Destination			_Destination.Reg
+
+/*
+ *  Local (static) OpenPIC Operations
+ */
+
+
+/* Global Operations */
+static void openpic_reset(void);
+static void openpic_enable_8259_pass_through(void);
+static void openpic_disable_8259_pass_through(void);
+static u_int openpic_irq(void);
+static void openpic_eoi(void);
+static u_int openpic_get_priority(void);
+static void openpic_set_priority(u_int pri);
+static u_int openpic_get_spurious(void);
+static void openpic_set_spurious(u_int vector);
+
+#ifdef CONFIG_SMP
+/* Interprocessor Interrupts */
+static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+#endif
+
+/* Timer Interrupts */
+static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
+static void openpic_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+static void openpic_enable_irq(u_int irq);
+static void openpic_disable_irq(u_int irq);
+static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+			    int is_level);
+static void openpic_mapirq(u_int irq, u_int cpumask);
+static void openpic_set_sense(u_int irq, int sense);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_OPENPIC_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pSeries_hvCall.S linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_hvCall.S
--- linux-2.4.19-pre4/arch/ppc64/kernel/pSeries_hvCall.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_hvCall.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,70 @@
+/*
+ * arch/ppc64/kernel/pSeries_hvCall.S
+ *
+ *
+ * This file contains the generic code to perform a call to the
+ * pSeries LPAR hypervisor.
+ * NOTE: this file will go away when we move to inline this work.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include "ppc_asm.h"
+	
+/*
+ * hcall interface to pSeries LPAR
+ */
+#define HSC .long 0x44000022
+
+/* long plpar_hcall(unsigned long opcode,	 R3 
+		 unsigned long arg1,		 R4 
+		 unsigned long arg2,		 R5 
+		 unsigned long arg3,		 R6 
+		 unsigned long arg4,		 R7 
+		 unsigned long *out1,		 R8 
+		 unsigned long *out2,		 R9
+		 unsigned long *out3);		 R10
+ */
+
+	.text
+_GLOBAL(plpar_hcall)
+	mfcr	r0
+	std	r0,-8(r1)
+	stdu	r1,-32(r1)
+
+        std     r8,-8(r1)       /* Save out ptrs. */
+        std     r9,-16(r1)
+        std     r10,-24(r1)
+	
+	HSC                     /* invoke the hypervisor */
+
+        ld      r10,-8(r1)      /* Fetch r4-r7 ret args. */
+        std     r4,0(r10)
+        ld      r10,-16(r1)
+        std     r5,0(r10)
+        ld      r10,-24(r1)
+        std     r6,0(r10)
+
+	ld	r1,0(r1)
+	ld	r0,-8(r1)
+	mtcrf	0xff,r0
+	blr                     /* return r3 = status */
+
+
+/* Simple interface with no output values (other than status) */
+_GLOBAL(plpar_hcall_norets)
+	mfcr	r0
+	std	r0,-8(r1)
+	HSC                     /* invoke the hypervisor */
+	ld	r0,-8(r1)
+	mtcrf	0xff,r0
+	blr                     /* return r3 = status */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pSeries_lpar.c linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_lpar.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pSeries_lpar.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_lpar.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,905 @@
+/*
+ * pSeries_lpar.c
+ * Copyright (C) 2001 Todd Inglett, IBM Corporation
+ *
+ * pSeries LPAR support.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/processor.h>
+#include <asm/semaphore.h>
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/abs_addr.h>
+#include <asm/mmu_context.h>
+#include <asm/ppcdebug.h>
+#include <asm/pci_dma.h>
+#include <linux/pci.h>
+#include <asm/Naca.h>
+
+/* Status return values */
+#define H_Success	0
+#define H_Busy		1	/* Hardware busy -- retry later */
+#define H_Hardware	-1	/* Hardware error */
+#define H_Function	-2	/* Function not supported */
+#define H_Privilege	-3	/* Caller not privileged */
+#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
+#define H_Bad_Mode	-5	/* Illegal msr value */
+#define H_PTEG_Full	-6	/* PTEG is full */
+#define H_Not_Found	-7	/* PTE was not found" */
+#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
+
+/* Flags */
+#define H_LARGE_PAGE		(1UL<<(63-16))
+#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
+#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
+#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE		(1UL<<(63-49))
+#define H_N			(1UL<<(63-61))
+#define H_PP1			(1UL<<(63-62))
+#define H_PP2			(1UL<<(63-63))
+
+
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE		0x04
+#define H_ENTER			0x08
+#define H_READ			0x0c
+#define H_CLEAR_MOD		0x10
+#define H_CLEAR_REF		0x14
+#define H_PROTECT		0x18
+#define H_GET_TCE		0x1c
+#define H_PUT_TCE		0x20
+#define H_SET_SPRG0		0x24
+#define H_SET_DABR		0x28
+#define H_PAGE_INIT		0x2c
+#define H_SET_ASR		0x30
+#define H_ASR_ON		0x34
+#define H_ASR_OFF		0x38
+#define H_LOGICAL_CI_LOAD	0x3c
+#define H_LOGICAL_CI_STORE	0x40
+#define H_LOGICAL_CACHE_LOAD	0x44
+#define H_LOGICAL_CACHE_STORE	0x48
+#define H_LOGICAL_ICBI		0x4c
+#define H_LOGICAL_DCBF		0x50
+#define H_GET_TERM_CHAR		0x54
+#define H_PUT_TERM_CHAR		0x58
+#define H_REAL_TO_LOGICAL	0x5c
+#define H_HYPERVISOR_DATA	0x60
+#define H_EOI			0x64
+#define H_CPPR			0x68
+#define H_IPI			0x6c
+#define H_IPOLL			0x70
+#define H_XIRR			0x74
+
+#define HSC			".long 0x44000022\n"
+#define H_ENTER_r3		"li	3, 0x08\n"
+
+/* plpar_hcall() -- Generic call interface using above opcodes
+ *
+ * The actual call interface is a hypervisor call instruction with
+ * the opcode in R3 and input args in R4-R7.
+ * Status is returned in R3 with variable output values in R4-R11.
+ * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
+ * and return only two out args which MUST ALWAYS BE PROVIDED.
+ */
+long plpar_hcall(unsigned long opcode,
+		 unsigned long arg1,
+		 unsigned long arg2,
+		 unsigned long arg3,
+		 unsigned long arg4,
+		 unsigned long *out1,
+		 unsigned long *out2,
+		 unsigned long *out3);
+
+/* Same as plpar_hcall but for those opcodes that return no values
+ * other than status.  Slightly more efficient.
+ */
+long plpar_hcall_norets(unsigned long opcode, ...);
+
+
+long plpar_pte_enter(unsigned long flags,
+		     unsigned long ptex,
+		     unsigned long new_pteh, unsigned long new_ptel,
+		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy, ret;
+	ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+	return(ret);
+}
+
+long plpar_pte_remove(unsigned long flags,
+		      unsigned long ptex,
+		      unsigned long avpn,
+		      unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+}
+
+long plpar_pte_read(unsigned long flags,
+		    unsigned long ptex,
+		    unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_READ, flags, ptex, 0, 0,
+			   old_pteh_ret, old_ptel_ret, &dummy);
+}
+
+long plpar_pte_protect(unsigned long flags,
+		       unsigned long ptex,
+		       unsigned long avpn)
+{
+	return plpar_hcall_norets(H_PROTECT, flags, ptex);
+}
+
+long plpar_tce_get(unsigned long liobn,
+		   unsigned long ioba,
+		   unsigned long *tce_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0,
+			   tce_ret, &dummy, &dummy);
+}
+
+
+long plpar_tce_put(unsigned long liobn,
+		   unsigned long ioba,
+		   unsigned long tceval)
+{
+	return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
+}
+
+long plpar_get_term_char(unsigned long termno,
+			 unsigned long *len_ret,
+			 char *buf_ret)
+{
+	unsigned long *lbuf = (unsigned long *)buf_ret;  /* ToDo: alignment? */
+	return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0,
+			   len_ret, lbuf+0, lbuf+1);
+}
+
+long plpar_put_term_char(unsigned long termno,
+			 unsigned long len,
+			 const char *buffer)
+{
+	unsigned long dummy;
+	unsigned long *lbuf = (unsigned long *)buffer;  /* ToDo: alignment? */
+	return plpar_hcall(H_PUT_TERM_CHAR, termno, len,
+			   lbuf[0], lbuf[1], &dummy, &dummy, &dummy);
+}
+
+long plpar_eoi(unsigned long xirr)
+{
+	return plpar_hcall_norets(H_EOI, xirr);
+}
+
+long plpar_cppr(unsigned long cppr)
+{
+	return plpar_hcall_norets(H_CPPR, cppr);
+}
+
+long plpar_ipi(unsigned long servernum,
+	       unsigned long mfrr)
+{
+	return plpar_hcall_norets(H_IPI, servernum, mfrr);
+}
+
+long plpar_xirr(unsigned long *xirr_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_XIRR, 0, 0, 0, 0,
+			   xirr_ret, &dummy, &dummy);
+}
+
+long plpar_ipoll(unsigned long servernum, unsigned long* xirr_ret, unsigned long* mfrr_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_IPOLL, servernum, 0, 0, 0,
+			   xirr_ret, mfrr_ret, &dummy);
+}
+
+/*
+ * The following section contains code that ultimately should
+ * be put in the relavent file (htab.c, xics.c, etc).  It has
+ * been put here for the time being in order to ease maintainence
+ * of the pSeries LPAR code until it can all be put into CVS.
+ */
+static void hpte_invalidate_pSeriesLP(unsigned long slot)
+{
+	HPTE old_pte;
+	unsigned long lpar_rc;
+	unsigned long flags = 0;
+			
+	lpar_rc = plpar_pte_remove(flags,
+				   slot,
+				   0,
+				   &old_pte.dw0.dword0, 
+				   &old_pte.dw1.dword1);
+	if (lpar_rc != H_Success) BUG();
+}
+
+/* NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
+ * the low 3 bits of flags happen to line up.  So no transform is needed.
+ * We can probably optimize here and assume the high bits of newpp are
+ * already zero.  For now I am paranoid.
+ */
+static void hpte_updatepp_pSeriesLP(long slot, unsigned long newpp, unsigned long va)
+{
+	unsigned long lpar_rc;
+	unsigned long flags;
+	flags =   newpp & 3;
+	lpar_rc = plpar_pte_protect( flags,
+				     slot,
+				     0);
+	if (lpar_rc != H_Success) {
+		udbg_printf( " bad return code from pte protect rc = %lx \n", lpar_rc); 
+		for (;;);
+	}
+}
+
+static void hpte_updateboltedpp_pSeriesLP(unsigned long newpp, unsigned long ea)
+{
+	unsigned long lpar_rc;
+	unsigned long vsid,va,vpn,flags;
+	long slot;
+
+	vsid = get_kernel_vsid( ea );
+	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+	vpn = va >> PAGE_SHIFT;
+
+	slot = ppc_md.hpte_find( vpn );
+	flags =   newpp & 3;
+	lpar_rc = plpar_pte_protect( flags,
+				     slot,
+				     0);
+	if (lpar_rc != H_Success) {
+		udbg_printf( " bad return code from pte bolted protect rc = %lx \n", lpar_rc); 
+		for (;;);
+	}
+}
+
+
+static unsigned long hpte_getword0_pSeriesLP(unsigned long slot)
+{
+	unsigned long dword0;
+	unsigned long lpar_rc;
+	unsigned long dummy_word1;
+	unsigned long flags;
+	/* Read 1 pte at a time                        */
+	/* Do not need RPN to logical page translation */
+	/* No cross CEC PFT access                     */
+	flags = 0;
+	
+	lpar_rc = plpar_pte_read(flags,
+				 slot,
+				 &dword0, &dummy_word1);
+	if (lpar_rc != H_Success) {
+		udbg_printf(" error on pte read in get_hpte0 rc = %lx \n", lpar_rc);
+		for (;;);
+	}
+
+	return(dword0);
+}
+
+static long hpte_selectslot_pSeriesLP(unsigned long vpn)
+{
+	unsigned long primary_hash;
+	unsigned long hpteg_slot;
+	unsigned i, k;
+	unsigned long flags;
+	HPTE  pte_read;
+	unsigned long lpar_rc;
+
+	/* Search the primary group for an available slot */
+	primary_hash = hpt_hash(vpn, 0);
+
+	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+
+	/* Read 1 pte at a time                        */
+	/* Do not need RPN to logical page translation */
+	/* No cross CEC PFT access                     */
+	flags = 0;
+	for (i=0; i<HPTES_PER_GROUP; ++i) {
+		/* read the hpte entry from the slot */
+		lpar_rc = plpar_pte_read(flags,
+					 hpteg_slot + i,
+					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
+		if (lpar_rc != H_Success) {
+			udbg_printf(" read of hardware page table failed rc = %lx \n", lpar_rc); 
+			for (;;);
+		}
+		if ( pte_read.dw0.dw0.v == 0 ) {
+			/* If an available slot found, return it */
+			return hpteg_slot + i;
+		}
+
+	}
+
+
+	/* Search the secondary group for an available slot */
+	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+
+
+	for (i=0; i<HPTES_PER_GROUP; ++i) {
+		/* read the hpte entry from the slot */
+		lpar_rc = plpar_pte_read(flags,
+					 hpteg_slot + i,
+					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
+		if (lpar_rc != H_Success) {
+			udbg_printf(" read of hardware page table failed2 rc = %lx  \n", lpar_rc); 
+			for (;;);
+		}
+		if ( pte_read.dw0.dw0.v == 0 ) {
+			/* If an available slot found, return it */
+			return hpteg_slot + i;
+		}
+
+	}
+
+	/* No available entry found in secondary group */
+
+
+	/* Select an entry in the primary group to replace */
+
+	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+
+	k = htab_data.next_round_robin++ & 0x7;
+
+	for (i=0; i<HPTES_PER_GROUP; ++i) {
+		if (k == HPTES_PER_GROUP)
+			k = 0;
+
+		lpar_rc = plpar_pte_read(flags,
+					 hpteg_slot + k,
+					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
+		if (lpar_rc != H_Success) {
+			udbg_printf( " pte read failed - rc = %lx", lpar_rc); 
+			for (;;);
+		}
+		if (  ! pte_read.dw0.dw0.bolted)
+		{
+			hpteg_slot += k;
+			/* Invalidate the current entry */
+			ppc_md.hpte_invalidate(hpteg_slot); 
+			return hpteg_slot;
+		}
+		++k;
+	}
+
+	/* No non-bolted entry found in primary group - time to panic */
+	udbg_printf("select_hpte_slot - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
+	udbg_printf("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
+	for (;;);
+
+	/* never executes - avoid compiler errors */
+	return 0;
+}
+
+
+static void hpte_create_valid_pSeriesLP(unsigned long slot, unsigned long vpn,
+					unsigned long prpn, unsigned hash, 
+					void *ptep, unsigned hpteflags, 
+					unsigned bolted)
+{
+	/* Local copy of HPTE */
+	struct {
+		/* Local copy of first doubleword of HPTE */
+		union {
+			unsigned long d;
+			Hpte_dword0   h;
+		} dw0;
+		/* Local copy of second doubleword of HPTE */
+		union {
+			unsigned long     d;
+			Hpte_dword1       h;
+			Hpte_dword1_flags f;
+		} dw1;
+	} lhpte;
+	
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn( prpn );
+
+	unsigned long lpar_rc;
+	unsigned long flags;
+	HPTE ret_hpte;
+
+	/* Fill in the local HPTE with absolute rpn, avpn and flags */
+	lhpte.dw1.d        = 0;
+	lhpte.dw1.h.rpn    = arpn;
+	lhpte.dw1.f.flags  = hpteflags;
+
+	lhpte.dw0.d        = 0;
+	lhpte.dw0.h.avpn   = avpn;
+	lhpte.dw0.h.h      = hash;
+	lhpte.dw0.h.bolted = bolted;
+	lhpte.dw0.h.v      = 1;
+
+	/* Now fill in the actual HPTE */
+	/* Set CEC cookie to 0                  */
+	/* Large page = 0                       */
+	/* Zero page = 0                        */
+	/* I-cache Invalidate = 0               */
+	/* I-cache synchronize = 0              */
+	/* Exact = 1 - only modify exact entry  */
+	flags = H_EXACT;
+
+	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+		lhpte.dw1.f.flags &= ~_PAGE_COHERENT;
+#if 1
+	__asm__ __volatile__ (
+		 H_ENTER_r3
+		 "mr	4, %1\n"
+		 "mr	5, %2\n"
+		 "mr	6, %3\n"
+		 "mr	7, %4\n"
+		 HSC
+		 "mr	%0, 3\n"
+		 : "=r" (lpar_rc)
+		 : "r" (flags), "r" (slot), "r" (lhpte.dw0.d), "r" (lhpte.dw1.d)
+		 : "r3", "r4", "r5", "r6", "r7", "cc");
+#else
+	lpar_rc =  plpar_pte_enter(flags,
+				   slot,
+				   lhpte.dw0.d,
+				   lhpte.dw1.d,
+				   &ret_hpte.dw0.dword0,
+				   &ret_hpte.dw1.dword1);
+#endif
+	if (lpar_rc != H_Success) {
+		udbg_printf("error on pte enter lapar rc = %ld\n",lpar_rc);
+		udbg_printf("ent: s=%lx, dw0=%lx, dw1=%lx\n", slot, lhpte.dw0.d, lhpte.dw1.d);
+		/* xmon_backtrace("backtrace"); */
+		for (;;);
+	}
+}
+
+static long hpte_find_pSeriesLP(unsigned long vpn)
+{
+	union {
+		unsigned long d;
+		Hpte_dword0   h;
+	} hpte_dw0;
+	long slot;
+	unsigned long hash;
+	unsigned long i,j;
+
+	hash = hpt_hash(vpn, 0);
+	for ( j=0; j<2; ++j ) {
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
+			hpte_dw0.d = hpte_getword0_pSeriesLP( slot );
+			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
+			     ( hpte_dw0.h.v ) &&
+			     ( hpte_dw0.h.h == j ) ) {
+				/* HPTE matches */
+				if ( j )
+					slot = -slot;
+				return slot;
+			}
+			++slot;
+		}
+		hash = ~hash;
+	}
+	return -1;
+} 
+
+/*
+ * Create a pte - LPAR .  Used during initialization only.
+ * We assume the PTE will fit in the primary PTEG.
+ */
+void make_pte_LPAR(HPTE *htab,
+		   unsigned long va, unsigned long pa, int mode,
+		   unsigned long hash_mask, int large)
+{
+	HPTE  local_hpte, ret_hpte;
+	unsigned long hash, slot, flags,lpar_rc, vpn;
+
+	if (large)
+		vpn = va >> 24;
+	else
+		vpn = va >> 12;
+
+	hash = hpt_hash(vpn, large);
+
+	slot = ((hash & hash_mask)*HPTES_PER_GROUP);
+
+	local_hpte.dw1.dword1 = pa | mode;
+	local_hpte.dw0.dword0 = 0;
+	local_hpte.dw0.dw0.avpn = va >> 23;
+	local_hpte.dw0.dw0.bolted = 1;				/* bolted */
+	if (large)
+    local_hpte.dw0.dw0.l = 1;  /* large page */
+	local_hpte.dw0.dw0.v = 1;
+
+	/* Set CEC cookie to 0                   */
+	/* Zero page = 0                         */
+	/* I-cache Invalidate = 0                */
+	/* I-cache synchronize = 0               */
+	/* Exact = 0 - modify any entry in group */
+	flags = 0;
+#if 1
+	__asm__ __volatile__ (
+		 H_ENTER_r3
+		 "mr	4, %1\n"
+		 "mr	5, %2\n"
+		 "mr	6, %3\n"
+		 "mr	7, %4\n"
+		 HSC
+		 "mr	%0, 3\n"
+		 : "=r" (lpar_rc)
+		 : "r" (flags), "r" (slot), "r" (local_hpte.dw0.dword0), "r" (local_hpte.dw1.dword1)
+		 : "r3", "r4", "r5", "r6", "r7", "cc");
+#else
+	lpar_rc =  plpar_pte_enter(flags,
+				   slot,
+				   local_hpte.dw0.dword0,
+				   local_hpte.dw1.dword1,
+				   &ret_hpte.dw0.dword0,
+				   &ret_hpte.dw1.dword1);
+#endif
+#if 0 /* NOTE: we explicitly do not check return status here because it is
+       * "normal" for early boot code to map io regions for which a partition
+       * has no access.  However, we will die if we actually fault on these
+       * "permission denied" pages.
+       */
+	if (lpar_rc != H_Success) {
+		/* pSeriesLP_init_early(); */
+		udbg_printf("flags=%lx, slot=%lx, dword0=%lx, dword1=%lx, rc=%d\n", flags, slot, local_hpte.dw0.dword0,local_hpte.dw1.dword1, lpar_rc);
+		BUG();
+	}
+#endif
+}
+
+static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, 
+				unsigned long uaddr, int direction )
+{
+	u64 setTceRc;
+	union Tce tce;
+	
+	PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr);
+	PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", 
+	       tcenum, tbl, tbl->index);
+
+	tce.wholeTce = 0;
+	tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+
+	tce.tceBits.readWrite = 1;
+	if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1;
+
+	setTceRc = plpar_tce_put((u64)tbl->index, 
+				 (u64)tcenum << 12, 
+				 tce.wholeTce );
+	/* Make sure the update is visible to hardware.
+	 * ToDo: sync after setting *all* the tce's.
+	 */
+	__asm__ __volatile__ ("sync" : : : "memory");
+
+	if(setTceRc) {
+		PPCDBG(PPCDBG_TCE, "setTce failed. rc=%ld\n", setTceRc);
+		PPCDBG(PPCDBG_TCE, "\tindex   = 0x%lx\n", (u64)tbl->index);
+		PPCDBG(PPCDBG_TCE, "\ttcenum  = 0x%lx\n", (u64)tcenum);
+		PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce );
+	}
+}
+
+static inline void free_tce_range(struct TceTable *tbl, 
+				  long tcenum, unsigned order )
+{
+	unsigned long flags;
+
+	/* Lock the tce allocation bitmap */
+	spin_lock_irqsave( &(tbl->lock), flags );
+
+	/* Do the actual work */
+	free_tce_range_nolock( tbl, tcenum, order );
+	
+	/* Unlock the tce allocation bitmap */
+	spin_unlock_irqrestore( &(tbl->lock), flags );
+
+}
+
+static void tce_free_pSeriesLP(struct TceTable *tbl, dma_addr_t dma_addr, 
+			       unsigned order, unsigned numPages)
+{
+	u64 setTceRc;
+	long tcenum, freeTce, maxTcenum;
+	unsigned i;
+	union Tce tce;
+
+	maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
+	
+	tcenum = dma_addr >> PAGE_SHIFT;
+
+	freeTce = tcenum - tbl->startOffset;
+
+	if ( freeTce > maxTcenum ) {
+		printk("free_tces: tcenum > maxTcenum\n");
+		printk("\ttcenum    = 0x%lx\n", tcenum); 
+		printk("\tfreeTce   = 0x%lx\n", freeTce); 
+		printk("\tmaxTcenum = 0x%lx\n", maxTcenum); 
+		printk("\tTCE Table = 0x%lx\n", (u64)tbl);
+		printk("\tbus#      = 0x%lx\n", 
+		       (u64)tbl->busNumber );
+		printk("\tsize      = 0x%lx\n", (u64)tbl->size);
+		printk("\tstartOff  = 0x%lx\n", 
+		       (u64)tbl->startOffset );
+		printk("\tindex     = 0x%lx\n", (u64)tbl->index);
+		return;
+	}
+	
+	for (i=0; i<numPages; ++i) {
+		tce.wholeTce = 0;
+		setTceRc = plpar_tce_put((u64)tbl->index, 
+					 (u64)tcenum << 12, /* note: not freeTce */
+					 tce.wholeTce );
+		if ( setTceRc ) {
+			printk("tce_free: setTce failed\n");
+			printk("\trc      = %ld\n", setTceRc);
+			printk("\tindex   = 0x%lx\n", 
+			       (u64)tbl->index);
+			printk("\ttcenum  = 0x%lx\n", (u64)tcenum);
+			printk("\tfreeTce = 0x%lx\n", (u64)freeTce);
+			printk("\ttce val = 0x%lx\n", 
+			       tce.wholeTce );
+		}
+
+		++tcenum;
+	}
+
+	/* Make sure the update is visible to hardware. */
+	__asm__ __volatile__ ("sync" : : : "memory");
+
+	free_tce_range( tbl, freeTce, order );
+}
+
+/* PowerPC Interrupts for lpar. */
+/* NOTE: this typedef is duplicated (for now) from xics.c! */
+typedef struct {
+	int (*xirr_info_get)(int cpu);
+	void (*xirr_info_set)(int cpu, int val);
+	void (*cppr_info)(int cpu, u8 val);
+	void (*qirr_info)(int cpu, u8 val);
+} xics_ops;
+static int pSeriesLP_xirr_info_get(int n_cpu)
+{
+	unsigned long lpar_rc;
+	unsigned long return_value; 
+
+	lpar_rc = plpar_xirr(&return_value);
+	if (lpar_rc != H_Success) {
+		panic(" bad return code xirr - rc = %lx \n", lpar_rc); 
+	}
+	return ((int)(return_value));
+}
+
+static void pSeriesLP_xirr_info_set(int n_cpu, int value)
+{
+	unsigned long lpar_rc;
+	unsigned long val64 = value & 0xffffffff;
+
+	lpar_rc = plpar_eoi(val64);
+	if (lpar_rc != H_Success) {
+		panic(" bad return code EOI - rc = %ld, value=%lx \n", lpar_rc, val64); 
+	}
+}
+
+static void pSeriesLP_cppr_info(int n_cpu, u8 value)
+{
+	unsigned long lpar_rc;
+
+	lpar_rc = plpar_cppr(value);
+	if (lpar_rc != H_Success) {
+		panic(" bad return code cppr - rc = %lx \n", lpar_rc); 
+	}
+}
+
+static void pSeriesLP_qirr_info(int n_cpu , u8 value)
+{
+	unsigned long lpar_rc;
+
+	lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu),value);
+	if (lpar_rc != H_Success) {
+    udbg_printf("pSeriesLP_qirr_info - plpar_ipi failed!!!!!!!! \n");
+		panic(" bad return code qirr -ipi  - rc = %lx \n", lpar_rc); 
+	}
+}
+
+xics_ops pSeriesLP_ops = {
+	pSeriesLP_xirr_info_get,
+	pSeriesLP_xirr_info_set,
+	pSeriesLP_cppr_info,
+	pSeriesLP_qirr_info
+};
+/* end TAI-LPAR */
+
+
+int vtermno;	/* virtual terminal# for udbg  */
+
+static void udbg_putcLP(unsigned char c)
+{
+	char buf[16];
+	unsigned long rc;
+
+	if (c == '\n')
+		udbg_putcLP('\r');
+
+	buf[0] = c;
+	do {
+		rc = plpar_put_term_char(vtermno, 1, buf);
+	} while(rc == H_Busy);
+}
+
+/* Buffered chars getc */
+static long inbuflen;
+static long inbuf[2];	/* must be 2 longs */
+
+static int udbg_getc_pollLP(void)
+{
+	/* The interface is tricky because it may return up to 16 chars.
+	 * We save them statically for future calls to udbg_getc().
+	 */
+	char ch, *buf = (char *)inbuf;
+	int i;
+	long rc;
+	if (inbuflen == 0) {
+		/* get some more chars. */
+		inbuflen = 0;
+		rc = plpar_get_term_char(vtermno, &inbuflen, buf);
+		if (inbuflen == 0 && rc == H_Success)
+			return -1;
+	}
+	ch = buf[0];
+	for (i = 1; i < inbuflen; i++)	/* shuffle them down. */
+		buf[i-1] = buf[i];
+	inbuflen--;
+	return ch;
+}
+
+static unsigned char udbg_getcLP(void)
+{
+	int ch;
+	for (;;) {
+		ch = udbg_getc_pollLP();
+		if (ch == -1) {
+			/* This shouldn't be needed...but... */
+			volatile unsigned long delay;
+			for (delay=0; delay < 2000000; delay++)
+				;
+		} else {
+			return ch;
+		}
+	}
+}
+
+
+/* This is called early in setup.c.
+ * Use it to setup page table ppc_md stuff as well as udbg.
+ */
+void pSeriesLP_init_early(void)
+{
+	ppc_md.hpte_invalidate   = hpte_invalidate_pSeriesLP;
+	ppc_md.hpte_updatepp     = hpte_updatepp_pSeriesLP;
+	ppc_md.hpte_updateboltedpp  = hpte_updateboltedpp_pSeriesLP;
+	ppc_md.hpte_getword0     = hpte_getword0_pSeriesLP;
+	ppc_md.hpte_selectslot   = hpte_selectslot_pSeriesLP;
+	ppc_md.hpte_create_valid = hpte_create_valid_pSeriesLP;
+	ppc_md.hpte_find	 = hpte_find_pSeriesLP;
+
+	ppc_md.tce_build	 = tce_build_pSeriesLP;
+	ppc_md.tce_free		 = tce_free_pSeriesLP;
+
+#ifdef CONFIG_SMP
+	smp_init_pSeries();
+#endif
+	pSeries_pcibios_init_early();
+
+	/* The keyboard is not useful in the LPAR environment.
+	 * Leave all the interfaces NULL.
+	 */
+
+	if (naca->serialPortAddr) {
+		void *comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
+		udbg_init_uart(comport);
+		ppc_md.udbg_putc = udbg_putc;
+		ppc_md.udbg_getc = udbg_getc;
+		ppc_md.udbg_getc_poll = udbg_getc_poll;
+	} else {
+		/* lookup the first virtual terminal number in case we don't have a com port.
+		 * Zero is probably correct in case someone calls udbg before the init.
+		 * The property is a pair of numbers.  The first is the starting termno (the
+		 * one we use) and the second is the number of terminals.
+		 */
+		u32 *termno;
+		struct device_node *np = find_path_device("/rtas");
+		if (np) {
+			termno = (u32 *)get_property(np, "ibm,termno", 0);
+			if (termno)
+				vtermno = termno[0];
+		}
+		ppc_md.udbg_putc = udbg_putcLP;
+		ppc_md.udbg_getc = udbg_getcLP;
+		ppc_md.udbg_getc_poll = udbg_getc_pollLP;
+	}
+}
+
+/* Confidential code for hvc_console.  Should move it back eventually. */
+
+int hvc_get_chars(int index, char *buf, int count)
+{
+	unsigned long got;
+
+	if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got,
+		(unsigned long *)buf, (unsigned long *)buf+1) == H_Success) {
+		/*
+		 * Work around a HV bug where it gives us a null
+		 * after every \r.  -- paulus
+		 */
+		if (got > 0) {
+			int i;
+			for (i = 1; i < got; ++i) {
+				if (buf[i] == 0 && buf[i-1] == '\r') {
+					--got;
+					if (i < got)
+						memmove(&buf[i], &buf[i+1],
+							got - i);
+				}
+			}
+		}
+		return got;
+	}
+	return 0;
+}
+
+int hvc_put_chars(int index, const char *buf, int count)
+{
+	unsigned long dummy;
+	unsigned long *lbuf = (unsigned long *) buf;
+	long ret;
+
+	ret = plpar_hcall(H_PUT_TERM_CHAR, index, count, lbuf[0], lbuf[1],
+			  &dummy, &dummy, &dummy);
+	if (ret == H_Success)
+		return count;
+	if (ret == H_Busy)
+		return 0;
+	return -1;
+}
+
+int hvc_count(int *start_termno)
+{
+	u32 *termno;
+	struct device_node *dn;
+
+	if ((dn = find_path_device("/rtas")) != NULL) {
+		if ((termno = (u32 *)get_property(dn, "ibm,termno", 0)) != NULL) {
+			if (start_termno)
+				*start_termno = termno[0];
+			return termno[1];
+		}
+	}
+	return 0;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pSeries_pci.c linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pSeries_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pSeries_pci.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,813 @@
+/*
+ * pSeries_pci.c
+ *
+ * pSeries_pcibios_init(void)opyright (C) 2001 Dave Engebretsen, IBM Corporation
+ *
+ * pSeries specific routines for PCI.
+ * 
+ * Based on code from pci.c and chrp_pci.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *    
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/init.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppcdebug.h>
+#include <asm/Naca.h>
+#include <asm/pci_dma.h>
+#ifdef CONFIG_PPC_EEH
+#include <asm/eeh.h>
+#endif
+
+#include "xics.h"
+#include "open_pic.h"
+#include "pci.h"
+
+extern struct device_node *allnodes;
+
+/*******************************************************************
+ * Forward declares of prototypes. 
+ *******************************************************************/
+unsigned long find_and_init_phbs(void);
+struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ;
+void pSeries_pcibios_fixup(void);
+static int rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval);
+
+/* RTAS tokens */
+static int read_pci_config;
+static int write_pci_config;
+static int ibm_read_pci_config;
+static int ibm_write_pci_config;
+
+static int s7a_workaround;
+
+/******************************************************************************
+ *
+ * pSeries I/O Operations to access the PCI configuration space.
+ *
+ *****************************************************************************/
+#define RTAS_PCI_READ_OP(size, type, nbytes) \
+int __chrp \
+rtas_read_config_##size(struct device_node *dn, int offset, type val) {  \
+	unsigned long returnval = ~0L; \
+	unsigned long buid; \
+	unsigned int addr; \
+	int ret; \
+	 \
+	if (dn == NULL) { \
+		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
+	} else { \
+		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
+		buid = dn->phb->buid; \
+		if (buid) { \
+			ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \
+                        if (ret < 0) \
+                               ret = rtas_fake_read(dn, offset, nbytes, &returnval); \
+		} else { \
+			ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \
+		} \
+	} \
+	*val = returnval; \
+	return ret; \
+} \
+int __chrp \
+rtas_pci_read_config_##size(struct pci_dev *dev, int offset, type val) {  \
+        struct device_node *dn = pci_device_to_OF_node(dev); \
+	int ret = rtas_read_config_##size(dn, offset, val); \
+        /* udbg_printf("read bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \
+        return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
+}
+
+#define RTAS_PCI_WRITE_OP(size, type, nbytes) \
+int __chrp \
+rtas_write_config_##size(struct device_node *dn, int offset, type val) { \
+	unsigned long buid; \
+	unsigned int addr; \
+	int ret; \
+	 \
+	if (dn == NULL) { \
+		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
+	} else { \
+		buid = dn->phb->buid; \
+		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
+		if (buid) { \
+			ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, nbytes, (ulong) val); \
+		} else { \
+			ret = rtas_call(write_pci_config, 3, 1, NULL, addr, nbytes, (ulong)val); \
+		} \
+	} \
+	return ret; \
+} \
+int __chrp \
+rtas_pci_write_config_##size(struct pci_dev *dev, int offset, type val) { \
+	return rtas_write_config_##size(pci_device_to_OF_node(dev), offset, val); \
+}
+
+RTAS_PCI_READ_OP(byte, u8 *, 1)
+RTAS_PCI_READ_OP(word, u16 *, 2)
+RTAS_PCI_READ_OP(dword, u32 *, 4)
+RTAS_PCI_WRITE_OP(byte, u8, 1)
+RTAS_PCI_WRITE_OP(word, u16, 2)
+RTAS_PCI_WRITE_OP(dword, u32, 4)
+
+struct pci_ops rtas_pci_ops = {
+	rtas_pci_read_config_byte,
+	rtas_pci_read_config_word,
+	rtas_pci_read_config_dword,
+	rtas_pci_write_config_byte,
+ 	rtas_pci_write_config_word,
+	rtas_pci_write_config_dword,
+};
+
+/*
+ * Handle the case where rtas refuses to do a pci config read.
+ * This currently only happens with some PHBs in which case we totally fake
+ * out the values (and call it a speedwagaon -- something we could look up
+ * in the device tree).
+ */
+static int
+rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval)
+{
+	char *device_type = (char *)get_property(dn, "device_type", 0);
+	u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
+
+	*returnval = ~0;	/* float by default */
+
+	/* udbg_printf("rtas_fake_read dn=%p, offset=0x%02x, nbytes=%d, device_type=%s\n", dn, offset, nbytes, device_type ? device_type : "<none>"); */
+	if (device_type && strcmp(device_type, "pci") != 0)
+		return -3;	/* Not a phb or bridge */
+
+	/* NOTE: class_code != NULL => EADS pci bridge.  Else a PHB */
+	if (nbytes == 1) {
+		if (offset == PCI_HEADER_TYPE)
+			*returnval = 0x80;	/* multifunction */
+		else if (offset == PCI_INTERRUPT_PIN || offset == PCI_INTERRUPT_LINE)
+			*returnval = 0;
+	} else if (nbytes == 2) {
+		if (offset == PCI_SUBSYSTEM_VENDOR_ID || offset == PCI_SUBSYSTEM_ID)
+			*returnval = 0;
+		else if (offset == PCI_COMMAND)
+			*returnval = PCI_COMMAND_PARITY|PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY;
+	} else if (nbytes == 4) {
+		if (offset == PCI_VENDOR_ID)
+			*returnval = 0x1014 | ((class_code ? 0x8b : 0x102) << 16); /* a phb */
+		else if (offset == PCI_REVISION_ID)
+			*returnval = (class_code ? PCI_CLASS_BRIDGE_PCI : PCI_CLASS_BRIDGE_HOST) << 16; /* revs are zero */
+		else if ((offset >= PCI_BASE_ADDRESS_0 && offset <= PCI_BASE_ADDRESS_5) || offset == PCI_ROM_ADDRESS)
+			*returnval = 0;
+	}
+
+	/* printk("fake: %s nbytes=%d, offset=%lx ret=%lx\n", class_code ? "EADS" : "PHB", nbytes, offset, *returnval); */
+	return 0;
+}
+
+/******************************************************************
+ * pci_read_irq_line
+ *
+ * Reads the Interrupt Pin to determine if interrupt is use by card.
+ * If the interrupt is used, then gets the interrupt line from the 
+ * openfirmware and sets it in the pci_dev and pci_config line.
+ *
+ ******************************************************************/
+int 
+pci_read_irq_line(struct pci_dev *Pci_Dev)
+{
+	u8 InterruptPin;
+	struct device_node *Node;
+
+    	pci_read_config_byte(Pci_Dev, PCI_INTERRUPT_PIN, &InterruptPin);
+	if (InterruptPin == 0) {
+		PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n",Pci_Dev->slot_name);
+		return 0;	
+	}
+	Node = pci_device_to_OF_node(Pci_Dev);
+	if ( Node == NULL) { 
+		PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n",Pci_Dev->slot_name);
+		return -1;	
+	}
+	if (Node->n_intrs == 0) 	{
+		PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n",Pci_Dev->slot_name);
+		return -1;	
+	}
+	Pci_Dev->irq = Node->intrs[0].line;
+
+	if (s7a_workaround) {
+		if (Pci_Dev->irq > 16)
+			Pci_Dev->irq -= 3;
+	}
+
+	pci_write_config_byte(Pci_Dev, PCI_INTERRUPT_LINE, Pci_Dev->irq);
+	
+	PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n",Pci_Dev->slot_name,Pci_Dev->irq);
+	return 0;
+}
+
+/******************************************************************
+ * Find all PHBs in the system and initialize a set of data 
+ * structures to represent them.
+ ******************************************************************/
+unsigned long __init
+find_and_init_phbs(void)
+{
+        struct device_node *Pci_Node;
+        struct pci_controller *phb;
+        unsigned int root_addr_size_words = 0, this_addr_size_words = 0;
+	unsigned int this_addr_count = 0, range_stride;
+        unsigned int *ui_ptr = NULL, *ranges;
+        char *model;
+	struct pci_range64 range;
+	struct resource *res;
+	unsigned int memno, rlen, i, index;
+	unsigned int *opprop;
+	int has_isa = 0;
+        PPCDBG(PPCDBG_PHBINIT, "find_and_init_phbs\n"); 
+
+	read_pci_config = rtas_token("read-pci-config");
+	write_pci_config = rtas_token("write-pci-config");
+	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
+	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
+#ifdef CONFIG_PPC_EEH
+	eeh_init();
+#endif
+
+	if (naca->interrupt_controller == IC_OPEN_PIC) {
+		opprop = (unsigned int *)get_property(find_path_device("/"),
+				"platform-open-pic", NULL);
+	}
+
+	/* Get the root address word size. */
+	ui_ptr = (unsigned int *) get_property(find_path_device("/"), 
+					       "#size-cells", NULL);
+	if (ui_ptr) {
+		root_addr_size_words = *ui_ptr;
+	} else {
+		PPCDBG(PPCDBG_PHBINIT, "\tget #size-cells failed.\n"); 
+		return(-1);
+	}
+
+	if (find_type_devices("isa")) {
+		has_isa = 1;
+		PPCDBG(PPCDBG_PHBINIT, "\tFound an ISA bus.\n"); 
+	}
+
+	index = 0;
+
+	/******************************************************************
+	* Find all PHB devices and create an object for them.
+	******************************************************************/
+	for (Pci_Node = find_devices("pci"); Pci_Node != NULL; Pci_Node = Pci_Node->next) {
+		model = (char *) get_property(Pci_Node, "model", NULL);
+		if (model != NULL)  {
+			phb = alloc_phb(Pci_Node, model, root_addr_size_words);
+			if (phb == NULL) return(-1);
+		}
+		else {
+         		continue;
+		}
+		
+		/* Get this node's address word size. */
+		ui_ptr = (unsigned int *) get_property(Pci_Node, "#size-cells", NULL);
+		if (ui_ptr)
+			this_addr_size_words = *ui_ptr;
+		else
+			this_addr_size_words = 1;
+		/* Get this node's address word count. */
+		ui_ptr = (unsigned int *) get_property(Pci_Node, "#address-cells", NULL);
+		if (ui_ptr)
+			this_addr_count = *ui_ptr;
+		else
+			this_addr_count = 3;
+		
+		range_stride = this_addr_count + root_addr_size_words + this_addr_size_words;
+	      
+		memno = 0;
+		phb->io_base_phys = 0;
+         
+		ranges = (unsigned int *) get_property(Pci_Node, "ranges", &rlen);
+		PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen);
+                
+		for (i = 0; i < (rlen/sizeof(*ranges)); i+=range_stride) {
+		  	/* Put the PCI addr part of the current element into a 
+			 * '64' struct. 
+			 */
+		  	range = *((struct pci_range64 *)(ranges + i));
+
+			/* If this is a '32' element, map into a 64 struct. */
+			if ((range_stride * sizeof(int)) == 
+			   sizeof(struct pci_range32)) {
+				range.parent_addr = 
+					(unsigned long)(*(ranges + i + 3));
+				range.size = 
+					(((unsigned long)(*(ranges + i + 4)))<<32) | 
+					(*(ranges + i + 5));
+			} else {
+				range.parent_addr = 
+					(((unsigned long)(*(ranges + i + 3)))<<32) | 
+					(*(ranges + i + 4));
+				range.size = 
+					(((unsigned long)(*(ranges + i + 5)))<<32) | 
+					(*(ranges + i + 6));
+			}
+			
+			PPCDBG(PPCDBG_PHBINIT, "\trange.parent_addr    = 0x%lx\n", 
+			       range.parent_addr);
+			PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.hi  = 0x%lx\n", 
+			       range.child_addr.a_hi);
+			PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.mid = 0x%lx\n", 
+			       range.child_addr.a_mid);
+			PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.lo  = 0x%lx\n", 
+			       range.child_addr.a_lo);
+			PPCDBG(PPCDBG_PHBINIT, "\trange.size           = 0x%lx\n", 
+			       range.size);
+
+			res = NULL;
+		        switch ((range.child_addr.a_hi >> 24) & 0x3) {
+			case 1:		/* I/O space */
+				PPCDBG(PPCDBG_PHBINIT, "\tIO Space\n");
+				phb->io_base_phys = range.parent_addr;
+				res = &phb->io_resource;
+				res->name = Pci_Node->full_name;
+				res->flags = IORESOURCE_IO;
+#ifdef CONFIG_PPC_EEH
+				if (!isa_io_base && has_isa) {
+					/* map a page for ISA ports.  Not EEH protected. */
+					isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
+				}
+			        res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
+				res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
+#else
+			        phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
+				if (!pci_io_base) {
+					pci_io_base = (unsigned long)phb->io_base_virt;
+					if (has_isa)
+						isa_io_base = pci_io_base;
+				}
+				res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
+				res->start += (unsigned long)phb->io_base_virt;
+				res->end =   res->start + range.size - 1;
+#endif
+				res->parent = NULL;
+				res->sibling = NULL;
+				res->child = NULL;
+				phb->pci_io_offset = range.parent_addr - 
+					((((unsigned long)
+					   range.child_addr.a_mid) << 32) | 
+					 (range.child_addr.a_lo));
+				PPCDBG(PPCDBG_PHBINIT, "\tpci_io_offset  = 0x%lx\n", 
+				       phb->pci_io_offset);
+			  	break;
+			case 2:		/* mem space */
+				PPCDBG(PPCDBG_PHBINIT, "\tMem Space\n");
+				phb->pci_mem_offset = range.parent_addr - 
+					((((unsigned long)
+					   range.child_addr.a_mid) << 32) | 
+					 (range.child_addr.a_lo));
+				PPCDBG(PPCDBG_PHBINIT, "\tpci_mem_offset = 0x%lx\n", 
+				       phb->pci_mem_offset);
+				if (memno < sizeof(phb->mem_resources)/sizeof(phb->mem_resources[0])) {
+					res = &(phb->mem_resources[memno]);
+					++memno;
+					res->name = Pci_Node->full_name;
+					res->flags = IORESOURCE_MEM;
+#ifdef CONFIG_PPC_EEH
+					res->start = eeh_token(index, 0, 0, 0);
+					res->end =   eeh_token(index, 0xff, 0xff, 0xffffffff);
+#else
+					res->start = range.parent_addr;
+					res->end =   range.parent_addr + range.size - 1;
+#endif
+					res->parent = NULL;
+					res->sibling = NULL;
+					res->child = NULL;
+				}
+			  	break;
+			}
+		}
+		PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys   = 0x%lx\n", 
+		       phb->io_base_phys); 
+		PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n", 
+		       phb->pci_mem_offset); 
+
+		if (naca->interrupt_controller == IC_OPEN_PIC) {
+			int addr = root_addr_size_words * (index + 2) - 1;
+			openpic_setup_ISU(index, opprop[addr]); 
+		}
+		index++;
+	}
+	pci_devs_phb_init();
+	return 0;	 /*Success */
+}
+
+/******************************************************************
+ *
+ * Allocate and partially initialize a structure to represent a PHB.
+ *
+ ******************************************************************/
+struct pci_controller *
+alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words)
+{
+	struct pci_controller *phb;
+	unsigned int *ui_ptr = NULL, len;
+	struct reg_property64 reg_struct;
+	int *bus_range;
+	int *buid_vals;
+
+	PPCDBG(PPCDBG_PHBINIT, "alloc_phb: %s\n", dev->full_name); 
+	PPCDBG(PPCDBG_PHBINIT, "\tdev             = 0x%lx\n", dev); 
+	PPCDBG(PPCDBG_PHBINIT, "\tmodel           = 0x%lx\n", model); 
+	PPCDBG(PPCDBG_PHBINIT, "\taddr_size_words = 0x%lx\n", addr_size_words); 
+  
+	/* Found a PHB, now figure out where his registers are mapped. */
+	ui_ptr = (unsigned int *) get_property(dev, "reg", &len);
+	if (ui_ptr == NULL) {
+		PPCDBG(PPCDBG_PHBINIT, "\tget reg failed.\n"); 
+		return(NULL);
+	}
+
+	if (addr_size_words == 1) {
+		reg_struct.address = ((struct reg_property32 *)ui_ptr)->address;
+		reg_struct.size    = ((struct reg_property32 *)ui_ptr)->size;
+	} else {
+		reg_struct = *((struct reg_property64 *)ui_ptr);
+	}
+
+	PPCDBG(PPCDBG_PHBINIT, "\treg_struct.address = 0x%lx\n", reg_struct.address);
+	PPCDBG(PPCDBG_PHBINIT, "\treg_struct.size    = 0x%lx\n", reg_struct.size); 
+
+	/***************************************************************
+	* Set chip specific data in the phb, including types & 
+	* register pointers.
+	***************************************************************/
+
+	/****************************************************************
+	* Python
+	***************************************************************/
+	if (strstr(model, "Python")) {
+		PPCDBG(PPCDBG_PHBINIT, "\tCreate python\n");
+	        phb = pci_alloc_pci_controller("PHB PY",phb_type_python);
+		if (phb == NULL) return NULL;
+	
+       		phb->cfg_addr = (volatile unsigned long *) 
+			ioremap(reg_struct.address + 0xf8000, PAGE_SIZE);
+		PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_r = 0x%lx\n", 
+		       reg_struct.address + 0xf8000);
+		PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_v = 0x%lx\n", 
+		       phb->cfg_addr);
+		phb->cfg_data = (char*)(phb->cfg_addr + 0x02);
+       		phb->phb_regs = (volatile unsigned long *) 
+			ioremap(reg_struct.address + 0xf7000, PAGE_SIZE);
+		/* Python's register file is 1 MB in size. */
+		phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 
+					 0x100000); 
+
+		/* 
+		 * Firmware doesnt always clear this bit which is critical
+		 * for good performance - Anton
+		 */
+		{
+			volatile u32 *tmp, i;
+
+#define PRG_CL_RESET_VALID 0x00010000
+
+			tmp = (u32 *)((unsigned long)phb->chip_regs + 0xf6030);
+
+			if (*tmp & PRG_CL_RESET_VALID) {
+				printk("Python workaround: ");
+				*tmp &= ~PRG_CL_RESET_VALID;
+				/*
+				 * We must read it back for changes to
+				 * take effect
+				 */
+				i = *tmp;
+				printk("reg0: %x\n", i);
+			}
+		}
+
+	/***************************************************************
+	* Speedwagon
+	***************************************************************/
+	} else if (strstr(model, "Speedwagon")) {
+		PPCDBG(PPCDBG_PHBINIT, "\tCreate speedwagon\n");
+	        phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
+		if (phb == NULL) return NULL;
+
+		if (_machine == _MACH_pSeries) {
+			phb->cfg_addr = (volatile unsigned long *) 
+			  ioremap(reg_struct.address + 0x140, PAGE_SIZE);
+			phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
+			phb->phb_regs = (volatile unsigned long *) 
+			  ioremap(reg_struct.address, PAGE_SIZE);
+			/* Speedwagon's register file is 1 MB in size. */
+			phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL),
+						 0x100000); 
+			PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n", 
+			       reg_struct.address & 0xfffff, phb->chip_regs);
+		} else {
+			phb->cfg_addr = NULL;
+			phb->cfg_data = NULL; 
+			phb->phb_regs = NULL;
+			phb->chip_regs = NULL;
+		}
+
+		phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8;
+	/***************************************************************
+	* Trying to build a known just gets the code in trouble.
+	***************************************************************/
+	} else { 
+		PPCDBG(PPCDBG_PHBINIT, "\tUnknown PHB Type!\n");
+		printk("PCI: Unknown Phb Type!\n");
+		return NULL;
+	}
+
+	bus_range = (int *) get_property(dev, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		PPCDBG(PPCDBG_PHBINIT, "Can't get bus-range for %s\n", dev->full_name);
+		kfree(phb);
+		return(NULL);
+	}
+
+	/***************************************************************
+	* Finished with the initialization
+	***************************************************************/
+	phb->first_busno =  bus_range[0];
+	phb->last_busno  =  bus_range[1];
+
+	phb->arch_data   = dev;
+	phb->ops = &rtas_pci_ops;
+
+	buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len);
+	
+  if (buid_vals == NULL) {
+		phb->buid = 0;
+	} 
+  else {
+		struct pci_bus check;
+		if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 ||
+		    sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) {
+			udbg_printf("pSeries_pci:  this system has large bus numbers and the kernel was not\n"
+			      "built with the patch that fixes include/linux/pci.h struct pci_bus so\n"
+			      "number, primary, secondary and subordinate are ints.\n");
+			panic("pSeries_pci:  this system has large bus numbers and the kernel was not\n"
+			      "built with the patch that fixes include/linux/pci.h struct pci_bus so\n"
+			      "number, primary, secondary and subordinate are ints.\n");
+    }
+    
+    if (len < 2 * sizeof(int))
+      phb->buid = (unsigned long)buid_vals[0];  // Support for new OF that only has 1 integer for buid.
+    else
+      phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
+                  (((unsigned long)buid_vals[1]) & 0xffffffff);
+  	
+		phb->first_busno += (phb->global_number << 8);
+		phb->last_busno += (phb->global_number << 8);
+	}
+
+	/* Dump PHB information for Debug */
+	PPCDBGCALL(PPCDBG_PHBINIT,dumpPci_Controller(phb) );
+
+	return phb;
+}
+
+void 
+fixup_resources(struct pci_dev *dev)
+{
+ 	int i;
+ 	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
+#ifdef CONFIG_PPC_EEH
+	struct device_node *dn;
+	unsigned long eeh_disable_bit;
+
+	/* Add IBM loc code (slot) as a prefix to the device names for service */
+	dn = pci_device_to_OF_node(dev);
+	if (dn) {
+		char *loc_code = get_property(dn, "ibm,loc-code", 0);
+		if (loc_code) {
+			int loc_len = strlen(loc_code);
+			if (loc_len < sizeof(dev->name)) {
+				memmove(dev->name+loc_len+1, dev->name, sizeof(dev->name)-loc_len-1);
+				memcpy(dev->name, loc_code, loc_len);
+				dev->name[loc_len] = ' ';
+				dev->name[sizeof(dev->name)-1] = '\0';
+			}
+		}
+	}
+
+	if (is_eeh_configured(dev)) {
+		eeh_disable_bit = 0;
+		printk("PCI: eeh configured for %s %s\n", dev->slot_name, dev->name);
+		if (eeh_set_option(dev, EEH_ENABLE) != 0) {
+			printk("PCI: failed to enable eeh for %s %s\n", dev->slot_name, dev->name);
+			eeh_disable_bit = EEH_TOKEN_DISABLED;
+		}
+	} else {
+		/* Assume device is by default EEH_DISABLE'd */
+		printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
+		eeh_disable_bit = EEH_TOKEN_DISABLED;
+	}
+#endif
+
+	PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); 
+	PPCDBG(PPCDBG_PHBINIT, "\tphb                 = 0x%016LX\n", phb); 
+	PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset  = 0x%016LX\n", phb->pci_io_offset); 
+	PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%016LX\n", phb->pci_mem_offset); 
+
+	PPCDBG(PPCDBG_PHBINIT, "\tdev->name   = %s\n", dev->name);
+	PPCDBG(PPCDBG_PHBINIT, "\tdev->vendor:device = 0x%04X : 0x%04X\n", dev->vendor, dev->device);
+
+	if (phb == NULL)
+		return;
+
+ 	for (i = 0; i <  DEVICE_COUNT_RESOURCE; ++i) {
+		PPCDBG(PPCDBG_PHBINIT, "\tdevice %x.%x[%d] (flags %x) [%lx..%lx]\n",
+			    dev->bus->number, dev->devfn, i,
+			    dev->resource[i].flags,
+			    dev->resource[i].start,
+			    dev->resource[i].end);
+
+		if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) {
+			continue;
+		}
+
+		if (dev->resource[i].flags & IORESOURCE_IO) {
+#ifdef CONFIG_PPC_EEH
+			unsigned int busno = dev->bus ? dev->bus->number : 0;
+			unsigned long size = dev->resource[i].end - dev->resource[i].start;
+			unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
+			if (!addr)
+				panic("fixup_resources: ioremap failed!\n");
+			dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
+			dev->resource[i].end = dev->resource[i].start + size;
+#else
+			unsigned long offset = (unsigned long)phb->io_base_virt;
+			dev->resource[i].start += offset;
+			dev->resource[i].end += offset;
+#endif
+			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
+			       dev->resource[i].start, dev->resource[i].end);
+		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
+			if (dev->resource[i].start == 0) {
+				/* Bogus.  Probably an unused bridge. */
+				dev->resource[i].end = 0;
+			} else {
+#ifdef CONFIG_PPC_EEH
+				unsigned int busno = dev->bus ? dev->bus->number : 0;
+				unsigned long size = dev->resource[i].end - dev->resource[i].start;
+				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
+				if (!addr)
+					panic("fixup_resources: ioremap failed!\n");
+				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
+				dev->resource[i].end = dev->resource[i].start + size;
+#else
+				dev->resource[i].start += phb->pci_mem_offset;
+				dev->resource[i].end += phb->pci_mem_offset;
+#endif
+			}
+			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
+			       dev->resource[i].start, dev->resource[i].end);
+
+		} else {
+			continue;
+		}
+
+ 		/* zap the 2nd function of the winbond chip */
+ 		if (dev->resource[i].flags & IORESOURCE_IO
+ 		    && dev->bus->number == 0 && dev->devfn == 0x81)
+ 			dev->resource[i].flags &= ~IORESOURCE_IO;
+ 	}
+}   
+
+static void check_s7a(void)
+{
+	struct device_node *root;
+	char *model;
+
+	root = find_path_device("/");
+	if (root) {
+		model = get_property(root, "model", NULL);
+		if (model && !strcmp(model, "IBM,7013-S7A"))
+			s7a_workaround = 1;
+	}
+}
+
+void __init
+pSeries_pcibios_fixup(void)
+{
+	struct pci_dev *dev;
+
+	PPCDBG(PPCDBG_PHBINIT, "pSeries_pcibios_fixup: start\n");
+	pci_assign_all_busses = 0;
+
+	check_s7a();
+	
+	pci_for_each_dev(dev) {
+		pci_read_irq_line(dev);
+		PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Dev(dev) );
+	}
+
+	if (naca->interrupt_controller == IC_PPC_XIC) {
+		xics_isa_init(); 
+	}
+}
+
+/*********************************************************************** 
+ * pci_find_hose_for_OF_device
+ *
+ * This function finds the PHB that matching device_node in the 
+ * OpenFirmware by scanning all the pci_controllers.
+ * 
+ ***********************************************************************/
+struct pci_controller*
+pci_find_hose_for_OF_device(struct device_node *node)
+{
+	while (node) {
+		struct pci_controller *hose;
+		for (hose=hose_head;hose;hose=hose->next)
+			if (hose->arch_data == node)
+				return hose;
+		node=node->parent;
+	}
+	return NULL;
+}
+
+/*********************************************************************** 
+ * ppc64_pcibios_init
+ *  
+ * Chance to initialize and structures or variable before PCI Bus walk.
+ *  
+ ***********************************************************************/
+void 
+pSeries_pcibios_init(void)
+{
+	PPCDBG(PPCDBG_PHBINIT, "\tppc64_pcibios_init Entry.\n"); 
+
+	if (get_property(find_path_device("/rtas"),"ibm,fw-phb-id",NULL) != NULL) {
+		PPCDBG(PPCDBG_PHBINIT, "\tFound: ibm,fw-phb-id\n"); 
+		Pci_Large_Bus_System = 1;
+	}
+}
+
+/*
+ * This is called very early before the page table is setup.
+ */
+void 
+pSeries_pcibios_init_early(void)
+{
+	ppc_md.pcibios_read_config_byte = rtas_read_config_byte;
+	ppc_md.pcibios_read_config_word = rtas_read_config_word;
+	ppc_md.pcibios_read_config_dword = rtas_read_config_dword;
+	ppc_md.pcibios_write_config_byte = rtas_write_config_byte;
+	ppc_md.pcibios_write_config_word = rtas_write_config_word;
+	ppc_md.pcibios_write_config_dword = rtas_write_config_dword;
+}
+/************************************************************************/
+/* Get a char* of the device physical location(U0.3-P1-I8)              */
+/* See the Product Topology in the RS/6000 Architecture.                */
+/************************************************************************/
+int device_Location(struct pci_dev *PciDev, char *BufPtr)
+{
+	struct device_node *DevNode = (struct device_node *)PciDev->sysdata;
+	return sprintf(BufPtr,"PCI: Bus%3d, Device%3d, Vendor %04X, Location %-12s",
+		       PciDev->bus->number,
+		       PCI_SLOT(PciDev->devfn),
+		       PciDev->vendor,
+		       (char*)get_property(DevNode,"ibm,loc-code",0));
+}
+/************************************************************************/
+/* Set the slot reset line to the state passed in.                      */
+/* This is the platform specific for code for the pci_reset_device      */
+/* function.                                                            */
+/************************************************************************/
+int pci_set_reset(struct pci_dev *PciDev, int state)
+{
+	return -1;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pacaData.c linux-2.4.19-pre5/arch/ppc64/kernel/pacaData.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pacaData.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pacaData.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,118 @@
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#define __KERNEL__ 1
+#include <asm/types.h>
+#include <asm/page.h>
+#include <stddef.h>
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/Paca.h>
+
+
+/* The Paca is an array with one entry per processor.  Each contains an 
+ * ItLpPaca, which contains the information shared between the 
+ * hypervisor and Linux.  Each also contains an ItLpRegSave area which
+ * is used by the hypervisor to save registers.
+ * On systems with hardware multi-threading, there are two threads
+ * per processor.  The Paca array must contain an entry for each thread.
+ * The VPD Areas will give a max logical processors = 2 * max physical
+ * processors.  The processor VPD array needs one entry per physical
+ * processor (not thread).
+ */
+#define PACAINITDATA(number,start,lpq,asrr,asrv) \
+{                                                                          \
+        xLpPacaPtr: &xPaca[number].xLpPaca,                                 \
+        xLpRegSavePtr: &xPaca[number].xRegSav,                              \
+        xPacaIndex: (number),           /* Paca Index        */             \
+        default_decr: 0x00ff0000,       /* Initial Decr      */             \
+        xStab_data: {                                                       \
+                real: (asrr),           /* Real pointer to segment table */ \
+                virt: (asrv),           /* Virt pointer to segment table */ \
+                next_round_robin: 1     /* Round robin index */             \
+        },                                                                  \
+        lpQueuePtr: (lpq),              /* &xItLpQueue,                  */ \
+        xRtas: {                                                            \
+                lock: SPIN_LOCK_UNLOCKED                                    \
+        },                                                                  \
+        xProcStart: (start),            /* Processor start */               \
+        xLpPaca: {                                                          \
+                xDesc: 0xd397d781,      /* "LpPa"          */               \
+                xSize: sizeof(struct ItLpPaca),                             \
+                xFPRegsInUse: 1,                                            \
+                xDynProcStatus: 2,                                          \
+		xDecrVal: 0x00ff0000,					    \
+                xEndOfQuantum: 0xffffffffffffffff                           \
+        },                                                                  \
+        xRegSav: {                                                          \
+                xDesc: 0xd397d9e2,      /* "LpRS"          */               \
+                xSize: sizeof(struct ItLpRegSave)                           \
+        },                                                                  \
+        exception_sp:                                                       \
+                (&xPaca[number].exception_stack[0]) - EXC_FRAME_SIZE,       \
+}
+
+struct Paca xPaca[maxPacas] __page_aligned = {
+#ifdef CONFIG_PPC_ISERIES
+	PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
+#else
+	PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000),
+#endif
+	PACAINITDATA( 1, 0, 0, 0, 0),
+	PACAINITDATA( 2, 0, 0, 0, 0),
+	PACAINITDATA( 3, 0, 0, 0, 0),
+	PACAINITDATA( 4, 0, 0, 0, 0),
+	PACAINITDATA( 5, 0, 0, 0, 0),
+	PACAINITDATA( 6, 0, 0, 0, 0),
+	PACAINITDATA( 7, 0, 0, 0, 0),
+	PACAINITDATA( 8, 0, 0, 0, 0),
+	PACAINITDATA( 9, 0, 0, 0, 0),
+	PACAINITDATA(10, 0, 0, 0, 0),
+	PACAINITDATA(11, 0, 0, 0, 0),
+	PACAINITDATA(12, 0, 0, 0, 0),
+	PACAINITDATA(13, 0, 0, 0, 0),
+	PACAINITDATA(14, 0, 0, 0, 0),
+	PACAINITDATA(15, 0, 0, 0, 0),
+	PACAINITDATA(16, 0, 0, 0, 0),
+	PACAINITDATA(17, 0, 0, 0, 0),
+	PACAINITDATA(18, 0, 0, 0, 0),
+	PACAINITDATA(19, 0, 0, 0, 0),
+	PACAINITDATA(20, 0, 0, 0, 0),
+	PACAINITDATA(21, 0, 0, 0, 0),
+	PACAINITDATA(22, 0, 0, 0, 0),
+	PACAINITDATA(23, 0, 0, 0, 0),
+	PACAINITDATA(24, 0, 0, 0, 0),
+	PACAINITDATA(25, 0, 0, 0, 0),
+	PACAINITDATA(26, 0, 0, 0, 0),
+	PACAINITDATA(27, 0, 0, 0, 0),
+	PACAINITDATA(28, 0, 0, 0, 0),
+	PACAINITDATA(29, 0, 0, 0, 0),
+	PACAINITDATA(30, 0, 0, 0, 0),
+	PACAINITDATA(31, 0, 0, 0, 0),
+	PACAINITDATA(32, 0, 0, 0, 0),
+	PACAINITDATA(33, 0, 0, 0, 0),
+	PACAINITDATA(34, 0, 0, 0, 0),
+	PACAINITDATA(35, 0, 0, 0, 0),
+	PACAINITDATA(36, 0, 0, 0, 0),
+	PACAINITDATA(37, 0, 0, 0, 0),
+	PACAINITDATA(38, 0, 0, 0, 0),
+	PACAINITDATA(39, 0, 0, 0, 0),
+	PACAINITDATA(40, 0, 0, 0, 0),
+	PACAINITDATA(41, 0, 0, 0, 0),
+	PACAINITDATA(42, 0, 0, 0, 0),
+	PACAINITDATA(43, 0, 0, 0, 0),
+	PACAINITDATA(44, 0, 0, 0, 0),
+	PACAINITDATA(45, 0, 0, 0, 0),
+	PACAINITDATA(46, 0, 0, 0, 0),
+	PACAINITDATA(47, 0, 0, 0, 0)
+};
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pci.c linux-2.4.19-pre5/arch/ppc64/kernel/pci.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pci.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,1062 @@
+/*
+ * 
+ *
+ * Port for PPC64 David Engebretsen, IBM Corp.
+ *   Contains common pci routines for ppc64 platform, pSeries and iSeries brands. 
+ * 
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/flight_recorder.h>
+#include <asm/ppcdebug.h>
+#include <asm/Naca.h>
+#include <asm/pci_dma.h>
+#include <asm/machdep.h>
+#ifdef CONFIG_PPC_EEH
+#include <asm/eeh.h>
+#endif
+
+#include "pci.h"
+
+/* pci_io_base -- the base address from which io bars are offsets.
+ * This is the lowest I/O base address (so bar values are always positive),
+ * and it *must* be the start of ISA space if an ISA bus exists because
+ * ISA drivers use hard coded offsets.  If no ISA bus exists a dummy
+ * page is mapped and isa_io_limit prevents access to it.
+ */
+unsigned long isa_io_base     = 0;	/* NULL if no ISA bus */
+unsigned long pci_io_base     = 0;
+unsigned long isa_mem_base    = 0;
+unsigned long pci_dram_offset = 0;
+
+/******************************************************************
+ * Forward declare of prototypes
+ ******************************************************************/
+static void pcibios_fixup_resources(struct pci_dev* dev);
+static void fixup_broken_pcnet32(struct pci_dev* dev);
+static void fixup_windbond_82c105(struct pci_dev* dev);
+void        fixup_resources(struct pci_dev* dev);
+
+void   iSeries_pcibios_init(void);
+void   pSeries_pcibios_init(void);
+
+
+extern struct Naca *naca;
+
+int pci_assign_all_busses = 0;
+
+struct pci_controller* hose_head;
+struct pci_controller** hose_tail = &hose_head;
+
+LIST_HEAD(iSeries_Global_Device_List);
+
+/*******************************************************************
+ * Counters and control flags. 
+ *******************************************************************/
+long   Pci_Io_Read_Count  = 0;
+long   Pci_Io_Write_Count = 0;
+long   Pci_Cfg_Read_Count = 0;
+long   Pci_Cfg_Write_Count= 0;
+long   Pci_Error_Count    = 0;
+
+int    Pci_Retry_Max      = 3;	/* Only retry 3 times  */	
+int    Pci_Error_Flag     = 1;	/* Set Retry Error on. */
+int    Pci_Trace_Flag     = 0;
+
+/******************************************************************
+ * 
+ ******************************************************************/
+int  global_phb_number    = 0;           /* Global phb counter    */
+int  Pci_Large_Bus_System = 0;
+int  Pci_Set_IOA_Address  = 0;
+int  Pci_Manage_Phb_Space = 0;
+struct pci_controller *phbtab[PCI_MAX_PHB];
+
+static int pci_bus_count;
+
+/* Cached ISA bridge dev. */
+struct pci_dev *ppc64_isabridge_dev = NULL;
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TRIDENT,	PCI_ANY_ID, fixup_broken_pcnet32 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_WINBOND,	PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105 },
+	{ PCI_FIXUP_HEADER, PCI_ANY_ID,	PCI_ANY_ID, pcibios_fixup_resources },
+ 	{ 0 }
+};
+
+static void fixup_broken_pcnet32(struct pci_dev* dev)
+{
+	if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
+		dev->vendor = PCI_VENDOR_ID_AMD;
+		pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+		pci_name_device(dev);
+	}
+}
+
+static void fixup_windbond_82c105(struct pci_dev* dev)
+{
+	/* Assume the windbond 82c105 is the IDE controller on a
+	 * p610.  We should probably be more careful in case
+	 * someone tries to plug in a similar adapter.
+	 */
+	unsigned int reg;
+
+	printk("Using INTC for W82c105 IDE controller.\n");
+	pci_read_config_dword(dev, 0x40, &reg);
+	/* Enable LEGIRQ to use INTC instead of ISA interrupts */
+	pci_write_config_dword(dev, 0x40, reg | (1<<11));
+}
+
+
+void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
+				struct pbus_set_ranges_data *pranges)
+{
+}
+
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			     struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+	struct pci_controller* hose = PCI_GET_PHB_PTR(dev);
+	
+	new = res->start;
+	if (hose && res->flags & IORESOURCE_MEM)
+		new -= hose->pci_mem_offset;
+	new |= (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+}
+
+static void
+pcibios_fixup_resources(struct pci_dev* dev)
+{
+	fixup_resources(dev);
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+	struct pci_dev *dev = data;
+
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (size > 0x100) {
+			printk(KERN_ERR "PCI: Can not align I/O Region %s %s because size %ld is too large.\n",
+                                        dev->slot_name, res->name, size);
+		}
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *	- I/O or memory regions not configured
+ *	- regions configured, but not enabled in the command register
+ *	- bogus I/O addresses above 64K used
+ *	- expansion ROMs left enabled (this may sound harmless, but given
+ *	  the fact the PCI specs explicitly allow address decoders to be
+ *	  shared between expansion ROMs and other resource regions, it's
+ *	  at least dangerous)
+ *
+ *  Our solution:
+ *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *	    This gives us fixed barriers on where we can allocate.
+ *	(2) Allocate resources for all enabled devices.  If there is
+ *	    a collision, just mark the resource as unallocated. Also
+ *	    disable expansion ROMs during this step.
+ *	(3) Try to allocate resources for disabled devices.  If the
+ *	    resources were assigned correctly, everything goes well,
+ *	    if they weren't, they won't disturb allocation of other
+ *	    resources.
+ *	(4) Assign new addresses to resources which were either
+ *	    not configured at all or misconfigured.  If explicitly
+ *	    requested by the user, configure expansion ROM address
+ *	    as well.
+ */
+
+static void __init
+pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+	struct list_head *ln;
+	struct pci_bus *bus;
+	int i;
+	struct resource *res, *pr;
+
+	/* Depth-First Search on bus tree */
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		for (i = 0; i < 4; ++i) {
+			if ((res = bus->resource[i]) == NULL || !res->flags)
+				continue;
+			if (bus->parent == NULL)
+				pr = (res->flags & IORESOURCE_IO)?
+					&ioport_resource: &iomem_resource;
+			else
+				pr = pci_find_parent_resource(bus->self, res);
+
+			if (pr == res)
+				continue;	/* transparent bus or undefined */
+			if (pr && request_resource(pr, res) == 0)
+				continue;
+			printk(KERN_ERR "PCI: Cannot allocate resource region "
+			       "%d of PCI bridge %x\n", i, bus->number);
+			printk(KERN_ERR "PCI: resource is %lx..%lx (%lx), parent %p\n",
+			    res->start, res->end, res->flags, pr);
+		}
+		pcibios_allocate_bus_resources(&bus->children);
+	}
+}
+
+static void __init
+pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev;
+	int idx, disabled;
+	u16 command;
+	struct resource *r, *pr;
+
+	pci_for_each_dev(dev) {
+		pci_read_config_word(dev, PCI_COMMAND, &command);
+		for(idx = 0; idx < 6; idx++) {
+			r = &dev->resource[idx];
+			if (r->parent)		/* Already allocated */
+				continue;
+			if (!r->start)		/* Address not assigned at all */
+				continue;
+
+			if (r->flags & IORESOURCE_IO)
+				disabled = !(command & PCI_COMMAND_IO);
+			else
+				disabled = !(command & PCI_COMMAND_MEMORY);
+			if (pass == disabled) {
+				PPCDBG(PPCDBG_PHBINIT,
+				       "PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+				       r->start, r->end, r->flags, disabled, pass);
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0) {
+					PPCDBG(PPCDBG_PHBINIT,
+					       "PCI: Cannot allocate resource region %d of device %s, pr = 0x%lx\n", idx, dev->slot_name, pr);
+					if(pr) {
+					PPCDBG(PPCDBG_PHBINIT,
+					       "PCI: Cannot allocate resource 0x%lx\n", request_resource(pr,r));
+					}
+					/* We'll assign a new address later */
+					r->end -= r->start;
+					r->start = 0;
+				}
+			}
+		}
+		if (!pass) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+				u32 reg;
+				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
+		}
+	}
+}
+
+static void __init
+pcibios_assign_resources(void)
+{
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r;
+
+	pci_for_each_dev(dev) {
+		int class = dev->class >> 8;
+
+		/* Don't touch classless devices and host bridges */
+		if (!class || class == PCI_CLASS_BRIDGE_HOST)
+			continue;
+
+		for(idx=0; idx<6; idx++) {
+			r = &dev->resource[idx];
+
+			/*
+			 *  Don't touch IDE controllers and I/O ports of video cards!
+			 */
+			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+				continue;
+
+			/*
+			 *  We shall assign a new address to this resource, either because
+			 *  the BIOS forgot to do so or because we have decided the old
+			 *  address was unusable for some reason.
+			 */
+			if (!r->start && r->end && ppc_md.pcibios_enable_device_hook &&
+			    !ppc_md.pcibios_enable_device_hook(dev, 1))
+				pci_assign_resource(dev, idx);
+		}
+
+		if (0) { /* don't assign ROMs */
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			r->end -= r->start;
+			r->start = 0;
+			if (r->end)
+				pci_assign_resource(dev, PCI_ROM_RESOURCE);
+		}
+	}
+}
+
+
+int
+pcibios_enable_resources(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/* 
+ * Allocate pci_controller(phb) initialized common variables. 
+ */
+struct pci_controller * __init
+pci_alloc_pci_controller(char *model, enum phb_types controller_type)
+{
+        struct pci_controller *hose;
+        PPCDBG(PPCDBG_PHBINIT, "PCI: Allocate pci_controller for %s\n",model);
+        hose = (struct pci_controller *)alloc_bootmem(sizeof(struct pci_controller));
+        if(hose == NULL) {
+                printk(KERN_ERR "PCI: Allocate pci_controller failed.\n");
+                return NULL;
+        }
+        memset(hose, 0, sizeof(struct pci_controller));
+        if(strlen(model) < 8) strcpy(hose->what,model);
+        else                  memcpy(hose->what,model,7);
+        hose->type = controller_type;
+        hose->global_number = global_phb_number;
+	phbtab[global_phb_number++] = hose;
+        
+        *hose_tail = hose;
+        hose_tail = &hose->next;
+        return hose;
+}
+
+/*
+ * This fixup is arch independent and probably should go somewhere else.
+ */
+void __init
+pcibios_generic_fixup(void)
+{
+	struct pci_dev *dev;
+
+	/* Fix miss-identified vendor AMD pcnet32 adapters. */
+	dev = NULL;
+	while ((dev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, dev)) != NULL &&
+	       dev->class == (PCI_CLASS_NETWORK_ETHERNET << 8))
+		dev->vendor = PCI_VENDOR_ID_AMD;
+}
+
+
+
+/*********************************************************************** 
+ *
+ *
+ * 
+ ***********************************************************************/
+void __init
+pcibios_init(void)
+{
+	struct pci_controller *hose;
+	struct pci_bus *bus;
+	int    next_busno;
+
+#ifndef CONFIG_PPC_ISERIES
+	pSeries_pcibios_init();
+#else
+	iSeries_pcibios_init(); 
+#endif
+
+	printk("PCI: Probing PCI hardware\n");
+	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n");
+				
+
+	/* Scan all of the recorded PCI controllers.  */
+	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
+		hose->last_busno = 0xff;
+		bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data);
+		hose->bus = bus;
+		hose->last_busno = bus->subordinate;
+		if (pci_assign_all_busses || next_busno <= hose->last_busno)
+			next_busno = hose->last_busno+1;
+	}
+	pci_bus_count = next_busno;
+		
+	/* Call machine dependant fixup */
+	if (ppc_md.pcibios_fixup) {
+		ppc_md.pcibios_fixup();
+	}
+
+	/* Generic fixups */
+	pcibios_generic_fixup();
+
+	/* Allocate and assign resources */
+	pcibios_allocate_bus_resources(&pci_root_buses);
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
+	pcibios_assign_resources();
+
+#ifndef CONFIG_PPC_ISERIES
+	pci_fix_bus_sysdata();
+
+	create_tce_tables();
+	PPCDBG(PPCDBG_BUSWALK,"pSeries create_tce_tables()\n");
+#endif
+
+	/* Cache the location of the ISA bridge (if we have one) */
+	if (ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL))
+		printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name);
+
+	printk("PCI: Probing PCI hardware done\n");
+	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n");
+
+}
+
+int __init
+pcibios_assign_all_busses(void)
+{
+	return pci_assign_all_busses;
+}
+
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+			     unsigned long start, unsigned long size)
+{
+	return start;
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
+	struct resource *res;
+	int i;
+
+#ifndef CONFIG_PPC_ISERIES
+	if (bus->parent == NULL) {
+		/* This is a host bridge - fill in its resources */
+		phb->bus = bus;
+		bus->resource[0] = res = &phb->io_resource;
+		if (!res->flags)
+			BUG();	/* No I/O resource for this PHB? */
+
+		for (i = 0; i < 3; ++i) {
+			res = &phb->mem_resources[i];
+			if (!res->flags) {
+				if (i == 0)
+					BUG();	/* No memory resource for this PHB? */
+			}
+			bus->resource[i+1] = res;
+		}
+	} else {
+		/* This is a subordinate bridge */
+		pci_read_bridge_bases(bus);
+
+		for (i = 0; i < 4; ++i) {
+			if ((res = bus->resource[i]) == NULL)
+				continue;
+			if (!res->flags)
+				continue;
+			if (res == pci_find_parent_resource(bus->self, res)) {
+				/* Transparent resource -- don't try to "fix" it. */
+				continue;
+			}
+#ifdef CONFIG_PPC_EEH
+			if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
+				res->start = eeh_token(phb->global_number, bus->number, 0, 0);
+				res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
+			}
+#else
+			if (res->flags & IORESOURCE_IO) {
+				res->start += (unsigned long)phb->io_base_virt;
+				res->end += (unsigned long)phb->io_base_virt;
+			} else if (phb->pci_mem_offset
+				   && (res->flags & IORESOURCE_MEM)) {
+				if (res->start < phb->pci_mem_offset) {
+					res->start += phb->pci_mem_offset;
+					res->end += phb->pci_mem_offset;
+				}
+			}
+#endif
+		}
+	}
+#endif	
+	if ( ppc_md.pcibios_fixup_bus )
+		ppc_md.pcibios_fixup_bus(bus);
+}
+
+char __init *pcibios_setup(char *str)
+{
+	return str;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n",__FUNCTION__,dev->slot_name);
+	if (ppc_md.pcibios_enable_device_hook)
+		if (ppc_md.pcibios_enable_device_hook(dev, 0))
+			return -EINVAL;
+			
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
+		PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n",dev->slot_name);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+struct pci_controller*
+pci_bus_to_hose(int bus)
+{
+	struct pci_controller* hose = hose_head;
+
+	for (; hose; hose = hose->next)
+		if (bus >= hose->first_busno && bus <= hose->last_busno)
+			return hose;
+	return NULL;
+}
+
+void*
+pci_bus_io_base(unsigned int bus)
+{
+	struct pci_controller *hose;
+
+	hose = pci_bus_to_hose(bus);
+	if (!hose)
+		return NULL;
+	return hose->io_base_virt;
+}
+
+unsigned long
+pci_bus_io_base_phys(unsigned int bus)
+{
+	struct pci_controller *hose;
+
+	hose = pci_bus_to_hose(bus);
+	if (!hose)
+		return 0;
+	return hose->io_base_phys;
+}
+
+unsigned long
+pci_bus_mem_base_phys(unsigned int bus)
+{
+	struct pci_controller *hose;
+
+	hose = pci_bus_to_hose(bus);
+	if (!hose)
+		return 0;
+	return hose->pci_mem_offset;
+}
+
+/*
+ * Return the index of the PCI controller for device pdev.
+ */
+int pci_controller_num(struct pci_dev *dev)
+{
+	struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
+
+	return hose->global_number;
+}
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ *  -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap.  They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static __inline__ int
+__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+		       enum pci_mmap_state mmap_state)
+{
+	struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long io_offset = 0;
+	int i, res_bit;
+
+	if (hose == 0)
+		return -EINVAL;		/* should never happen */
+
+	/* If memory, add on the PCI bridge address offset */
+	if (mmap_state == pci_mmap_mem) {
+		offset += hose->pci_mem_offset;
+		res_bit = IORESOURCE_MEM;
+	} else {
+		io_offset = (unsigned long)hose->io_base_virt;
+		offset += io_offset;
+		res_bit = IORESOURCE_IO;
+	}
+
+	/*
+	 * Check that the offset requested corresponds to one of the
+	 * resources of the device.
+	 */
+	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+		struct resource *rp = &dev->resource[i];
+		int flags = rp->flags;
+
+		/* treat ROM as memory (should be already) */
+		if (i == PCI_ROM_RESOURCE)
+			flags |= IORESOURCE_MEM;
+
+		/* Active and same type? */
+		if ((flags & res_bit) == 0)
+			continue;
+
+		/* In the range of this resource? */
+		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+			continue;
+
+		/* found it! construct the final physical address */
+		if (mmap_state == pci_mmap_io)
+			offset += hose->io_base_phys - io_offset;
+
+		vma->vm_pgoff = offset >> PAGE_SHIFT;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
+ * mapping.
+ */
+static __inline__ void
+__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
+		     enum pci_mmap_state mmap_state)
+{
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static __inline__ void
+__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
+		      enum pci_mmap_state mmap_state, int write_combine)
+{
+	long prot = pgprot_val(vma->vm_page_prot);
+
+	/* XXX would be nice to have a way to ask for write-through */
+	prot |= _PAGE_NO_CACHE;
+	if (!write_combine)
+		prot |= _PAGE_GUARDED;
+	vma->vm_page_prot = __pgprot(prot);
+}
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture.  The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state,
+			int write_combine)
+{
+	int ret;
+
+	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
+	if (ret < 0)
+		return ret;
+
+	__pci_mmap_set_flags(dev, vma, mmap_state);
+	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+
+	ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+	return ret;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory.  Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+	struct pci_controller* hose = pci_bus_to_hose(bus);
+	long result = -EOPNOTSUPP;
+
+	if (!hose)
+		return -ENODEV;
+	
+	switch (which) {
+	case IOBASE_BRIDGE_NUMBER:
+		return (long)hose->first_busno;
+	case IOBASE_MEMORY:
+		return (long)hose->pci_mem_offset;
+	case IOBASE_IO:
+		return (long)hose->io_base_phys;
+	case IOBASE_ISA_IO:
+		return (long)isa_io_base;
+	case IOBASE_ISA_MEM:
+		return (long)isa_mem_base;
+	}
+
+	return result;
+}
+/************************************************************************/
+/* Formats the device information and location for service.             */
+/* - Pass in pci_dev* pointer to the device.                            */
+/* - Pass in buffer to place the data.  Danger here is the buffer must  */
+/*   be as big as the client says it is.   Should be at least 128 bytes.*/
+/* Return will the length of the string data put in the buffer.         */
+/* The brand specific method device_Location is called.                 */
+/* Format:                                                              */
+/* PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet */
+/* PCI: Bus  0, Device 26, Vendor 0x12AE  Location U0.3-P1-I8  Ethernet */
+/* For pSeries, see the Product Topology in the RS/6000 Architecture.   */
+/* For iSeries, see the Service Manuals.                                */
+/************************************************************************/
+int  format_device_location(struct pci_dev* PciDev,char* BufPtr, int BufferSize)
+{
+	struct device_node* DevNode = (struct device_node*)PciDev->sysdata;
+	int  LineLen = 0;
+	if (DevNode != NULL && BufferSize >= 128) {
+		LineLen += device_Location(PciDev,BufPtr+LineLen);
+		LineLen += sprintf(BufPtr+LineLen," %12s",pci_class_name(PciDev->class >> 8) );
+	}
+	return LineLen;
+}
+/************************************************************************
+ * Saves the config registers for a device.                             *
+ ************************************************************************
+ * Note: This does byte reads so the data may appear byte swapped,      *
+ * The data returned in the pci_config_reg_save_area structure can be   *
+ * used to the restore of the data.  If the save failed, the data       *
+ * will not be restore.  Yes I know, you are most likey toast.          *
+ ************************************************************************/
+int pci_save_config_regs(struct pci_dev* PciDev,struct pci_config_reg_save_area* SaveArea)
+{
+	memset(SaveArea,0x00,sizeof(struct pci_config_reg_save_area) );
+	SaveArea->PciDev    = PciDev;
+	SaveArea->RCode     = 0;
+	SaveArea->Register  = 0;
+	/******************************************************************
+	 * Save All the Regs,  NOTE: restore skips the first 16 bytes.    *
+	 ******************************************************************/
+	while (SaveArea->Register < REG_SAVE_SIZE && SaveArea->RCode == 0) {
+		SaveArea->RCode = pci_read_config_byte(PciDev, SaveArea->Register, &SaveArea->Regs[SaveArea->Register]);
+		++SaveArea->Register;
+	}
+	if (SaveArea->RCode != 0) { 	/* Ouch */
+		SaveArea->Flags = 0x80;	
+		printk("PCI: pci_restore_save_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode);
+		PCIFR(      "pci_restore_save_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode);
+	}
+	else {
+		SaveArea->Flags = 0x01;
+	}
+	return  SaveArea->RCode;
+}
+
+/************************************************************************
+ * Restores the registers saved via the save function.  See the save    *
+ * function for details.                                                *
+ ************************************************************************/
+int pci_restore_config_regs(struct pci_dev* PciDev,struct pci_config_reg_save_area* SaveArea)
+{
+ 	if (SaveArea->PciDev != PciDev || SaveArea->Flags == 0x80 || SaveArea->RCode != 0) {
+		printk("PCI: pci_restore_config_regs failed! %p\n",PciDev);
+		return -1;
+	}
+	/******************************************************************
+	 * Don't touch the Cmd or BIST regs, user must restore those.     *
+	 * Restore PCI_VENDOR_ID & PCI_DEVICE_ID                          *
+	 * Restore PCI_CACHE_LINE_SIZE & PCI_LATENCY_TIMER                *
+	 * Restore Saved Regs from 0x10 to 0x3F                           * 
+	 ******************************************************************/
+	SaveArea->Register = 0;
+	while(SaveArea->Register < REG_SAVE_SIZE && SaveArea->RCode == 0) {
+		SaveArea->RCode = pci_write_config_byte(PciDev,SaveArea->Register,SaveArea->Regs[SaveArea->Register]);
+		++SaveArea->Register;
+		if (     SaveArea->Register == PCI_COMMAND)     SaveArea->Register = PCI_CACHE_LINE_SIZE;
+		else if (SaveArea->Register == PCI_HEADER_TYPE) SaveArea->Register = PCI_BASE_ADDRESS_0;
+	}
+	if (SaveArea->RCode != 0) {
+		printk("PCI: pci_restore_config_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode);
+		PCIFR(      "pci_restore_config_regs failed! %p\n 0x%04X",PciDev,SaveArea->RCode);
+	}
+	return  SaveArea->RCode;
+}
+
+/************************************************************************/
+/* Interface to toggle the reset line                                   */
+/* Time is in .1 seconds, need for seconds.                             */
+/************************************************************************/
+int  pci_reset_device(struct pci_dev* PciDev, int AssertTime, int DelayTime)
+{
+	unsigned long AssertDelay, WaitDelay;
+	int RtnCode;
+	/********************************************************************
+	 * Set defaults, Assert is .5 second, Wait is 3 seconds.
+	 ********************************************************************/
+	if (AssertTime == 0) AssertDelay = ( 5 * HZ)/10;
+	else                 AssertDelay = (AssertTime*HZ)/10;
+	if (WaitDelay == 0)  WaitDelay   = (30 * HZ)/10;
+	else                 WaitDelay   = (DelayTime* HZ)/10;
+
+	/********************************************************************
+	 * Assert reset, wait, de-assert reset, wait for IOA to reset.
+	 * - Don't waste the CPU time on jiffies.
+	 ********************************************************************/
+	RtnCode = pci_set_reset(PciDev,1);
+	if (RtnCode == 0) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(AssertDelay);   /* Sleep for the time     */
+		RtnCode = pci_set_reset(PciDev,0);
+		set_current_state(TASK_UNINTERRUPTIBLE);  
+		schedule_timeout(WaitDelay);
+	}
+	if (RtnCode == 0) {
+		PCIFR(      "Bus%3d, Device%3d, Reset\n",PciDev->bus->number,PCI_SLOT(PciDev->devfn) );
+	} 
+	else {
+		printk("PCI: Bus%3d, Device%3d, Reset Failed:0x%04X\n",PciDev->bus->number,PCI_SLOT(PciDev->devfn),RtnCode );
+		PCIFR(      "Bus%3d, Device%3d, Reset Failed:0x%04X\n",PciDev->bus->number,PCI_SLOT(PciDev->devfn),RtnCode );
+	}
+	return RtnCode;
+}
+
+/*****************************************************
+ * Dump Resource information
+ *****************************************************/
+void dumpResources(struct resource* Resource)
+{
+	if(Resource != NULL) {
+		int Flags = 0x00000F00 & Resource->flags;
+		if(Resource->start == 0 && Resource->end == 0) return;
+		else if(Resource->start == Resource->end )     return;
+		else {
+			if     (Flags == IORESOURCE_IO)  udbg_printf("IO.:");
+			else if(Flags == IORESOURCE_MEM) udbg_printf("MEM:");
+			else if(Flags == IORESOURCE_IRQ) udbg_printf("IRQ:");
+			else                             udbg_printf("0x%02X:",Resource->flags);
+
+		}
+		udbg_printf("0x%016LX / 0x%016LX (0x%08X)\n",
+			    Resource->start, Resource->end, Resource->end - Resource->start);
+	}
+}
+
+int  resourceSize(struct resource* Resource)
+{
+	if(Resource->start == 0 && Resource->end == 0) return 0;
+	else if(Resource->start == Resource->end )     return 0;
+	else return (Resource->end-1)-Resource->start;
+}
+
+
+/*****************************************************
+ * Dump PHB information for Debug
+ *****************************************************/
+void dumpPci_Controller(struct pci_controller* phb)
+{
+	udbg_printf("\tpci_controller= 0x%016LX\n", phb);
+	if (phb != NULL) {
+		udbg_printf("\twhat & type   = %s 0x%02X\n ",phb->what,phb->type);
+		udbg_printf("\tbus           = ");
+		if (phb->bus != NULL) udbg_printf("0x%02X\n",   phb->bus->number);
+		else                  udbg_printf("<NULL>\n");
+		udbg_printf("\tarch_data     = 0x%016LX\n", phb->arch_data);
+		udbg_printf("\tfirst_busno   = 0x%02X\n",   phb->first_busno);
+		udbg_printf("\tlast_busno    = 0x%02X\n",   phb->last_busno);
+		udbg_printf("\tio_base_virt* = 0x%016LX\n", phb->io_base_virt);
+		udbg_printf("\tio_base_phys  = 0x%016LX\n", phb->io_base_phys);
+		udbg_printf("\tpci_mem_offset= 0x%016LX\n", phb->pci_mem_offset);
+		udbg_printf("\tpci_io_offset = 0x%016LX\n", phb->pci_io_offset);
+
+		udbg_printf("\tcfg_addr      = 0x%016LX\n", phb->cfg_addr);
+		udbg_printf("\tcfg_data      = 0x%016LX\n", phb->cfg_data);
+		udbg_printf("\tphb_regs      = 0x%016LX\n", phb->phb_regs);
+		udbg_printf("\tchip_regs     = 0x%016LX\n", phb->chip_regs);
+
+
+		udbg_printf("\tResources\n");
+		dumpResources(&phb->io_resource);
+		if (phb->mem_resource_count >  0) dumpResources(&phb->mem_resources[0]);
+		if (phb->mem_resource_count >  1) dumpResources(&phb->mem_resources[1]);
+		if (phb->mem_resource_count >  2) dumpResources(&phb->mem_resources[2]);
+
+		udbg_printf("\tglobal_num    = 0x%02X\n",   phb->global_number);
+		udbg_printf("\tlocal_num     = 0x%02X\n",   phb->local_number);
+	}
+}
+
+/*****************************************************
+ * Dump PHB information for Debug
+ *****************************************************/
+void dumpPci_Bus(struct pci_bus* Pci_Bus)
+{
+	int i;
+	udbg_printf("\tpci_bus         = 0x%016LX   \n",Pci_Bus);
+	if (Pci_Bus != NULL) {
+
+		udbg_printf("\tnumber          = 0x%02X     \n",Pci_Bus->number);
+		udbg_printf("\tprimary         = 0x%02X     \n",Pci_Bus->primary);
+		udbg_printf("\tsecondary       = 0x%02X     \n",Pci_Bus->secondary);
+		udbg_printf("\tsubordinate     = 0x%02X     \n",Pci_Bus->subordinate);
+
+		for (i=0;i<4;++i) {
+			if(Pci_Bus->resource[i] == NULL) continue;
+			if(Pci_Bus->resource[i]->start == 0 && Pci_Bus->resource[i]->end == 0) break;
+			udbg_printf("\tResources[%d]",i);
+			dumpResources(Pci_Bus->resource[i]);
+		}
+	}
+}
+
+/*****************************************************
+ * Dump Device information for Debug
+ *****************************************************/
+void dumpPci_Dev(struct pci_dev* Pci_Dev)
+{
+	int i;
+	udbg_printf("\tpci_dev*        = 0x%p\n",Pci_Dev);
+	if ( Pci_Dev == NULL )  return;
+	udbg_printf("\tname            = %s  \n",Pci_Dev->name);
+	udbg_printf("\tbus*            = 0x%p\n",Pci_Dev->bus);
+	udbg_printf("\tsysdata*        = 0x%p\n",Pci_Dev->sysdata);
+	udbg_printf("\tDevice          = 0x%4X%02X:%02X.%02X 0x%04X:%04X\n",
+		    PCI_GET_PHB_NUMBER(Pci_Dev),
+		    PCI_GET_BUS_NUMBER(Pci_Dev),
+		    PCI_SLOT(Pci_Dev->devfn),
+		    PCI_FUNC(Pci_Dev->devfn),
+		    Pci_Dev->vendor,
+		    Pci_Dev->device);
+	udbg_printf("\tHdr/Irq         = 0x%02X/0x%02X \n",Pci_Dev->hdr_type,Pci_Dev->irq);
+	for (i=0;i<DEVICE_COUNT_RESOURCE;++i) {
+		if (Pci_Dev->resource[i].start == 0 && Pci_Dev->resource[i].end == 0) continue;
+		udbg_printf("\tResources[%d] ",i);
+		dumpResources(&Pci_Dev->resource[i]);
+	}
+	dumpResources(&Pci_Dev->resource[i]);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pci.h linux-2.4.19-pre5/arch/ppc64/kernel/pci.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/pci.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pci.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,119 @@
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#ifndef __PPC_KERNEL_PCI_H__
+#define __PPC_KERNEL_PCI_H__
+
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_dram_offset;
+
+/*******************************************************************
+ * Platform independant variables referenced.
+ *******************************************************************
+ * Set pci_assign_all_busses to 1 if you want the kernel to re-assign
+ * all PCI bus numbers.  
+ *******************************************************************/
+extern int pci_assign_all_busses;
+
+extern struct pci_controller* pci_alloc_pci_controller(char *model, enum phb_types controller_type);
+extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node);
+
+extern struct pci_controller* hose_head;
+extern struct pci_controller** hose_tail;
+/* PHB's are also in a table. */
+#define PCI_MAX_PHB 64
+extern int  global_phb_number;
+extern struct pci_controller *phbtab[];
+
+/*******************************************************************
+ * Platform functions that are brand specific implementation. 
+ *******************************************************************/
+extern unsigned long find_and_init_phbs(void);
+
+extern void   fixup_resources(struct pci_dev *dev);
+extern void   ppc64_pcibios_init(void);
+
+extern int    pci_set_reset(struct pci_dev*,int);
+extern int    device_Location(struct pci_dev*,char*);
+extern int    format_device_location(struct pci_dev*,char*, int );
+
+extern struct pci_dev *ppc64_isabridge_dev;	/* may be NULL if no ISA bus */
+
+/*******************************************************************
+ * PCI device_node operations
+ *******************************************************************/
+struct device_node;
+typedef void *(*traverse_func)(struct device_node *me, void *data);
+void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data);
+void *traverse_all_pci_devices(traverse_func pre);
+
+void pci_devs_phb_init(void);
+void pci_fix_bus_sysdata(void);
+struct device_node *fetch_dev_dn(struct pci_dev *dev);
+
+void iSeries_pcibios_init_early(void);
+void pSeries_pcibios_init_early(void);
+void pSeries_pcibios_init(void);
+
+/* Get a device_node from a pci_dev.  This code must be fast except in the case
+ * where the sysdata is incorrect and needs to be fixed up (hopefully just once)
+ */
+static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
+{
+	struct device_node *dn = (struct device_node *)(dev->sysdata);
+	if (dn->devfn == dev->devfn && dn->busno == dev->bus->number)
+		return dn;	/* fast path.  sysdata is good */
+	else
+		return fetch_dev_dn(dev);
+}
+/* Use this macro after the PCI bus walk for max performance when it
+ * is known that sysdata is correct.
+ */
+#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata))
+
+
+/*******************************************************************
+ * Platform configuration flags.. (Live in pci.c)
+ *******************************************************************/
+extern int  Pci_Large_Bus_System;      /* System has > 256 buses   */
+extern int  Pci_Manage_Phb_Space;      /* Manage Phb Space for IOAs*/
+
+/*******************************************************************
+ * Helper macros for extracting data from pci structures.  
+ *   PCI_GET_PHB_PTR(struct pci_dev*)    returns the Phb pointer.
+ *   PCI_GET_PHB_NUMBER(struct pci_dev*) returns the Phb number.
+ *   PCI_GET_BUS_NUMBER(struct pci_dev*) returns the bus number.
+ *******************************************************************/
+#define PCI_GET_PHB_PTR(dev)    (((struct device_node *)(dev)->sysdata)->phb)
+#define PCI_GET_PHB_NUMBER(dev) (((dev)->bus->number&0x00FFFF00)>>8)
+#define PCI_GET_BUS_NUMBER(dev) ((dev)->bus->number&0x0000FF)
+
+/*******************************************************************
+ * Pci Flight Recorder support.
+ *******************************************************************/
+#define PCIFR(...) fr_Log_Entry(PciFr,__VA_ARGS__);
+extern struct flightRecorder* PciFr;
+extern int    Pci_Trace_Flag;
+
+/*******************************************************************
+ * Debugging  Routines.
+ *******************************************************************/
+extern void dumpResources(struct resource* Resource);
+extern void dumpPci_Controller(struct pci_controller* phb);
+extern void dumpPci_Bus(struct pci_bus* Pci_Bus);
+extern void dumpPci_Dev(struct pci_dev* Pci_Dev);
+
+extern void dump_Phb_tree(void);
+extern void dump_Bus_tree(void);
+extern void dump_Dev_tree(void);
+
+#endif /* __PPC_KERNEL_PCI_H__ */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pci_dma.c linux-2.4.19-pre5/arch/ppc64/kernel/pci_dma.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pci_dma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pci_dma.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,1474 @@
+/*
+ * pci_dma.c
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
+ *
+ * Dynamic DMA mapping support.
+ * 
+ * Manages the TCE space assigned to this partition.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/ppcdebug.h>
+
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/pci_dma.h>
+#include <asm/pci-bridge.h>
+#include <asm/iSeries/iSeries_pci.h>
+
+#include <asm/machdep.h>
+
+#include "pci.h"
+
+/* #define DEBUG_TCE 1   */
+/* #define MONITOR_TCE 1 */ /* Turn on to sanity check TCE generation. */
+
+
+/* Initialize so this guy does not end up in the BSS section.
+ * Only used to pass OF initialization data set in prom.c into the main 
+ * kernel code -- data ultimately copied into tceTables[].
+ */
+extern struct _of_tce_table of_tce_table[];
+
+extern struct pci_controller* hose_head;
+extern struct pci_controller** hose_tail;
+extern struct list_head iSeries_Global_Device_List;
+
+struct TceTable   virtBusVethTceTable;	/* Tce table for virtual ethernet */
+struct TceTable   virtBusVioTceTable;	/* Tce table for virtual I/O */
+
+struct iSeries_Device_Node iSeries_veth_dev_node = { LogicalSlot: 0xFF, DevTceTable: &virtBusVethTceTable };
+struct iSeries_Device_Node iSeries_vio_dev_node  = { LogicalSlot: 0xFF, DevTceTable: &virtBusVioTceTable };
+
+struct pci_dev    iSeries_veth_dev_st = { sysdata: &iSeries_veth_dev_node };
+struct pci_dev    iSeries_vio_dev_st  = { sysdata: &iSeries_vio_dev_node  };
+
+struct pci_dev  * iSeries_veth_dev = &iSeries_veth_dev_st;
+struct pci_dev  * iSeries_vio_dev  = &iSeries_vio_dev_st;
+
+/* Device TceTable is stored in Device Node */
+/* struct TceTable * tceTables[256]; */	/* Tce tables for 256 busses
+					 * Bus 255 is the virtual bus
+					 * zero indicates no bus defined
+					 */
+/* allocates a contiguous range of tces (power-of-2 size) */
+static inline long alloc_tce_range(struct TceTable *, 
+				   unsigned order );
+
+/* allocates a contiguous range of tces (power-of-2 size)
+ * assumes lock already held
+ */
+static long alloc_tce_range_nolock(struct TceTable *, 
+				   unsigned order );
+
+/* frees a contiguous range of tces (power-of-2 size) */
+static inline void free_tce_range(struct TceTable *, 
+				  long tcenum, 
+				  unsigned order );
+
+/* frees a contiguous rnage of tces (power-of-2 size)
+ * assumes lock already held
+ */
+void free_tce_range_nolock(struct TceTable *, 
+			   long tcenum, 
+			   unsigned order );
+
+/* allocates a range of tces and sets them to the pages  */
+static inline dma_addr_t get_tces( struct TceTable *, 
+				   unsigned order, 
+				   void *page, 
+				   unsigned numPages,
+				   int direction );
+
+static long test_tce_range( struct TceTable *, 
+			    long tcenum, 
+			    unsigned order );
+
+static unsigned fill_scatterlist_sg(struct scatterlist *sg, int nents, 
+				    dma_addr_t dma_addr, 
+				    unsigned long numTces );
+
+static unsigned long num_tces_sg( struct scatterlist *sg, 
+				  int nents );
+	
+static dma_addr_t create_tces_sg( struct TceTable *tbl, 
+				  struct scatterlist *sg, 
+			 	  int nents, 
+				  unsigned numTces,
+				  int direction );
+
+static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode,
+				      struct TceTable *tce_table_parms );
+
+static void getTceTableParmsPSeries( struct pci_controller *phb, 
+				     struct device_node *dn,
+				     struct TceTable *tce_table_parms );
+
+static void getTceTableParmsPSeriesLP(struct pci_controller *phb,
+				    struct device_node *dn,
+				    struct TceTable *newTceTable );
+
+static struct TceTable* findHwTceTable(struct TceTable * newTceTable );
+
+void create_pci_bus_tce_table( unsigned long token );
+
+u8 iSeries_Get_Bus( struct pci_dev * dv )
+{
+	return 0;
+}
+
+static inline struct TceTable *get_tce_table(struct pci_dev *dev)
+{
+	if (!dev)
+		dev = ppc64_isabridge_dev;
+	if (!dev)
+		return NULL;
+	if ( _machine == _MACH_iSeries ) {
+ 		return ISERIES_DEVNODE(dev)->DevTceTable;
+	} else {
+		return PCI_GET_DN(dev)->tce_table;
+	}
+}
+
+static unsigned long __inline__ count_leading_zeros64( unsigned long x )
+{
+	unsigned long lz;
+	asm("cntlzd %0,%1" : "=r"(lz) : "r"(x));
+	return lz;
+}
+
+static void tce_build_iSeries(struct TceTable *tbl, long tcenum, 
+			       unsigned long uaddr, int direction )
+{
+	u64 setTceRc;
+	union Tce tce;
+	
+	PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr);
+	PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", 
+	       tcenum, tbl, tbl->index);
+
+	tce.wholeTce = 0;
+	tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+
+	/* If for virtual bus */
+	if ( tbl->tceType == TCE_VB ) {
+		tce.tceBits.valid = 1;
+		tce.tceBits.allIo = 1;
+		if ( direction != PCI_DMA_TODEVICE )
+			tce.tceBits.readWrite = 1;
+	} else {
+		/* If for PCI bus */
+		tce.tceBits.readWrite = 1; // Read allowed 
+		if ( direction != PCI_DMA_TODEVICE )
+			tce.tceBits.pciWrite = 1;
+	}
+
+	setTceRc = HvCallXm_setTce((u64)tbl->index, 
+				   (u64)tcenum, 
+				   tce.wholeTce );
+	if(setTceRc) {
+		panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", setTceRc);
+	}
+}
+
+static void tce_build_pSeries(struct TceTable *tbl, long tcenum, 
+			       unsigned long uaddr, int direction )
+{
+	union Tce tce;
+	union Tce *tce_addr;
+	
+	PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr);
+	PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", 
+	       tcenum, tbl, tbl->index);
+
+	tce.wholeTce = 0;
+	tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+
+	tce.tceBits.readWrite = 1; // Read allowed 
+	if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1;
+
+	tce_addr = ((union Tce *)tbl->base) + tcenum;
+	*tce_addr = (union Tce)tce.wholeTce;
+
+	/* Make sure the update is visible to hardware. */
+	__asm__ __volatile__ ("sync" : : : "memory");
+}
+
+/* 
+ * Build a TceTable structure.  This contains a multi-level bit map which
+ * is used to manage allocation of the tce space.
+ */
+static struct TceTable *build_tce_table( struct TceTable * tbl )
+{
+	unsigned long bits, bytes, totalBytes;
+	unsigned long numBits[NUM_TCE_LEVELS], numBytes[NUM_TCE_LEVELS];
+	unsigned i, k, m;
+	unsigned char * pos, * p, b;
+
+	PPCDBG(PPCDBG_TCEINIT, "build_tce_table: tbl = 0x%lx\n", tbl);
+	spin_lock_init( &(tbl->lock) );
+	
+	tbl->mlbm.maxLevel = 0;
+
+	/* Compute number of bits and bytes for each level of the
+	 * multi-level bit map
+	 */ 
+	totalBytes = 0;
+	bits = tbl->size * (PAGE_SIZE / sizeof( union Tce ));
+	
+	for ( i=0; i<NUM_TCE_LEVELS; ++i ) {
+		bytes = ((bits+63)/64) * 8;
+		PPCDBG(PPCDBG_TCEINIT, "build_tce_table: level %d bits=%ld, bytes=%ld\n", i, bits, bytes );
+		numBits[i] = bits;
+		numBytes[i] = bytes;
+		bits /= 2;
+		totalBytes += bytes;
+	}
+	PPCDBG(PPCDBG_TCEINIT, "build_tce_table: totalBytes=%ld\n", totalBytes );
+	
+	pos = (char *)__get_free_pages( GFP_ATOMIC, get_order( totalBytes ));
+ 
+	if ( pos == NULL ) {
+		panic("PCI_DMA: Allocation failed in build_tce_table!\n");
+	}
+
+	/* For each level, fill in the pointer to the bit map,
+	 * and turn on the last bit in the bit map (if the
+	 * number of bits in the map is odd).  The highest
+	 * level will get all of its bits turned on.
+	 */
+	memset( pos, 0, totalBytes );
+	for (i=0; i<NUM_TCE_LEVELS; ++i) {
+		if ( numBytes[i] ) {
+			tbl->mlbm.level[i].map = pos;
+			tbl->mlbm.maxLevel = i;
+
+			if ( numBits[i] & 1 ) {
+				p = pos + numBytes[i] - 1;
+				m = (( numBits[i] % 8) - 1) & 7;
+				*p = 0x80 >> m;
+				PPCDBG(PPCDBG_TCEINIT, "build_tce_table: level %d last bit %x\n", i, 0x80>>m );
+			}
+		}
+		else
+			tbl->mlbm.level[i].map = 0;
+		pos += numBytes[i];
+		tbl->mlbm.level[i].numBits = numBits[i];
+		tbl->mlbm.level[i].numBytes = numBytes[i];
+	}
+
+	/* For the highest level, turn on all the bits */
+	
+	i = tbl->mlbm.maxLevel;
+	p = tbl->mlbm.level[i].map;
+	m = numBits[i];
+	PPCDBG(PPCDBG_TCEINIT, "build_tce_table: highest level (%d) has all bits set\n", i);
+	for (k=0; k<numBytes[i]; ++k) {
+		if ( m >= 8 ) {
+			/* handle full bytes */
+			*p++ = 0xff;
+			m -= 8;
+		}
+		else if(m>0) {
+			/* handle the last partial byte */
+			b = 0x80;
+			*p = 0;
+			while (m) {
+				*p |= b;
+				b >>= 1;
+				--m;
+			}
+		} else {
+			break;
+		}
+	}
+
+	return tbl;
+}
+
+static inline long alloc_tce_range( struct TceTable *tbl, unsigned order )
+{
+	long retval;
+	unsigned long flags;
+	
+	/* Lock the tce allocation bitmap */
+	spin_lock_irqsave( &(tbl->lock), flags );
+
+	/* Do the actual work */
+	retval = alloc_tce_range_nolock( tbl, order );
+	
+	/* Unlock the tce allocation bitmap */
+	spin_unlock_irqrestore( &(tbl->lock), flags );
+
+	return retval;
+}
+
+static long alloc_tce_range_nolock( struct TceTable *tbl, unsigned order )
+{
+	unsigned long numBits, numBytes;
+	unsigned long i, bit, block, mask;
+	long tcenum;
+	u64 * map;
+
+	/* If the order (power of 2 size) requested is larger than our
+	 * biggest, indicate failure
+	 */
+	if(order >= NUM_TCE_LEVELS) {
+		/* This can happen if block of TCE's are not found. This code      */
+		/*  maybe in a recursive loop looking up the bit map for the range.*/
+		panic("PCI_DMA: alloc_tce_range_nolock: invalid order: %d\n",order);
+	}
+	
+	numBits =  tbl->mlbm.level[order].numBits;
+	numBytes = tbl->mlbm.level[order].numBytes;
+	map =      (u64 *)tbl->mlbm.level[order].map;
+
+	/* Initialize return value to -1 (failure) */
+	tcenum = -1;
+
+	/* Loop through the bytes of the bitmap */
+	for (i=0; i<numBytes/8; ++i) {
+		if ( *map ) {
+			/* A free block is found, compute the block
+			 * number (of this size)
+			 */
+			bit = count_leading_zeros64( *map );
+			block = (i * 64) + bit;    /* Bit count to free entry */
+
+			/* turn off the bit in the map to indicate
+			 * that the block is now in use
+			 */
+			mask = 0x1UL << (63 - bit);
+			*map &= ~mask;
+
+			/* compute the index into our tce table for
+			 * the first tce in the block
+			 */
+			PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: allocating block %ld, (byte=%ld, bit=%ld) order %d\n", block, i, bit, order );
+			tcenum = block << order;
+			return tcenum;
+		}
+		++map;
+	}
+
+#ifdef DEBUG_TCE
+	if ( tcenum == -1 ) {
+		PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: no available blocks of order = %d\n", order );
+		if ( order < tbl->mlbm.maxLevel ) {
+			PPCDBG(PPCDBG_TCE, "alloc_tce_range_nolock: trying next bigger size\n" );
+		}
+		else {
+			panic("PCI_DMA: alloc_tce_range_nolock: maximum size reached...failing\n");
+		}
+	}
+#endif	
+	
+	/* If no block of the requested size was found, try the next
+	 * size bigger.  If one of those is found, return the second
+	 * half of the block to freespace and keep the first half
+	 */
+	if((tcenum == -1) && (order < (NUM_TCE_LEVELS - 1))) {
+		tcenum = alloc_tce_range_nolock( tbl, order+1 );
+		if ( tcenum != -1 ) {
+			free_tce_range_nolock( tbl, tcenum+(1<<order), order );
+		}
+	}
+	
+	/* Return the index of the first tce in the block
+	 * (or -1 if we failed)
+	 */
+	return tcenum;
+}
+
+static inline void free_tce_range(struct TceTable *tbl, 
+				  long tcenum, unsigned order )
+{
+	unsigned long flags;
+
+	/* Lock the tce allocation bitmap */
+	spin_lock_irqsave( &(tbl->lock), flags );
+
+	/* Do the actual work */
+	free_tce_range_nolock( tbl, tcenum, order );
+	
+	/* Unlock the tce allocation bitmap */
+	spin_unlock_irqrestore( &(tbl->lock), flags );
+
+}
+
+void free_tce_range_nolock(struct TceTable *tbl, 
+			   long tcenum, unsigned order )
+{
+	unsigned long block;
+	unsigned byte, bit, mask, b;
+	unsigned char  * map, * bytep;
+
+	if (order >= NUM_TCE_LEVELS) {
+		panic("PCI_DMA: free_tce_range: invalid order: %d\n",order);
+		return;
+	}
+
+	block = tcenum >> order;
+
+#ifdef MONITOR_TCE
+	if ( tcenum != (block << order ) ) {
+		printk("PCI_DMA: Free_tce_range: tcenum %lx misaligned for order %x\n",tcenum, order);
+		return;
+	}
+	if ( block >= tbl->mlbm.level[order].numBits ) {
+		printk("PCI_DMA: Free_tce_range: tcenum %lx is outside the range of this map (order %x, numBits %lx\n", 
+		       tcenum, order, tbl->mlbm.level[order].numBits );
+		return;
+	}
+	if ( test_tce_range( tbl, tcenum, order ) ) {
+		printk("PCI_DMA: Freeing range not allocated: tTceTable %p, tcenum %lx, order %x\n",tbl, tcenum, order );
+		return;
+	}
+#endif
+
+	map = tbl->mlbm.level[order].map;
+	byte  = block / 8;
+	bit   = block % 8;
+	mask  = 0x80 >> bit;
+	bytep = map + byte;
+
+#ifdef DEBUG_TCE
+	PPCDBG(PPCDBG_TCE,"free_tce_range_nolock: freeing block %ld (byte=%d, bit=%d) of order %d\n",
+	       block, byte, bit, order);
+#endif	
+
+#ifdef MONITOR_TCE
+	if ( *bytep & mask ) {
+		panic("PCI_DMA: Tce already free: TceTable %p, tcenum %lx, order %x\n",tbl,tcenum,order);
+	}
+#endif	
+
+	*bytep |= mask;
+
+	/* If there is a higher level in the bit map than this we may be
+	 * able to buddy up this block with its partner.
+	 *   If this is the highest level we can't buddy up
+	 *   If this level has an odd number of bits and
+	 *      we are freeing the last block we can't buddy up
+	 * Don't buddy up if it's in the first 1/4 of the level
+	 */
+	if (( block > (tbl->mlbm.level[order].numBits/4) ) &&
+	    (( block < tbl->mlbm.level[order].numBits-1 ) ||
+	      ( 0 == ( tbl->mlbm.level[order].numBits & 1)))) {
+		/* See if we can buddy up the block we just freed */
+		bit  &= 6;		/* get to the first of the buddy bits */
+		mask  = 0xc0 >> bit;	/* build two bit mask */
+		b     = *bytep & mask;	/* Get the two bits */
+		if ( 0 == (b ^ mask) ) { /* If both bits are on */
+			/* both of the buddy blocks are free we can combine them */
+			*bytep ^= mask;	/* turn off the two bits */
+			block = ( byte * 8 ) + bit; /* block of first of buddies */
+			tcenum = block << order;
+			/* free the buddied block */
+			PPCDBG(PPCDBG_TCE, 
+			       "free_tce_range: buddying blocks %ld & %ld\n",
+			       block, block+1);
+			free_tce_range_nolock( tbl, tcenum, order+1 ); 
+		}	
+	}
+}
+
+static long test_tce_range( struct TceTable *tbl, long tcenum, unsigned order )
+{
+	unsigned long block;
+	unsigned byte, bit, mask, b;
+	long	retval, retLeft, retRight;
+	unsigned char  * map;
+	
+	map = tbl->mlbm.level[order].map;
+	block = tcenum >> order;
+	byte = block / 8;		/* Byte within bitmap */
+	bit  = block % 8;		/* Bit within byte */
+	mask = 0x80 >> bit;		
+	b    = (*(map+byte) & mask );	/* 0 if block is allocated, else free */
+	if ( b ) 
+		retval = 1;		/* 1 == block is free */
+	else
+		retval = 0;		/* 0 == block is allocated */
+	/* Test bits at all levels below this to ensure that all agree */
+
+	if (order) {
+		retLeft  = test_tce_range( tbl, tcenum, order-1 );
+		retRight = test_tce_range( tbl, tcenum+(1<<(order-1)), order-1 );
+		if ( retLeft || retRight ) {
+			retval = 2;		
+		}
+	}
+
+	/* Test bits at all levels above this to ensure that all agree */
+	
+	return retval;
+}
+
+static inline dma_addr_t get_tces( struct TceTable *tbl, unsigned order, void *page, unsigned numPages, int direction )
+{
+	long tcenum;
+	unsigned long uaddr;
+	unsigned i;
+	dma_addr_t retTce = NO_TCE;
+
+	uaddr = (unsigned long)page & PAGE_MASK;
+	
+	/* Allocate a range of tces */
+	tcenum = alloc_tce_range( tbl, order );
+	if ( tcenum != -1 ) {
+		/* We got the tces we wanted */
+		tcenum += tbl->startOffset;	/* Offset into real TCE table */
+		retTce = tcenum << PAGE_SHIFT;	/* Set the return dma address */
+		/* Setup a tce for each page */
+		for (i=0; i<numPages; ++i) {
+			ppc_md.tce_build(tbl, tcenum, uaddr, direction); 
+			++tcenum;
+			uaddr += PAGE_SIZE;
+		}
+	}
+	else {
+		panic("PCI_DMA: Tce Allocation failure in get_tces. 0x%p\n",tbl);
+	}
+
+	return retTce; 
+}
+
+static void tce_free_iSeries(struct TceTable *tbl, dma_addr_t dma_addr, 
+			     unsigned order, unsigned numPages)
+{
+	u64 setTceRc;
+	long tcenum, freeTce, maxTcenum;
+	unsigned i;
+	union Tce tce;
+
+	maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
+	
+	tcenum = dma_addr >> PAGE_SHIFT;
+
+	freeTce = tcenum - tbl->startOffset;
+
+	if ( freeTce > maxTcenum ) {
+		PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n");
+		PPCDBG(PPCDBG_TCE, "\ttcenum    = 0x%lx\n", tcenum); 
+		PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum); 
+		PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl);
+		PPCDBG(PPCDBG_TCE, "\tbus#      = 0x%lx\n", (u64)tbl->busNumber );
+		PPCDBG(PPCDBG_TCE, "\tsize      = 0x%lx\n", (u64)tbl->size);
+		PPCDBG(PPCDBG_TCE, "\tstartOff  = 0x%lx\n", (u64)tbl->startOffset );
+		PPCDBG(PPCDBG_TCE, "\tindex     = 0x%lx\n", (u64)tbl->index);
+		return;
+	}
+	
+	for (i=0; i<numPages; ++i) {
+		tce.wholeTce = 0;
+		setTceRc = HvCallXm_setTce((u64)tbl->index, 
+					   (u64)tcenum, 
+					   tce.wholeTce );
+
+		if ( setTceRc ) {
+			panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", setTceRc);
+		}
+		++tcenum;
+	}
+	free_tce_range( tbl, freeTce, order );
+}
+
+static void tce_free_pSeries(struct TceTable *tbl, dma_addr_t dma_addr, 
+			     unsigned order, unsigned numPages)
+{
+	long tcenum, freeTce, maxTcenum;
+	unsigned i;
+	union Tce tce;
+	union Tce *tce_addr;
+
+	maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1;
+	
+	tcenum = dma_addr >> PAGE_SHIFT;
+	// tcenum -= tbl->startOffset;
+
+	freeTce = tcenum - tbl->startOffset;
+
+	if ( freeTce > maxTcenum ) {
+		PPCDBG(PPCDBG_TCE, "free_tces: tcenum > maxTcenum\n");
+		PPCDBG(PPCDBG_TCE, "\ttcenum    = 0x%lx\n", tcenum); 
+		PPCDBG(PPCDBG_TCE, "\tmaxTcenum = 0x%lx\n", maxTcenum); 
+		PPCDBG(PPCDBG_TCE, "\tTCE Table = 0x%lx\n", (u64)tbl);
+		PPCDBG(PPCDBG_TCE, "\tbus#      = 0x%lx\n", 
+		       (u64)tbl->busNumber );
+		PPCDBG(PPCDBG_TCE, "\tsize      = 0x%lx\n", (u64)tbl->size);
+		PPCDBG(PPCDBG_TCE, "\tstartOff  = 0x%lx\n", 
+		       (u64)tbl->startOffset );
+		PPCDBG(PPCDBG_TCE, "\tindex     = 0x%lx\n", (u64)tbl->index);
+		return;
+	}
+	
+	for (i=0; i<numPages; ++i) {
+		tce.wholeTce = 0;
+
+		tce_addr  = ((union Tce *)tbl->base) + tcenum;
+		*tce_addr = (union Tce)tce.wholeTce;
+
+		++tcenum;
+	}
+
+	/* Make sure the update is visible to hardware. */
+	__asm__ __volatile__ ("sync" : : : "memory");
+
+	free_tce_range( tbl, freeTce, order );
+}
+
+void __init create_virtual_bus_tce_table(void)
+{
+	struct TceTable *t;
+	struct TceTableManagerCB virtBusTceTableParms;
+	u64 absParmsPtr;
+
+	virtBusTceTableParms.busNumber = 255;	/* Bus 255 is the virtual bus */
+	virtBusTceTableParms.virtualBusFlag = 0xff; /* Ask for virtual bus */
+	
+	absParmsPtr = virt_to_absolute( (u64)&virtBusTceTableParms );
+	HvCallXm_getTceTableParms( absParmsPtr );
+	
+	virtBusVethTceTable.size = virtBusTceTableParms.size / 2;
+	virtBusVethTceTable.busNumber = virtBusTceTableParms.busNumber;
+	virtBusVethTceTable.startOffset = virtBusTceTableParms.startOffset;
+	virtBusVethTceTable.index = virtBusTceTableParms.index;
+	virtBusVethTceTable.tceType = TCE_VB;
+
+	virtBusVioTceTable.size = virtBusTceTableParms.size - virtBusVethTceTable.size;
+	virtBusVioTceTable.busNumber = virtBusTceTableParms.busNumber;
+	virtBusVioTceTable.startOffset = virtBusTceTableParms.startOffset +
+			virtBusVethTceTable.size * (PAGE_SIZE/sizeof(union Tce));
+	virtBusVioTceTable.index = virtBusTceTableParms.index;
+	virtBusVioTceTable.tceType = TCE_VB; 
+
+	t = build_tce_table( &virtBusVethTceTable );
+	if ( t ) {
+		/* tceTables[255] = t; */
+		//VirtBusVethTceTable = t;
+		printk( "Virtual Bus VETH TCE table built successfully.\n");
+		printk( "  TCE table size = %ld entries\n", 
+				(unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
+		printk( "  TCE table token = %d\n",
+				(unsigned)t->index );
+		printk( "  TCE table start entry = 0x%lx\n",
+				(unsigned long)t->startOffset );
+	}
+	else printk( "Virtual Bus VETH TCE table failed.\n");
+
+	t = build_tce_table( &virtBusVioTceTable );
+	if ( t ) {
+		//VirtBusVioTceTable = t;
+		printk( "Virtual Bus VIO TCE table built successfully.\n");
+		printk( "  TCE table size = %ld entries\n", 
+				(unsigned long)t->size*(PAGE_SIZE/sizeof(union Tce)) );
+		printk( "  TCE table token = %d\n",
+				(unsigned)t->index );
+		printk( "  TCE table start entry = 0x%lx\n",
+				(unsigned long)t->startOffset );
+	}
+	else printk( "Virtual Bus VIO TCE table failed.\n");
+}
+
+void create_tce_tables_for_buses(struct list_head *bus_list)
+{
+	struct pci_controller* phb;
+	struct device_node *dn, *first_dn;
+	int num_slots, num_slots_ilog2;
+	int first_phb = 1;
+
+	for (phb=hose_head;phb;phb=phb->next) {
+		first_dn = ((struct device_node *)phb->arch_data)->child;
+		/* Carve 2GB into the largest dma_window_size possible */
+		for (dn = first_dn, num_slots = 0; dn != NULL; dn = dn->sibling)
+			num_slots++;
+		num_slots_ilog2 = __ilog2(num_slots);
+		if ((1<<num_slots_ilog2) != num_slots)
+			num_slots_ilog2++;
+		phb->dma_window_size = 1 << (22 - num_slots_ilog2);
+		/* Reserve 16MB of DMA space on the first PHB.
+		 * We should probably be more careful and use firmware props.
+		 * In reality this space is remapped, not lost.  But we don't
+		 * want to get that smart to handle it -- too much work.
+		 */
+		phb->dma_window_base_cur = first_phb ? (1 << 12) : 0;
+		first_phb = 0;
+		for (dn = first_dn, num_slots = 0; dn != NULL; dn = dn->sibling) {
+			create_pci_bus_tce_table((unsigned long)dn);
+		}
+	}
+}
+
+void create_tce_tables_for_busesLP(struct list_head *bus_list)
+{
+	struct list_head *ln;
+	struct pci_bus *bus;
+	struct device_node *busdn;
+	u32 *dma_window;
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		busdn = PCI_GET_DN(bus);
+		/* NOTE: there should never be a window declared on a bus when
+		 * child devices also have a window.  If this should ever be
+		 * architected, we probably want children to have priority.
+		 * In reality, the PHB containing ISA has the property, but otherwise
+		 * it is the pci-bridges that have the property.
+		 */
+		dma_window = (u32 *)get_property(busdn, "ibm,dma-window", 0);
+		if (dma_window) {
+			/* Busno hasn't been copied yet.
+			 * Do it now because getTceTableParmsPSeriesLP needs it.
+			 */
+			busdn->busno = bus->number;
+			create_pci_bus_tce_table((unsigned long)busdn);
+		} else
+			create_tce_tables_for_busesLP(&bus->children);
+	}
+}
+
+void create_tce_tables(void) {
+	struct pci_dev *dev;
+	struct device_node *dn, *mydn;
+
+	if (_machine == _MACH_pSeriesLP) {
+		create_tce_tables_for_busesLP(&pci_root_buses);
+	}
+	else {
+		create_tce_tables_for_buses(&pci_root_buses);
+	}
+	/* Now copy the tce_table ptr from the bus devices down to every
+	 * pci device_node.  This means get_tce_table() won't need to search
+	 * up the device tree to find it.
+	 */
+	pci_for_each_dev(dev) {
+		mydn = dn = PCI_GET_DN(dev);
+		while (dn && dn->tce_table == NULL)
+			dn = dn->parent;
+		if (dn) {
+			mydn->tce_table = dn->tce_table;
+		}
+	}
+}
+
+
+/*
+ * iSeries token = iSeries_device_Node*
+ * pSeries token = pci_controller*
+ *
+ */
+void create_pci_bus_tce_table( unsigned long token ) {
+	struct TceTable * newTceTable;
+
+	PPCDBG(PPCDBG_TCE, "Entering create_pci_bus_tce_table.\n");
+	PPCDBG(PPCDBG_TCE, "\ttoken = 0x%lx\n", token);
+
+	newTceTable = (struct TceTable *)kmalloc( sizeof(struct TceTable), GFP_KERNEL );
+
+	/*****************************************************************/
+ 	/* For the iSeries machines, the HvTce Table can be one of three */
+ 	/* flavors,                                                      */
+ 	/* - Single bus TCE table,                                       */
+ 	/* - Tce Table Share between buses,                              */
+ 	/* - Tce Table per logical slot.                                 */
+	/*****************************************************************/
+	if(_machine == _MACH_iSeries) {
+
+		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;
+		getTceTableParmsiSeries(DevNode,newTceTable);
+
+		/* Look for existing TCE table for this device.          */
+		DevNode->DevTceTable = findHwTceTable(newTceTable );
+		if( DevNode->DevTceTable == NULL) {
+			DevNode->DevTceTable = build_tce_table( newTceTable );
+		}
+		else {
+		    /* We're using a shared table, free this new one.    */
+		    kfree(newTceTable);
+		}
+		printk("Pci Device 0x%p TceTable: %p\n",DevNode,DevNode->DevTceTable);
+ 		return;
+	}
+	/* pSeries Leg */
+	else {
+		struct device_node *dn;
+		struct pci_controller *phb;
+
+		dn = (struct device_node *)token;
+		phb = dn->phb;
+		if (_machine == _MACH_pSeries)
+			getTceTableParmsPSeries(phb, dn, newTceTable);
+		else
+			getTceTableParmsPSeriesLP(phb, dn, newTceTable);
+
+		dn->tce_table  = build_tce_table( newTceTable );
+	}
+}
+
+/***********************************************************************/
+/* This function compares the known Tce tables to find a TceTable that */
+/* has already been built for hardware TCEs.                           */
+/* Search the complete(all devices) for a TCE table assigned.  If the  */
+/* startOffset, index, and size match, then the TCE for this device has*/
+/* already been built and it should be shared with this device         */
+/***********************************************************************/
+static struct TceTable* findHwTceTable(struct TceTable * newTceTable )
+{
+	struct list_head* Device_Node_Ptr    = iSeries_Global_Device_List.next;
+	/* Cache the compare values. */
+	u64  startOffset = newTceTable->startOffset;
+	u64  index       = newTceTable->index;
+	u64  size        = newTceTable->size;
+
+	while(Device_Node_Ptr != &iSeries_Global_Device_List) {
+		struct iSeries_Device_Node* CmprNode = (struct iSeries_Device_Node*)Device_Node_Ptr;
+		if( CmprNode->DevTceTable != NULL &&
+		    CmprNode->DevTceTable->tceType == TCE_PCI) {
+			if( CmprNode->DevTceTable->startOffset == startOffset &&
+			    CmprNode->DevTceTable->index       == index       &&
+			    CmprNode->DevTceTable->size        == size        ) {
+				printk("PCI TCE table matches 0x%p \n",CmprNode->DevTceTable);
+				return CmprNode->DevTceTable;
+			}
+		}
+		/* Get next Device Node in List             */
+		Device_Node_Ptr = Device_Node_Ptr->next;
+	}
+	return NULL;
+}
+
+/***********************************************************************/
+/* Call Hv with the architected data structure to get TCE table info.  */
+/* info. Put the returned data into the Linux representation of the    */
+/* TCE table data.                                                     */
+/* The Hardware Tce table comes in three flavors.                      */ 
+/* 1. TCE table shared between Buses.                                  */
+/* 2. TCE table per Bus.                                               */
+/* 3. TCE Table per IOA.                                               */
+/***********************************************************************/
+static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode,
+				    struct TceTable* newTceTable )
+{
+	struct TceTableManagerCB* pciBusTceTableParms = (struct TceTableManagerCB*)kmalloc( sizeof(struct TceTableManagerCB), GFP_KERNEL );
+	if(pciBusTceTableParms == NULL) panic("PCI_DMA: TCE Table Allocation failed.");
+
+	memset( (void*)pciBusTceTableParms,0,sizeof(struct TceTableManagerCB) );
+	pciBusTceTableParms->busNumber      = ISERIES_BUS(DevNode);
+	pciBusTceTableParms->logicalSlot    = DevNode->LogicalSlot;
+	pciBusTceTableParms->virtualBusFlag = 0;
+
+	HvCallXm_getTceTableParms( REALADDR(pciBusTceTableParms) );
+
+        /* PciTceTableParms Bus:0x18 Slot:0x04 Start:0x000000 Offset:0x04c000 Size:0x0020 */
+	printk("PciTceTableParms Bus:0x%02lx Slot:0x%02x Start:0x%06lx Offset:0x%06lx Size:0x%04lx\n",
+	       pciBusTceTableParms->busNumber,
+	       pciBusTceTableParms->logicalSlot,
+	       pciBusTceTableParms->start,
+	       pciBusTceTableParms->startOffset,
+	       pciBusTceTableParms->size);
+
+	newTceTable->size        = pciBusTceTableParms->size;
+	newTceTable->busNumber   = pciBusTceTableParms->busNumber;
+	newTceTable->startOffset = pciBusTceTableParms->startOffset;
+	newTceTable->index       = pciBusTceTableParms->index;
+	newTceTable->tceType     = TCE_PCI;
+
+	kfree(pciBusTceTableParms);
+}
+
+static void getTceTableParmsPSeries(struct pci_controller *phb,
+				    struct device_node *dn,
+				    struct TceTable *newTceTable ) {
+	phandle node;
+	unsigned long i;
+
+	node = ((struct device_node *)(phb->arch_data))->node;
+
+	PPCDBG(PPCDBG_TCEINIT, "getTceTableParms: start\n"); 
+	PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table = 0x%lx\n", of_tce_table); 
+	PPCDBG(PPCDBG_TCEINIT, "\tphb          = 0x%lx\n", phb); 
+	PPCDBG(PPCDBG_TCEINIT, "\tdn           = 0x%lx\n", dn); 
+	PPCDBG(PPCDBG_TCEINIT, "\tdn->name     = %s\n", dn->name); 
+	PPCDBG(PPCDBG_TCEINIT, "\tdn->full_name= %s\n", dn->full_name); 
+	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable  = 0x%lx\n", newTceTable); 
+	PPCDBG(PPCDBG_TCEINIT, "\tdma_window_size = 0x%lx\n", phb->dma_window_size); 
+
+	i = 0;
+	while(of_tce_table[i].node) {
+		PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].node = 0x%lx\n", 
+		       i, of_tce_table[i].node);
+		PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].base = 0x%lx\n", 
+		       i, of_tce_table[i].base);
+		PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].size = 0x%lx\n", 
+		       i, of_tce_table[i].size >> PAGE_SHIFT);
+		PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data->node = 0x%lx\n", 
+		       node);
+
+		if(of_tce_table[i].node == node) {
+			memset((void *)of_tce_table[i].base, 
+			       0, of_tce_table[i].size);
+			newTceTable->busNumber = phb->bus->number;
+
+			/* Units of tce entries.                        */
+			newTceTable->startOffset = phb->dma_window_base_cur;
+
+			/* Adjust the current table offset to the next  */
+			/* region.  Measured in TCE entries. Force an   */
+			/* alignment to the size alloted per IOA. This  */
+			/* makes it easier to remove the 1st 16MB.      */
+			phb->dma_window_base_cur += (phb->dma_window_size>>3);
+			phb->dma_window_base_cur &= 
+				~((phb->dma_window_size>>3)-1);
+
+			/* Set the tce table size - measured in units   */
+			/* of pages of tce table.                       */
+			newTceTable->size = ((phb->dma_window_base_cur -
+					      newTceTable->startOffset) << 3)
+					      >> PAGE_SHIFT;
+
+			/* Test if we are going over 2GB of DMA space.  */
+			if(phb->dma_window_base_cur > (1 << 19)) { 
+				panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); 
+			}
+
+			newTceTable->base = of_tce_table[i].base;
+			newTceTable->index = 0;
+			
+			PPCDBG(PPCDBG_TCEINIT, 
+			       "\tnewTceTable->base        = 0x%lx\n",
+			       newTceTable->base);
+			PPCDBG(PPCDBG_TCEINIT, 
+			       "\tnewTceTable->startOffset = 0x%lx"
+			       "(# tce entries)\n", 
+			       newTceTable->startOffset);
+			PPCDBG(PPCDBG_TCEINIT, 
+			       "\tnewTceTable->size        = 0x%lx"
+			       "(# pages of tce table)\n", 
+			       newTceTable->size);
+		}
+		i++;
+	}
+}
+
+/*
+ * getTceTableParmsPSeriesLP
+ *
+ * Function: On pSeries LPAR systems, return TCE table info, given a pci bus.
+ *
+ * ToDo: properly interpret the ibm,dma-window property.  The definition is:
+ *	logical-bus-number	(1 word)
+ *	phys-address		(#address-cells words)
+ *	size			(#cell-size words)
+ *
+ * Currently we hard code these sizes (more or less).
+ */
+static void getTceTableParmsPSeriesLP(struct pci_controller *phb,
+				    struct device_node *dn,
+				    struct TceTable *newTceTable ) {
+	u32 *dma_window = (u32 *)get_property(dn, "ibm,dma-window", 0);
+	if (!dma_window) {
+		panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name);
+	}
+
+	newTceTable->busNumber = dn->busno;
+	newTceTable->size = (((((unsigned long)dma_window[4] << 32) | (unsigned long)dma_window[5]) >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
+	newTceTable->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12);
+	newTceTable->base = 0;
+	newTceTable->index = dma_window[0];
+	PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->busno);
+	PPCDBG(PPCDBG_TCEINIT, "\tDevice = %s\n", dn->full_name);
+	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->index       = 0x%lx\n", newTceTable->index);
+	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->startOffset = 0x%lx\n", newTceTable->startOffset);
+	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->size        = 0x%lx\n", newTceTable->size);
+}
+
+/* Allocates a contiguous real buffer and creates TCEs over it.
+ * Returns the virtual address of the buffer and sets dma_handle
+ * to the dma address (tce) of the first page.
+ */
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t *dma_handle)
+{
+	struct TceTable * tbl;
+	void *ret = NULL;
+	unsigned order, nPages;
+	dma_addr_t tce;
+
+	PPCDBG(PPCDBG_TCE, "pci_alloc_consistent:\n");
+	PPCDBG(PPCDBG_TCE, "\thwdev      = 0x%16.16lx\n", hwdev);
+	PPCDBG(PPCDBG_TCE, "\tsize       = 0x%16.16lx\n", size);
+	PPCDBG(PPCDBG_TCE, "\tdma_handle = 0x%16.16lx\n", dma_handle);	
+
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+	nPages = 1 << order;
+
+	tbl = get_tce_table(hwdev); 
+
+	if ( tbl ) {
+		/* Alloc enough pages (and possibly more) */
+		ret = (void *)__get_free_pages( GFP_ATOMIC, order );
+		if ( ret ) {
+			/* Page allocation succeeded */
+			memset(ret, 0, nPages << PAGE_SHIFT);
+			/* Set up tces to cover the allocated range */
+			tce = get_tces( tbl, order, ret, nPages, PCI_DMA_BIDIRECTIONAL );
+			if ( tce == NO_TCE ) {
+				PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tces failed\n" );
+				free_pages( (unsigned long)ret, order );
+				ret = NULL;
+			}
+			else
+			{
+				*dma_handle = tce;
+			}
+		}
+		else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: __get_free_pages failed for order = %d\n", order);
+	}
+	else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tce_table failed for 0x%016lx\n", hwdev);
+
+	PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: dma_handle = 0x%16.16lx\n", *dma_handle);	
+	PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: return     = 0x%16.16lx\n", ret);	
+	return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+	struct TceTable * tbl;
+	unsigned order, nPages;
+	
+	PPCDBG(PPCDBG_TCE, "pci_free_consistent:\n");
+	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, dma_handle = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, dma_handle, vaddr);	
+
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+	nPages = 1 << order;
+
+	if ( order > 10 )
+		PPCDBG(PPCDBG_TCE, "pci_free_consistent: order=%d, size=%d, nPages=%d, dma_handle=%016lx, vaddr=%016lx\n",
+			order, size, nPages, (unsigned long)dma_handle, (unsigned long)vaddr );
+	
+	tbl = get_tce_table(hwdev); 
+
+	if ( tbl ) {
+		ppc_md.tce_free(tbl, dma_handle, order, nPages);
+		free_pages( (unsigned long)vaddr, order );
+	}
+}
+
+/* Creates TCEs for a user provided buffer.  The user buffer must be 
+ * contiguous real kernel storage (not vmalloc).  The address of the buffer
+ * passed here is the kernel (virtual) address of the buffer.  The buffer
+ * need not be page aligned, the dma_addr_t returned will point to the same
+ * byte within the page as vaddr.
+ */
+dma_addr_t pci_map_single(struct pci_dev *hwdev, void *vaddr, 
+			  size_t size, int direction )
+{
+	struct TceTable * tbl;
+	dma_addr_t dma_handle = NO_TCE;
+	unsigned long uaddr;
+	unsigned order, nPages;
+
+	PPCDBG(PPCDBG_TCE, "pci_map_single:\n");
+	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, direction, vaddr);	
+	if ( direction == PCI_DMA_NONE )
+		BUG();
+	
+	uaddr = (unsigned long)vaddr;
+	nPages = PAGE_ALIGN( uaddr + size ) - ( uaddr & PAGE_MASK );
+	order = get_order( nPages & PAGE_MASK );
+	nPages >>= PAGE_SHIFT;
+	
+	tbl = get_tce_table(hwdev); 
+
+	if ( tbl ) {
+		dma_handle = get_tces( tbl, order, vaddr, nPages, direction );
+		dma_handle |= ( uaddr & ~PAGE_MASK );
+	}
+
+	return dma_handle;
+}
+
+void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
+{
+	struct TceTable * tbl;
+	unsigned order, nPages;
+	
+	PPCDBG(PPCDBG_TCE, "pci_unmap_single:\n");
+	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, dma_handle = 0x%16.16lx\n", hwdev, size, direction, dma_handle);	
+	if ( direction == PCI_DMA_NONE )
+		BUG();
+
+	nPages = PAGE_ALIGN( dma_handle + size ) - ( dma_handle & PAGE_MASK );
+	order = get_order( nPages & PAGE_MASK );
+	nPages >>= PAGE_SHIFT;
+
+	if ( order > 10 )
+		PPCDBG(PPCDBG_TCE, "pci_unmap_single: order=%d, size=%d, nPages=%d, dma_handle=%016lx\n",
+			order, size, nPages, (unsigned long)dma_handle );
+	
+	tbl = get_tce_table(hwdev); 
+
+	if ( tbl ) 
+		ppc_md.tce_free(tbl, dma_handle, order, nPages);
+
+}
+
+/* Figure out how many TCEs are actually going to be required
+ * to map this scatterlist.  This code is not optimal.  It 
+ * takes into account the case where entry n ends in the same
+ * page in which entry n+1 starts.  It does not handle the 
+ * general case of entry n ending in the same page in which 
+ * entry m starts.   
+ */
+static unsigned long num_tces_sg( struct scatterlist *sg, int nents )
+{
+	unsigned long nTces, numPages, startPage, endPage, prevEndPage;
+	unsigned i;
+
+	prevEndPage = 0;
+	nTces = 0;
+
+	for (i=0; i<nents; ++i) {
+		/* Compute the starting page number and
+		 * the ending page number for this entry
+		 */
+		startPage = (unsigned long)sg->address >> PAGE_SHIFT;
+		endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT;
+		numPages = endPage - startPage + 1;
+		/* Simple optimization: if the previous entry ended
+		 * in the same page in which this entry starts
+		 * then we can reduce the required pages by one.
+		 * This matches assumptions in fill_scatterlist_sg and
+		 * create_tces_sg
+		 */
+		if ( startPage == prevEndPage )
+			--numPages;
+		nTces += numPages;
+		prevEndPage = endPage;
+		sg++;
+	}
+	return nTces;
+}
+
+/* Fill in the dma data in the scatterlist
+ * return the number of dma sg entries created
+ */
+static unsigned fill_scatterlist_sg( struct scatterlist *sg, int nents, 
+				 dma_addr_t dma_addr , unsigned long numTces)
+{
+	struct scatterlist *dma_sg;
+	u32 cur_start_dma;
+	unsigned long cur_len_dma, cur_end_virt, uaddr;
+	unsigned num_dma_ents;
+
+	dma_sg = sg;
+	num_dma_ents = 1;
+
+	/* Process the first sg entry */
+	cur_start_dma = dma_addr + ((unsigned long)sg->address & (~PAGE_MASK));
+	cur_len_dma = sg->length;
+	/* cur_end_virt holds the address of the byte immediately after the
+	 * end of the current buffer.
+	 */
+	cur_end_virt = (unsigned long)sg->address + cur_len_dma;
+	/* Later code assumes that unused sg->dma_address and sg->dma_length
+	 * fields will be zero.  Other archs seem to assume that the user
+	 * (device driver) guarantees that...I don't want to depend on that
+	 */
+	sg->dma_address = sg->dma_length = 0;
+	
+	/* Process the rest of the sg entries */
+	while (--nents) {
+		++sg;
+		/* Clear possibly unused fields. Note: sg >= dma_sg so
+		 * this can't be clearing a field we've already set
+		 */
+		sg->dma_address = sg->dma_length = 0;
+
+		/* Check if it is possible to make this next entry
+		 * contiguous (in dma space) with the previous entry.
+		 */
+		
+		/* The entries can be contiguous in dma space if
+		 * the previous entry ends immediately before the
+		 * start of the current entry (in virtual space)
+		 * or if the previous entry ends at a page boundary
+		 * and the current entry starts at a page boundary.
+		 */
+		uaddr = (unsigned long)sg->address;
+		if ( ( uaddr != cur_end_virt ) &&
+		     ( ( ( uaddr | cur_end_virt ) & (~PAGE_MASK) ) ||
+		       ( ( uaddr & PAGE_MASK ) == ( ( cur_end_virt-1 ) & PAGE_MASK ) ) ) ) {
+			/* This entry can not be contiguous in dma space.
+			 * save the previous dma entry and start a new one
+			 */
+			dma_sg->dma_address = cur_start_dma;
+			dma_sg->dma_length  = cur_len_dma;
+
+			++dma_sg;
+			++num_dma_ents;
+			
+			cur_start_dma += cur_len_dma-1;
+			/* If the previous entry ends and this entry starts
+			 * in the same page then they share a tce.  In that
+			 * case don't bump cur_start_dma to the next page 
+			 * in dma space.  This matches assumptions made in
+			 * num_tces_sg and create_tces_sg.
+			 */
+			if ((uaddr & PAGE_MASK) == ((cur_end_virt-1) & PAGE_MASK))
+				cur_start_dma &= PAGE_MASK;
+			else
+				cur_start_dma = PAGE_ALIGN(cur_start_dma+1);
+			cur_start_dma += ( uaddr & (~PAGE_MASK) );
+			cur_len_dma = 0;
+		}
+		/* Accumulate the length of this entry for the next 
+		 * dma entry
+		 */
+		cur_len_dma += sg->length;
+		cur_end_virt = uaddr + sg->length;
+	}
+	/* Fill in the last dma entry */
+	dma_sg->dma_address = cur_start_dma;
+	dma_sg->dma_length  = cur_len_dma;
+
+	if ((((cur_start_dma +cur_len_dma - 1)>> PAGE_SHIFT) - (dma_addr >> PAGE_SHIFT) + 1) != numTces)
+	  {
+	    PPCDBG(PPCDBG_TCE, "fill_scatterlist_sg: numTces %ld, used tces %d\n",
+		   numTces,
+		   (unsigned)(((cur_start_dma + cur_len_dma - 1) >> PAGE_SHIFT) - (dma_addr >> PAGE_SHIFT) + 1));
+	  }
+	
+
+	return num_dma_ents;
+}
+
+/* Call the hypervisor to create the TCE entries.
+ * return the number of TCEs created
+ */
+static dma_addr_t create_tces_sg( struct TceTable *tbl, struct scatterlist *sg, 
+		   int nents, unsigned numTces, int direction )
+{
+	unsigned order, i, j;
+	unsigned long startPage, endPage, prevEndPage, numPages, uaddr;
+	long tcenum, starttcenum;
+	dma_addr_t dmaAddr;
+
+	dmaAddr = NO_TCE;
+
+	order = get_order( numTces << PAGE_SHIFT );
+	/* allocate a block of tces */
+	tcenum = alloc_tce_range( tbl, order );
+	if ( tcenum != -1 ) {
+		tcenum += tbl->startOffset;
+		starttcenum = tcenum;
+		dmaAddr = tcenum << PAGE_SHIFT;
+		prevEndPage = 0;
+		for (j=0; j<nents; ++j) {
+			startPage = (unsigned long)sg->address >> PAGE_SHIFT;
+			endPage = ((unsigned long)sg->address + sg->length - 1) >> PAGE_SHIFT;
+			numPages = endPage - startPage + 1;
+			
+			uaddr = (unsigned long)sg->address;
+
+			/* If the previous entry ended in the same page that
+			 * the current page starts then they share that
+			 * tce and we reduce the number of tces we need
+			 * by one.  This matches assumptions made in
+			 * num_tces_sg and fill_scatterlist_sg
+			 */
+			if ( startPage == prevEndPage ) {
+				--numPages;
+				uaddr += PAGE_SIZE;
+			}
+			
+			for (i=0; i<numPages; ++i) {
+			  ppc_md.tce_build(tbl, tcenum, uaddr, direction); 
+			  ++tcenum;
+			  uaddr += PAGE_SIZE;
+			}
+			
+			prevEndPage = endPage;
+			sg++;
+		}
+		if ((tcenum - starttcenum) != numTces)
+	    		PPCDBG(PPCDBG_TCE, "create_tces_sg: numTces %d, tces used %d\n",
+		   		numTces, (unsigned)(tcenum - starttcenum));
+
+	}
+
+	return dmaAddr;
+}
+
+int pci_map_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction )
+{
+	struct TceTable * tbl;
+	unsigned numTces;
+	int num_dma;
+	dma_addr_t dma_handle;
+
+	PPCDBG(PPCDBG_TCE, "pci_map_sg:\n");
+	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nents = 0x%16.16lx\n", hwdev, sg, direction, nents);	
+	/* Fast path for a single entry scatterlist */
+	if ( nents == 1 ) {
+		sg->dma_address = pci_map_single( hwdev, sg->address, 
+					sg->length, direction );
+		sg->dma_length = sg->length;
+		return 1;
+	}
+	
+	if ( direction == PCI_DMA_NONE )
+		BUG();
+	
+	tbl = get_tce_table(hwdev); 
+
+	if ( tbl ) {
+		/* Compute the number of tces required */
+		numTces = num_tces_sg( sg, nents );
+		/* Create the tces and get the dma address */ 
+		dma_handle = create_tces_sg( tbl, sg, nents, numTces, direction );
+
+		/* Fill in the dma scatterlist */
+		num_dma = fill_scatterlist_sg( sg, nents, dma_handle, numTces );
+	}
+
+	return num_dma;
+}
+
+void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction )
+{
+	struct TceTable * tbl;
+	unsigned order, numTces, i;
+	dma_addr_t dma_end_page, dma_start_page;
+	
+	PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n");
+	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms);	
+
+	if ( direction == PCI_DMA_NONE )
+		BUG();
+
+	dma_start_page = sg->dma_address & PAGE_MASK;
+	for ( i=nelms; i>0; --i ) {
+		unsigned k = i - 1;
+		if ( sg[k].dma_length ) {
+			dma_end_page = ( sg[k].dma_address +
+					 sg[k].dma_length - 1 ) & PAGE_MASK;
+			break;
+		}
+	}
+
+	numTces = ((dma_end_page - dma_start_page ) >> PAGE_SHIFT) + 1;
+	order = get_order( numTces << PAGE_SHIFT );
+
+	if ( order > 10 )
+		PPCDBG(PPCDBG_TCE, "pci_unmap_sg: order=%d, numTces=%d, nelms=%d, dma_start_page=%016lx, dma_end_page=%016lx\n",
+			order, numTces, nelms, (unsigned long)dma_start_page, (unsigned long)dma_end_page );
+	
+	tbl = get_tce_table(hwdev); 
+
+	if ( tbl ) 
+		ppc_md.tce_free( tbl, dma_start_page, order, numTces );
+
+}
+
+/*
+ * phb_tce_table_init
+ * 
+ * Function: Display TCE config registers.  Could be easily changed
+ *           to initialize the hardware to use TCEs.
+ */
+unsigned long phb_tce_table_init(struct pci_controller *phb) {
+	unsigned int r, cfg_rw, i;	
+	unsigned long r64;	
+	phandle node;
+
+	PPCDBG(PPCDBG_TCE, "phb_tce_table_init: start.\n"); 
+
+	node = ((struct device_node *)(phb->arch_data))->node;
+
+	PPCDBG(PPCDBG_TCEINIT, "\tphb            = 0x%lx\n", phb); 
+	PPCDBG(PPCDBG_TCEINIT, "\tphb->type      = 0x%lx\n", phb->type); 
+	PPCDBG(PPCDBG_TCEINIT, "\tphb->phb_regs  = 0x%lx\n", phb->phb_regs); 
+	PPCDBG(PPCDBG_TCEINIT, "\tphb->chip_regs = 0x%lx\n", phb->chip_regs); 
+	PPCDBG(PPCDBG_TCEINIT, "\tphb: node      = 0x%lx\n", node);
+	PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data = 0x%lx\n", phb->arch_data); 
+
+	i = 0;
+	while(of_tce_table[i].node) {
+		if(of_tce_table[i].node == node) {
+			if(phb->type == phb_type_python) {
+				r = *(((unsigned int *)phb->phb_regs) + (0xf10>>2)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tTAR(low)    = 0x%x\n", r);
+				r = *(((unsigned int *)phb->phb_regs) + (0xf00>>2)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tTAR(high)   = 0x%x\n", r);
+				r = *(((unsigned int *)phb->phb_regs) + (0xfd0>>2)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tPHB cfg(rw) = 0x%x\n", r);
+				break;
+			} else if(phb->type == phb_type_speedwagon) {
+				r64 = *(((unsigned long *)phb->chip_regs) + 
+					(0x800>>3)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tNCFG    = 0x%lx\n", r64);
+				r64 = *(((unsigned long *)phb->chip_regs) + 
+					(0x580>>3)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tTAR0    = 0x%lx\n", r64);
+				r64 = *(((unsigned long *)phb->chip_regs) + 
+					(0x588>>3)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tTAR1    = 0x%lx\n", r64);
+				r64 = *(((unsigned long *)phb->chip_regs) + 
+					(0x590>>3)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tTAR2    = 0x%lx\n", r64);
+				r64 = *(((unsigned long *)phb->chip_regs) + 
+					(0x598>>3)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tTAR3    = 0x%lx\n", r64);
+				cfg_rw = *(((unsigned int *)phb->chip_regs) + 
+					   ((0x160 +
+					     (((phb->local_number)+8)<<12))>>2)); 
+				PPCDBG(PPCDBG_TCEINIT, "\tcfg_rw = 0x%x\n", cfg_rw);
+			}
+		}
+		i++;
+	}
+
+	PPCDBG(PPCDBG_TCEINIT, "phb_tce_table_init: done\n"); 
+
+	return(0); 
+}
+
+/* These are called very early. */
+void tce_init_pSeries(void)
+{
+	ppc_md.tce_build = tce_build_pSeries;
+	ppc_md.tce_free  = tce_free_pSeries;
+}
+
+void tce_init_iSeries(void)
+{
+	ppc_md.tce_build = tce_build_iSeries;
+	ppc_md.tce_free  = tce_free_iSeries;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pci_dn.c linux-2.4.19-pre5/arch/ppc64/kernel/pci_dn.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pci_dn.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pci_dn.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,386 @@
+/*
+ * pci_dn.c
+ *
+ * Copyright (C) 2001 Todd Inglett, IBM Corporation
+ *
+ * PCI manipulation via device_nodes.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *    
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/init.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppcdebug.h>
+#include <asm/Naca.h>
+#include <asm/pci_dma.h>
+
+#include "pci.h"
+
+/* Traverse_func that inits the PCI fields of the device node.
+ * NOTE: this *must* be done before read/write config to the device.
+ */
+static void * __init
+update_dn_pci_info(struct device_node *dn, void *data)
+{
+	struct pci_controller *phb = (struct pci_controller *)data;
+	u32 *regs;
+	char *device_type = get_property(dn, "device_type", 0);
+
+	dn->phb = phb;
+	if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) {
+		/* special case for PHB's.  Sigh. */
+		regs = (u32 *)get_property(dn, "bus-range", 0);
+		dn->busno = regs[0];
+		dn->devfn = 0;	/* assumption */
+	} else {
+		regs = (u32 *)get_property(dn, "reg", 0);
+		if (regs) {
+			/* First register entry is addr (00BBSS00)  */
+			dn->busno = (regs[0] >> 16) & 0xff;
+			dn->devfn = (regs[0] >> 8) & 0xff;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Hit all the BARs of all the devices with values from OF.
+ * This is unnecessary on most systems, but also harmless.
+ */
+static void * __init
+write_OF_bars(struct device_node *dn, void *data)
+{
+	int i;
+	u32 oldbar, newbar, newbartest;
+	u8  config_offset;
+	char *name = get_property(dn, "name", 0);
+	char *device_type = get_property(dn, "device_type", 0);
+	char devname[128];
+	sprintf(devname, "%04x:%02x.%x %s (%s)", dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn), name ? name : "<no name>", device_type ? device_type : "<unknown type>");
+
+	if (device_type && strcmp(device_type, "pci") == 0 &&
+	    get_property(dn, "class-code", 0) == 0)
+		return NULL;	/* This is probably a phb.  Skip it. */
+
+	if (dn->n_addrs == 0)
+		return NULL;	/* This is normal for some adapters or bridges */
+
+	if (dn->addrs == NULL) {
+		/* This shouldn't happen. */
+		printk(KERN_WARNING "write_OF_bars %s: device has %d BARs, but no addrs recorded\n", devname, dn->n_addrs);
+		return NULL;
+	}
+
+#ifndef CONFIG_PPC_ISERIES 
+	for (i = 0; i < dn->n_addrs; i++) {
+		newbar = dn->addrs[i].address;
+		config_offset = dn->addrs[i].space & 0xff;
+		if (ppc_md.pcibios_read_config_dword(dn, config_offset, &oldbar) != PCIBIOS_SUCCESSFUL) {
+			printk(KERN_WARNING "write_OF_bars %s: read BAR%d failed\n", devname, i);
+			continue;
+		}
+		/* Need to update this BAR. */
+		if (ppc_md.pcibios_write_config_dword(dn, config_offset, newbar) != PCIBIOS_SUCCESSFUL) {
+			printk(KERN_WARNING "write_OF_bars %s: write BAR%d with 0x%08x failed (old was 0x%08x)\n", devname, i, newbar, oldbar);
+			continue;
+		}
+		/* sanity check */
+		if (ppc_md.pcibios_read_config_dword(dn, config_offset, &newbartest) != PCIBIOS_SUCCESSFUL) {
+			printk(KERN_WARNING "write_OF_bars %s: sanity test read BAR%d failed?\n", devname, i);
+			continue;
+		}
+		if ((newbar & PCI_BASE_ADDRESS_MEM_MASK) != (newbartest & PCI_BASE_ADDRESS_MEM_MASK)) {
+			printk(KERN_WARNING "write_OF_bars %s: oops...BAR%d read back as 0x%08x%s!\n", devname, i, newbartest, (oldbar & PCI_BASE_ADDRESS_MEM_MASK) == (newbartest & PCI_BASE_ADDRESS_MEM_MASK) ? " (original value)" : "");
+			continue;
+		}
+	}
+#endif
+	return NULL; 
+}
+
+#if 0
+/* Traverse_func that starts the BIST (self test) */
+static void * __init
+startBIST(struct device_node *dn, void *data)
+{
+	struct pci_controller *phb = (struct pci_controller *)data;
+	u8 bist;
+
+	char *name = get_property(dn, "name", 0);
+	udbg_printf("startBIST: %s phb=%p, device=%p\n", name ? name : "<unknown>", phb, dn);
+
+	if (ppc_md.pcibios_read_config_byte(dn, PCI_BIST, &bist) == PCIBIOS_SUCCESSFUL) {
+		if (bist & PCI_BIST_CAPABLE) {
+			udbg_printf("  -> is BIST capable!\n", phb, dn);
+			/* Start bist here */
+		}
+	}
+	return NULL;
+}
+#endif
+
+
+/******************************************************************
+ * Traverse a device tree stopping each PCI device in the tree.
+ * This is done depth first.  As each node is processed, a "pre"
+ * function is called, the children are processed recursively, and
+ * then a "post" function is called.
+ *
+ * The "pre" and "post" funcs return a value.  If non-zero
+ * is returned from the "pre" func, the traversal stops and this
+ * value is returned.  The return value from "post" is not used.
+ * This return value is useful when using traverse as
+ * a method of finding a device.
+ *
+ * NOTE: we do not run the funcs for devices that do not appear to
+ * be PCI except for the start node which we assume (this is good
+ * because the start node is often a phb which may be missing PCI
+ * properties).
+ * We use the class-code as an indicator. If we run into
+ * one of these nodes we also assume its siblings are non-pci for
+ * performance.
+ *
+ ******************************************************************/
+void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data)
+{
+	struct device_node *dn, *nextdn;
+	void *ret;
+
+	if (pre && (ret = pre(start, data)) != NULL)
+		return ret;
+	for (dn = start->child; dn; dn = nextdn) {
+		nextdn = NULL;
+		if (get_property(dn, "class-code", 0)) {
+			if (pre && (ret = pre(dn, data)) != NULL)
+				return ret;
+			if (dn->child) {
+				/* Depth first...do children */
+				nextdn = dn->child;
+			} else if (dn->sibling) {
+				/* ok, try next sibling instead. */
+				nextdn = dn->sibling;
+			} else {
+				/* no more children or siblings...call "post" */
+				if (post)
+					post(dn, data);
+			}
+		}
+		if (!nextdn) {
+			/* Walk up to next valid sibling. */
+			do {
+				dn = dn->parent;
+				if (dn == start)
+					return NULL;
+			} while (dn->sibling == NULL);
+			nextdn = dn->sibling;
+		}
+	}
+	return NULL;
+}
+
+/* Same as traverse_pci_devices except this does it for all phbs.
+ */
+void *traverse_all_pci_devices(traverse_func pre)
+{
+	struct pci_controller* phb;
+	void *ret;
+	for (phb=hose_head;phb;phb=phb->next)
+		if ((ret = traverse_pci_devices((struct device_node *)phb->arch_data, pre, NULL, phb)) != NULL)
+			return ret;
+	return NULL;
+}
+
+
+/* Traversal func that looks for a <busno,devfcn> value.
+ * If found, the device_node is returned (thus terminating the traversal).
+ */
+static void *
+is_devfn_node(struct device_node *dn, void *data)
+{
+	int busno = ((unsigned long)data >> 8) & 0xff;
+	int devfn = ((unsigned long)data) & 0xff;
+	return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
+}
+
+/* Same as is_devfn_node except ignore the "fn" part of the "devfn".
+ */
+static void *
+is_devfn_sub_node(struct device_node *dn, void *data)
+{
+	int busno = ((unsigned long)data >> 8) & 0xff;
+	int devfn = ((unsigned long)data) & 0xf8;
+	return (devfn == (dn->devfn & 0xf8) && busno == dn->busno) ? dn : NULL;
+}
+
+/* Given an existing EADs (pci bridge) device node create a fake one
+ * that will simulate function zero.  Make it a sibling of other_eads.
+ */
+static struct device_node *
+create_eads_node(struct device_node *other_eads)
+{
+	struct device_node *eads = (struct device_node *)kmalloc(sizeof(struct device_node), GFP_KERNEL);
+
+	if (!eads) return NULL;	/* huh? */
+	*eads = *other_eads;
+	eads->devfn &= ~7;	/* make it function zero */
+	eads->tce_table = NULL;
+	/* NOTE: share properties.  We could copy but for now this should suffice.
+	 * The full_name is also incorrect...but seems harmless.
+	 */
+	eads->child = NULL;
+	eads->next = NULL;
+	other_eads->allnext = eads;
+	other_eads->sibling = eads;
+	return eads;
+}
+
+/* This is the "slow" path for looking up a device_node from a
+ * pci_dev.  It will hunt for the device under it's parent's
+ * phb and then update sysdata for a future fastpath.
+ *
+ * It may also do fixups on the actual device since this happens
+ * on the first read/write.
+ *
+ * Note that it also must deal with devices that don't exist.
+ * In this case it may probe for real hardware ("just in case")
+ * and add a device_node to the device tree if necessary.
+ *
+ */
+struct device_node *fetch_dev_dn(struct pci_dev *dev)
+{
+	struct device_node *orig_dn = (struct device_node *)dev->sysdata;
+	struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */
+	struct device_node *phb_dn;
+	struct device_node *dn;
+	unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
+
+	phb_dn = (struct device_node *)(phb->arch_data);
+	dn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_node, NULL, (void *)searchval);
+	if (dn) {
+		dev->sysdata = dn;
+		/* ToDo: call some device init hook here */
+	} else {
+		/* Now it is very possible that we can't find the device because it is
+		 * not the zero'th device of a mutifunction device and we don't have
+		 * permission to read the zero'th device.  If this is the case, Linux
+		 * would ordinarily skip all the other functions.
+		 */
+		if ((searchval & 0x7) == 0) {
+			struct device_node *thisdevdn;
+			/* Ok, we are looking for fn == 0.  Let's check for other functions. */
+			thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval);
+			if (thisdevdn) {
+				/* Ah ha!  There does exist a sub function.  Now this isn't an exact
+				 * match for searchval, but in order to get Linux to believe the sub
+				 * functions exist we will need to manufacture a fake device_node
+				 * for this zero'th function.  To keept this simple for now we only
+				 * handle pci bridges and we just hand back the found node which
+				 * isn't correct, but Linux won't care.
+				 */
+				char *device_type = (char *)get_property(thisdevdn, "device_type", 0);
+				if (device_type && strcmp(device_type, "pci") == 0) {
+					return create_eads_node(thisdevdn);
+				}
+			}
+		}
+		/* ToDo: device not found...probe for it anyway with a fake dn?
+		struct device_node fake_dn;
+		memset(&fake_dn, 0, sizeof(fake_dn));
+		fake_dn.phb = phb;
+		fake_dn.busno = dev->bus->number;
+		fake_dn.devfn = dev->devfn;
+		... now do ppc_md.pcibios_read_config_dword(&fake_dn.....)
+		 ... if ok, alloc a real device_node and dn = real_dn;
+		 */
+	}
+	return dn;
+}
+
+
+/******************************************************************
+ * Actually initialize the phbs.
+ * The buswalk on this phb has not happened yet.
+ ******************************************************************/
+void __init
+pci_devs_phb_init(void)
+{
+	/* This must be done first so the device nodes have valid pci info! */
+	traverse_all_pci_devices(update_dn_pci_info);
+
+	/* Hack for regatta which does not init the bars correctly */
+	traverse_all_pci_devices(write_OF_bars);
+#if 0
+	traverse_all_pci_devices(startBIST);
+	mdelay(5000);
+	traverse_all_pci_devices(checkBIST);
+#endif
+}
+
+
+static void __init
+pci_fixup_bus_sysdata_list(struct list_head *bus_list)
+{
+	struct list_head *ln;
+	struct pci_bus *bus;
+	struct pci_controller *phb;
+	int newnum;
+
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		if (bus->self) {
+			bus->sysdata = bus->self->sysdata;
+			/* Also fixup the bus number on large bus systems to
+			 * include the PHB# in the next byte
+			 */
+			phb = PCI_GET_DN(bus)->phb;
+			if (phb && phb->buid) {
+				newnum = (phb->global_number << 8) | bus->number;
+				bus->number = newnum;
+				sprintf(bus->name, "PCI Bus #%x", bus->number);
+			}
+		}
+		pci_fixup_bus_sysdata_list(&bus->children);
+	}
+}
+
+
+/******************************************************************
+ * Fixup the bus->sysdata ptrs to point to the bus' device_node.
+ * This is done late in pcibios_init().  We do this mostly for
+ * sanity, but pci_dma.c uses these at DMA time so they must be
+ * correct.
+ * To do this we recurse down the bus hierarchy.  Note that PHB's
+ * have bus->self == NULL, but fortunately bus->sysdata is already
+ * correct in this case.
+ ******************************************************************/
+void __init
+pci_fix_bus_sysdata(void)
+{
+	pci_fixup_bus_sysdata_list(&pci_root_buses);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/pmc.c linux-2.4.19-pre5/arch/ppc64/kernel/pmc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/pmc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/pmc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,167 @@
+/*
+ * pmc.c
+ * Copyright (C) 2001 Dave Engebretsen & Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Change Activity:
+ * 2001/06/05 : engebret : Created.
+ * End Change Activity 
+ */
+
+#include <asm/proc_fs.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/processor.h>
+
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/pmc.h>
+#include <asm/uaccess.h>
+#include <asm/Naca.h>
+
+extern struct Naca *naca;
+
+struct _pmc_sw pmc_sw_system = {
+	0  
+};
+
+struct _pmc_sw pmc_sw_cpu[NR_CPUS] = {
+	{0 }, 
+};
+
+/*
+ * Provide enough storage for either system level counters or
+ * one cpu's counters.
+ */
+struct _pmc_sw_text pmc_sw_text;
+struct _pmc_hw_text pmc_hw_text;
+
+char *
+ppc64_pmc_stab(int file)
+{
+	int  n;
+	unsigned long stab_faults, stab_capacity_castouts, stab_invalidations; 
+	unsigned long i;
+
+	stab_faults = stab_capacity_castouts = stab_invalidations = n = 0;
+
+	if (file == -1) {
+		for (i = 0;  i < smp_num_cpus; i++) {
+			stab_faults += pmc_sw_cpu[i].stab_faults;
+			stab_capacity_castouts += pmc_sw_cpu[i].stab_capacity_castouts;
+			stab_invalidations += pmc_sw_cpu[i].stab_invalidations;
+		}
+		n += sprintf(pmc_sw_text.buffer + n,    
+			     "Faults         0x%lx\n", stab_faults); 
+		n += sprintf(pmc_sw_text.buffer + n, 
+			     "Castouts       0x%lx\n", stab_capacity_castouts); 
+		n += sprintf(pmc_sw_text.buffer + n, 
+			     "Invalidations  0x%lx\n", stab_invalidations); 
+	} else {
+		n += sprintf(pmc_sw_text.buffer + n,
+			     "Faults         0x%lx\n", 
+			     pmc_sw_cpu[file].stab_faults);
+		
+		n += sprintf(pmc_sw_text.buffer + n,   
+			     "Castouts       0x%lx\n", 
+			     pmc_sw_cpu[file].stab_capacity_castouts);
+		
+		n += sprintf(pmc_sw_text.buffer + n,   
+			     "Invalidations  0x%lx\n", 
+			     pmc_sw_cpu[file].stab_invalidations);
+
+		for (i = 0; i < STAB_ENTRY_MAX; i++) {
+			if (pmc_sw_cpu[file].stab_entry_use[i]) {
+				n += sprintf(pmc_sw_text.buffer + n,   
+					     "Entry %02ld       0x%lx\n", i, 
+					     pmc_sw_cpu[file].stab_entry_use[i]);
+			}
+		}
+
+	}
+
+	return(pmc_sw_text.buffer); 
+}
+
+char *
+ppc64_pmc_htab(int file)
+{
+	int  n;
+	unsigned long htab_primary_overflows, htab_capacity_castouts;
+	unsigned long htab_read_to_write_faults; 
+
+	htab_primary_overflows = htab_capacity_castouts = 0;
+	htab_read_to_write_faults = n = 0;
+
+	if (file == -1) {
+		n += sprintf(pmc_sw_text.buffer + n,    
+			     "Primary Overflows  0x%lx\n", 
+			     pmc_sw_system.htab_primary_overflows); 
+		n += sprintf(pmc_sw_text.buffer + n, 
+			     "Castouts           0x%lx\n", 
+			     pmc_sw_system.htab_capacity_castouts); 
+	} else {
+		n += sprintf(pmc_sw_text.buffer + n,
+			     "Primary Overflows  N/A\n");
+
+		n += sprintf(pmc_sw_text.buffer + n,   
+			     "Castouts           N/A\n\n");
+
+	}
+	
+	return(pmc_sw_text.buffer); 
+}
+
+char *
+ppc64_pmc_hw(int file)
+{
+	int  n;
+
+	n = 0;
+	if (file == -1) {
+		n += sprintf(pmc_hw_text.buffer + n, "Not Implemented\n");
+	} else {
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "MMCR0  0x%lx\n", mfspr(MMCR0)); 
+		n += sprintf(pmc_hw_text.buffer + n, 
+			     "MMCR1  0x%lx\n", mfspr(MMCR1)); 
+#if 0
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "MMCRA  0x%lx\n", mfspr(MMCRA)); 
+#endif
+
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC1   0x%lx\n", mfspr(PMC1)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC2   0x%lx\n", mfspr(PMC2)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC3   0x%lx\n", mfspr(PMC3)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC4   0x%lx\n", mfspr(PMC4)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC5   0x%lx\n", mfspr(PMC5)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC6   0x%lx\n", mfspr(PMC6)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC7   0x%lx\n", mfspr(PMC7)); 
+		n += sprintf(pmc_hw_text.buffer + n,    
+			     "PMC8   0x%lx\n", mfspr(PMC8)); 
+	}
+
+	return(pmc_hw_text.buffer); 
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ppc-stub.c linux-2.4.19-pre5/arch/ppc64/kernel/ppc-stub.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ppc-stub.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc-stub.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,739 @@
+/* 
+ * ppc-stub.c:  KGDB support for the Linux kernel.
+ *
+ * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
+ * some stuff borrowed from Paul Mackerras' xmon
+ * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu)
+ *
+ * Modifications to run under Linux
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * This file originally came from the gdb sources, and the
+ * copyright notices have been retained below.
+ */
+
+/****************************************************************************
+
+		THIS SOFTWARE IS NOT COPYRIGHTED
+
+   HP offers the following for use in the public domain.  HP makes no
+   warranty with regard to the software or its performance and the
+   user accepts the software "AS IS" with all faults.
+
+   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:      Glenn Engel $
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:           See Below $
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
+ *							   baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/signal.h>
+#include <asm/kgdb.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+
+void breakinst(void);
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+static int initialized = 0;
+static int kgdb_active = 0;
+static int kgdb_started = 0;
+static u_int fault_jmp_buf[100];
+static int kdebug;
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Place where we save old trap entries for restoration - sparc*/
+/* struct tt_entry kgdb_savettable[256]; */
+/* typedef void (*trapfunc_t)(void); */
+
+#if 0
+/* Install an exception handler for kgdb */
+static void exceptionHandler(int tnum, unsigned int *tfunc)
+{
+	/* We are dorking with a live trap table, all irqs off */
+}
+#endif
+
+int
+kgdb_setjmp(long *buf)
+{
+	asm ("mflr 0; stw 0,0(%0);"
+	     "stw 1,4(%0); stw 2,8(%0);"
+	     "mfcr 0; stw 0,12(%0);"
+	     "stmw 13,16(%0)"
+	     : : "r" (buf));
+	/* XXX should save fp regs as well */
+	return 0;
+}
+void
+kgdb_longjmp(long *buf, int val)
+{
+	if (val == 0)
+		val = 1;
+	asm ("lmw 13,16(%0);"
+	     "lwz 0,12(%0); mtcrf 0x38,0;"
+	     "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
+	     "mtlr 0; mr 3,%1"
+	     : : "r" (buf), "r" (val));
+}
+/* Convert ch from a hex digit to an int */
+static int
+hex(unsigned char ch)
+{
+	if (ch >= 'a' && ch <= 'f')
+		return ch-'a'+10;
+	if (ch >= '0' && ch <= '9')
+		return ch-'0';
+	if (ch >= 'A' && ch <= 'F')
+		return ch-'A'+10;
+	return -1;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ */
+static unsigned char *
+mem2hex(char *mem, char *buf, int count)
+{
+	unsigned char ch;
+
+	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+		debugger_fault_handler = kgdb_fault_handler;
+		while (count-- > 0) {
+			ch = *mem++;
+			*buf++ = hexchars[ch >> 4];
+			*buf++ = hexchars[ch & 0xf];
+		}
+	} else {
+		/* error condition */
+	}
+	debugger_fault_handler = 0;
+	*buf = 0;
+	return buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written.
+*/
+static char *
+hex2mem(char *buf, char *mem, int count)
+{
+	int i;
+	unsigned char ch;
+
+	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+		debugger_fault_handler = kgdb_fault_handler;
+		for (i=0; i<count; i++) {
+			ch = hex(*buf++) << 4;
+			ch |= hex(*buf++);
+			*mem++ = ch;
+		}
+		flush_icache_range((int)mem, (int)mem+count);
+	} else {
+		/* error condition */
+	}
+	debugger_fault_handler = 0;
+	return mem;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+		debugger_fault_handler = kgdb_fault_handler;
+		while (**ptr) {
+			hexValue = hex(**ptr);
+			if (hexValue < 0)
+				break;
+
+			*intValue = (*intValue << 4) | hexValue;
+			numChars ++;
+
+			(*ptr)++;
+		}
+	} else {
+	     /* error condition */
+	}
+	debugger_fault_handler = 0;
+
+	return (numChars);
+}
+
+/* scan for the sequence $<data>#<checksum>     */
+static void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	unsigned char ch;
+
+	do {
+		/* wait around for the start character, ignore all other
+		 * characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+
+		if (count >= BUFMAX)
+			continue;
+
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum |= hex(getDebugChar() & 0x7f);
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+'); /* successful transfer */
+				/* if a sequence char is present, reply the ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i=3; i <= count; i++)
+						buffer[i-3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+}
+
+/* send the packet in buffer.  */
+static void putpacket(unsigned char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	unsigned char ch, recv;
+
+	/*  $<packet info>#<checksum>. */
+	do {
+		putDebugChar('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count])) {
+			putDebugChar(ch);
+			checksum += ch;
+			count += 1;
+		}
+
+		putDebugChar('#');
+		putDebugChar(hexchars[checksum >> 4]);
+		putDebugChar(hexchars[checksum & 0xf]);
+		recv = getDebugChar();
+	} while ((recv & 0x7f) != '+');
+}
+
+static void kgdb_flush_cache_all(void)
+{
+	flush_instruction_cache();
+}
+
+
+/* Set up exception handlers for tracing and breakpoints
+ * [could be called kgdb_init()]
+ */
+void set_debug_traps(void)
+{
+#if 0
+	unsigned char c;
+
+	save_and_cli(flags);
+
+	/* In case GDB is started before us, ack any packets (presumably
+	 * "$?#xx") sitting there.
+	 *
+	 * I've found this code causes more problems than it solves,
+	 * so that's why it's commented out.  GDB seems to work fine
+	 * now starting either before or after the kernel   -bwb
+	 */
+
+	while((c = getDebugChar()) != '$');
+	while((c = getDebugChar()) != '#');
+	c = getDebugChar(); /* eat first csum byte */
+	c = getDebugChar(); /* eat second csum byte */
+	putDebugChar('+'); /* ack it */
+#endif
+	debugger = kgdb;
+	debugger_bpt = kgdb_bpt;
+	debugger_sstep = kgdb_sstep;
+	debugger_iabr_match = kgdb_iabr_match;
+	debugger_dabr_match = kgdb_dabr_match;
+
+	initialized = 1;
+}
+
+static void kgdb_fault_handler(struct pt_regs *regs)
+{
+	kgdb_longjmp((long*)fault_jmp_buf, 1);
+}
+
+int kgdb_bpt(struct pt_regs *regs)
+{
+	handle_exception(regs);
+	return 1;
+}
+
+int kgdb_sstep(struct pt_regs *regs)
+{
+	handle_exception(regs);
+	return 1;
+}
+
+void kgdb(struct pt_regs *regs)
+{
+	handle_exception(regs);
+}
+
+int kgdb_iabr_match(struct pt_regs *regs)
+{
+	printk("kgdb doesn't support iabr, what?!?\n");
+	handle_exception(regs);
+	return 1;
+}
+
+int kgdb_dabr_match(struct pt_regs *regs)
+{
+	printk("kgdb doesn't support dabr, what?!?\n");
+	handle_exception(regs);
+	return 1;
+}
+
+/* Convert the SPARC hardware trap type code to a unix signal number. */
+/*
+ * This table contains the mapping between PowerPC hardware trap types, and
+ * signals, which are primarily what GDB understands.
+ */
+static struct hard_trap_info
+{
+	unsigned int tt;		/* Trap type code for powerpc */
+	unsigned char signo;		/* Signal that we map this trap into */
+} hard_trap_info[] = {
+	{ 0x200, SIGSEGV },			/* machine check */
+	{ 0x300, SIGSEGV },			/* address error (store) */
+	{ 0x400, SIGBUS },			/* instruction bus error */
+	{ 0x500, SIGINT },			/* interrupt */
+	{ 0x600, SIGBUS },			/* alingment */
+	{ 0x700, SIGTRAP },			/* breakpoint trap */
+	{ 0x800, SIGFPE },			/* fpu unavail */
+	{ 0x900, SIGALRM },			/* decrementer */
+	{ 0xa00, SIGILL },			/* reserved */
+	{ 0xb00, SIGILL },			/* reserved */
+	{ 0xc00, SIGCHLD },			/* syscall */
+	{ 0xd00, SIGTRAP },			/* single-step/watch */
+	{ 0xe00, SIGFPE },			/* fp assist */
+	{ 0, 0}				/* Must be last */
+};
+
+static int computeSignal(unsigned int tt)
+{
+	struct hard_trap_info *ht;
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		if (ht->tt == tt)
+			return ht->signo;
+
+	return SIGHUP;         /* default for things we don't know about */
+}
+
+#define PC_REGNUM 64
+#define SP_REGNUM 1
+
+/*
+ * This function does all command processing for interfacing to gdb.
+ */
+static void
+handle_exception (struct pt_regs *regs)
+{
+	int sigval;
+	int addr;
+	int length;
+	char *ptr;
+	unsigned long msr;
+
+	if (debugger_fault_handler) {
+		debugger_fault_handler(regs);
+		panic("kgdb longjump failed!\n");
+	}
+	if (kgdb_active) {
+		printk("interrupt while in kgdb, returning\n");
+		return;
+	}
+	kgdb_active = 1;
+	kgdb_started = 1;
+
+#ifdef KGDB_DEBUG
+	printk("kgdb: entering handle_exception; trap [0x%x]\n",
+	       (unsigned int)regs->trap);
+#endif
+
+	kgdb_interruptible(0);
+	lock_kernel();
+	msr = get_msr();
+	set_msr(msr & ~MSR_EE);	/* disable interrupts */
+
+	if (regs->nip == (unsigned long)breakinst) {
+		/* Skip over breakpoint trap insn */
+		regs->nip += 4;
+	}
+
+	/* reply to host that an exception has occurred */
+	sigval = computeSignal(regs->trap);
+	ptr = remcomOutBuffer;
+
+#if 0
+	*ptr++ = 'S';
+	*ptr++ = hexchars[sigval >> 4];
+	*ptr++ = hexchars[sigval & 0xf];
+#else
+	*ptr++ = 'T';
+	*ptr++ = hexchars[sigval >> 4];
+	*ptr++ = hexchars[sigval & 0xf];
+	*ptr++ = hexchars[PC_REGNUM >> 4];
+	*ptr++ = hexchars[PC_REGNUM & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&regs->nip, ptr, 4);
+	*ptr++ = ';';
+	*ptr++ = hexchars[SP_REGNUM >> 4];
+	*ptr++ = hexchars[SP_REGNUM & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex(((char *)&regs) + SP_REGNUM*4, ptr, 4);
+	*ptr++ = ';';
+#endif
+
+	*ptr++ = 0;
+
+	putpacket(remcomOutBuffer);
+
+	/* XXX We may want to add some features dealing with poking the
+	 * XXX page tables, ... (look at sparc-stub.c for more info)
+	 * XXX also required hacking to the gdb sources directly...
+	 */
+
+	while (1) {
+		remcomOutBuffer[0] = 0;
+
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':               /* report most recent signal */
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[sigval >> 4];
+			remcomOutBuffer[2] = hexchars[sigval & 0xf];
+			remcomOutBuffer[3] = 0;
+			break;
+#if 0
+		case 'q': /* this screws up gdb for some reason...*/
+		{
+			extern long _start, sdata, __bss_start;
+
+			ptr = &remcomInBuffer[1];
+			if (strncmp(ptr, "Offsets", 7) != 0)
+				break;
+
+			ptr = remcomOutBuffer;
+			sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
+				&_start, &sdata, &__bss_start);
+			break;
+		}
+#endif
+		case 'd':
+			/* toggle debug flag */
+			kdebug ^= 1;
+			break;
+
+		case 'g':	/* return the value of the CPU registers.
+				 * some of them are non-PowerPC names :(
+				 * they are stored in gdb like:
+				 * struct {
+				 *     u32 gpr[32];
+				 *     f64 fpr[32];
+				 *     u32 pc, ps, cnd, lr; (ps=msr)
+				 *     u32 cnt, xer, mq;
+				 * }
+				 */
+		{
+			int i;
+			ptr = remcomOutBuffer;
+			/* General Purpose Regs */
+			ptr = mem2hex((char *)regs, ptr, 32 * 4);
+			/* Floating Point Regs - FIXME */
+			/*ptr = mem2hex((char *), ptr, 32 * 8);*/
+			for(i=0; i<(32*8*2); i++) { /* 2chars/byte */
+				ptr[i] = '0';
+			}
+			ptr += 32*8*2;
+			/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
+			ptr = mem2hex((char *)&regs->nip, ptr, 4);
+			ptr = mem2hex((char *)&regs->msr, ptr, 4);
+			ptr = mem2hex((char *)&regs->ccr, ptr, 4);
+			ptr = mem2hex((char *)&regs->link, ptr, 4);
+			ptr = mem2hex((char *)&regs->ctr, ptr, 4);
+			ptr = mem2hex((char *)&regs->xer, ptr, 4);
+		}
+			break;
+
+		case 'G':   /* set the value of the CPU registers */
+		{
+			ptr = &remcomInBuffer[1];
+
+			/*
+			 * If the stack pointer has moved, you should pray.
+			 * (cause only god can help you).
+			 */
+
+			/* General Purpose Regs */
+			hex2mem(ptr, (char *)regs, 32 * 4);
+
+			/* Floating Point Regs - FIXME?? */
+			/*ptr = hex2mem(ptr, ??, 32 * 8);*/
+			ptr += 32*8*2;
+
+			/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
+			ptr = hex2mem(ptr, (char *)&regs->nip, 4);
+			ptr = hex2mem(ptr, (char *)&regs->msr, 4);
+			ptr = hex2mem(ptr, (char *)&regs->ccr, 4);
+			ptr = hex2mem(ptr, (char *)&regs->link, 4);
+			ptr = hex2mem(ptr, (char *)&regs->ctr, 4);
+			ptr = hex2mem(ptr, (char *)&regs->xer, 4);
+
+			strcpy(remcomOutBuffer,"OK");
+		}
+			break;
+		case 'H':
+			/* don't do anything, yet, just acknowledge */
+			hexToInt(&ptr, &addr);
+			strcpy(remcomOutBuffer,"OK");
+			break;
+
+		case 'm':	/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+				/* Try to read %x,%x.  */
+
+			ptr = &remcomInBuffer[1];
+
+			if (hexToInt(&ptr, &addr)
+			    && *ptr++ == ','
+			    && hexToInt(&ptr, &length))	{
+				if (mem2hex((char *)addr, remcomOutBuffer,length))
+					break;
+				strcpy (remcomOutBuffer, "E03");
+			} else {
+				strcpy(remcomOutBuffer,"E01");
+			}
+			break;
+
+		case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+			/* Try to read '%x,%x:'.  */
+
+			ptr = &remcomInBuffer[1];
+
+			if (hexToInt(&ptr, &addr)
+			    && *ptr++ == ','
+			    && hexToInt(&ptr, &length)
+			    && *ptr++ == ':') {
+				if (hex2mem(ptr, (char *)addr, length)) {
+					strcpy(remcomOutBuffer, "OK");
+				} else {
+					strcpy(remcomOutBuffer, "E03");
+				}
+				flush_icache_range(addr, addr+length);
+			} else {
+				strcpy(remcomOutBuffer, "E02");
+			}
+			break;
+
+
+		case 'k':    /* kill the program, actually just continue */
+		case 'c':    /* cAA..AA  Continue; address AA..AA optional */
+			/* try to read optional parameter, pc unchanged if no parm */
+
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr)) {
+				regs->nip = addr;
+			}
+
+/* Need to flush the instruction cache here, as we may have deposited a
+ * breakpoint, and the icache probably has no way of knowing that a data ref to
+ * some location may have changed something that is in the instruction cache.
+ */
+			kgdb_flush_cache_all();
+			set_msr(msr);
+			kgdb_interruptible(1);
+			unlock_kernel();
+			kgdb_active = 0;
+			return;
+
+		case 's':
+			kgdb_flush_cache_all();
+			regs->msr |= MSR_SE;
+#if 0
+			set_msr(msr | MSR_SE);
+#endif
+			unlock_kernel();
+			kgdb_active = 0;
+			return;
+
+		case 'r':		/* Reset (if user process..exit ???)*/
+			panic("kgdb reset.");
+			break;
+		}			/* switch */
+		if (remcomOutBuffer[0] && kdebug) {
+			printk("remcomInBuffer: %s\n", remcomInBuffer);
+			printk("remcomOutBuffer: %s\n", remcomOutBuffer);
+		}
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	} /* while(1) */
+}
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+
+void
+breakpoint(void)
+{
+	if (!initialized) {
+		printk("breakpoint() called b4 kgdb init\n");
+		return;
+	}
+
+	asm("	.globl breakinst
+	     breakinst: .long 0x7d821008
+            ");
+}
+
+/* Output string in GDB O-packet format if GDB has connected. If nothing
+   output, returns 0 (caller must then handle output). */
+int
+kgdb_output_string (const char* s, unsigned int count)
+{
+	char buffer[512];
+
+        if (!kgdb_started)
+            return 0;
+
+	count = (count <= (sizeof(buffer) / 2 - 2)) 
+		? count : (sizeof(buffer) / 2 - 2);
+
+	buffer[0] = 'O';
+	mem2hex (s, &buffer[1], count);
+	putpacket(buffer);
+
+        return 1;
+ }
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ppc_asm.h linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/ppc_asm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,117 @@
+/*
+ * arch/ppc/kernel/ppc_asm.h
+ *
+ * Definitions used by various bits of low-level assembly code on PowerPC.
+ *
+ * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)	std	n,GPR0+8*(n)(base)
+#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)	ld	n,GPR0+8*(n)(base)
+#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)	stfd	n,THREAD_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)	lfd	n,THREAD_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
+#define CHECKANYINT(ra,rb)			\
+	mfspr	rb,SPRG3;		/* Get Paca address */\
+	ld	ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\
+	cmpldi	0,ra,0;
+
+/* Macros to adjust thread priority for Iseries hardware multithreading */
+#define HMT_LOW		or 1,1,1
+#define HMT_MEDIUM	or 2,2,2
+#define HMT_HIGH	or 3,3,3
+
+/* Insert the high 32 bits of the MSR into what will be the new
+   MSR (via SRR1 and rfid)  This preserves the MSR.SF and MSR.ISF
+   bits. */
+
+#define FIX_SRR1(ra, rb)	\
+	mr	rb,ra;		\
+	mfmsr	ra;		\
+	rldimi	ra,rb,0,32
+
+#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
+
+/* 
+ * LOADADDR( rn, name )
+ *   loads the address of 'name' into 'rn'
+ *
+ * LOADBASE( rn, name )
+ *   loads the address (less the low 16 bits) of 'name' into 'rn'
+ *   suitable for base+disp addressing
+ */
+#define LOADADDR(rn,name) \
+	lis	rn,name##@highest;	\
+	ori	rn,rn,name##@higher;	\
+	rldicr	rn,rn,32,31;		\
+	oris	rn,rn,name##@h;		\
+	ori	rn,rn,name##@l
+
+#define LOADBASE(rn,name) \
+	lis	rn,name@highest;	\
+	ori	rn,rn,name@higher;	\
+	rldicr	rn,rn,32,31;		\
+	oris	rn,rn,name@ha
+
+
+#define SET_REG_TO_CONST(reg, value)	         	\
+	lis     reg,(((value)>>48)&0xFFFF);             \
+	ori     reg,reg,(((value)>>32)&0xFFFF);         \
+	rldicr  reg,reg,32,31;                          \
+	oris    reg,reg,(((value)>>16)&0xFFFF);         \
+	ori     reg,reg,((value)&0xFFFF);
+
+#define SET_REG_TO_LABEL(reg, label)	         	\
+	lis     reg,(label)@highest;                    \
+	ori     reg,reg,(label)@higher;                 \
+	rldicr  reg,reg,32,31;                          \
+	oris    reg,reg,(label)@h;                      \
+	ori     reg,reg,(label)@l;
+
+
+/* PPPBBB - DRENG  If KERNELBASE is always 0xC0...,
+ * Then we can easily do this with one asm insn. -Peter
+ */
+#define tophys(rd,rs)                           \
+        lis     rd,((KERNELBASE>>48)&0xFFFF);   \
+        rldicr  rd,rd,32,31;                    \
+        sub     rd,rs,rd
+
+#define tovirt(rd,rs)                           \
+        lis     rd,((KERNELBASE>>48)&0xFFFF);   \
+        rldicr  rd,rd,32,31;                    \
+        add     rd,rs,rd
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ppc_asm.tmpl linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.tmpl
--- linux-2.4.19-pre4/arch/ppc64/kernel/ppc_asm.tmpl	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_asm.tmpl	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,115 @@
+/* Condition Register Bit Fields */
+
+#define	cr0	0
+#define	cr1	1
+#define	cr2	2
+#define	cr3	3
+#define	cr4	4
+#define	cr5	5
+#define	cr6	6
+#define	cr7	7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define	r0	0
+#define	r1	1
+#define	r2	2
+#define	r3	3
+#define	r4	4
+#define	r5	5
+#define	r6	6
+#define	r7	7
+#define	r8	8
+#define	r9	9
+#define	r10	10
+#define	r11	11
+#define	r12	12
+#define	r13	13
+#define	r14	14
+#define	r15	15
+#define	r16	16
+#define	r17	17
+#define	r18	18
+#define	r19	19
+#define	r20	20
+#define	r21	21
+#define	r22	22
+#define	r23	23
+#define	r24	24
+#define	r25	25
+#define	r26	26
+#define	r27	27
+#define	r28	28
+#define	r29	29
+#define	r30	30
+#define	r31	31
+
+
+/* Floating Point Registers (FPRs) */
+
+#define	fr0	0
+#define	fr1	1
+#define	fr2	2
+#define	fr3	3
+#define	fr4	4
+#define	fr5	5
+#define	fr6	6
+#define	fr7	7
+#define	fr8	8
+#define	fr9	9
+#define	fr10	10
+#define	fr11	11
+#define	fr12	12
+#define	fr13	13
+#define	fr14	14
+#define	fr15	15
+#define	fr16	16
+#define	fr17	17
+#define	fr18	18
+#define	fr19	19
+#define	fr20	20
+#define	fr21	21
+#define	fr22	22
+#define	fr23	23
+#define	fr24	24
+#define	fr25	25
+#define	fr26	26
+#define	fr27	27
+#define	fr28	28
+#define	fr29	29
+#define	fr30	30
+#define	fr31	31
+
+#define	vr0	0
+#define	vr1	1
+#define	vr2	2
+#define	vr3	3
+#define	vr4	4
+#define	vr5	5
+#define	vr6	6
+#define	vr7	7
+#define	vr8	8
+#define	vr9	9
+#define	vr10	10
+#define	vr11	11
+#define	vr12	12
+#define	vr13	13
+#define	vr14	14
+#define	vr15	15
+#define	vr16	16
+#define	vr17	17
+#define	vr18	18
+#define	vr19	19
+#define	vr20	20
+#define	vr21	21
+#define	vr22	22
+#define	vr23	23
+#define	vr24	24
+#define	vr25	25
+#define	vr26	26
+#define	vr27	27
+#define	vr28	28
+#define	vr29	29
+#define	vr30	30
+#define	vr31	31
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ppc_defs.head linux-2.4.19-pre5/arch/ppc64/kernel/ppc_defs.head
--- linux-2.4.19-pre4/arch/ppc64/kernel/ppc_defs.head	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_defs.head	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,3 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.19-pre5/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ppc_ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ppc_ksyms.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,306 @@
+/* 
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/vt_kern.h>
+#include <linux/nvram.h>
+#include <linux/spinlock.h>
+#include <linux/console.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <asm/page.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/ide.h>
+#include <asm/ide.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/hw_irq.h>
+#include <asm/abs_addr.h>
+#ifdef CONFIG_SMP
+#include <asm/smplock.h>
+#endif /* CONFIG_SMP */
+#ifdef CONFIG_PPC_ISERIES
+#include <asm/iSeries/iSeries_pci.h>
+#include <asm/iSeries/iSeries_proc.h>
+#include <asm/iSeries/mf.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvLpConfig.h>
+#endif
+
+/* Tell string.h we don't want memcpy etc. as cpp defines */
+#define EXPORT_SYMTAB_STROPS
+
+extern void syscall_trace(void);
+extern void do_IRQ(struct pt_regs *regs, int isfake);
+extern void SystemResetException(struct pt_regs *regs);
+extern void MachineCheckException(struct pt_regs *regs);
+extern void AlignmentException(struct pt_regs *regs);
+extern void ProgramCheckException(struct pt_regs *regs);
+extern void SingleStepException(struct pt_regs *regs);
+extern int sys_sigreturn(struct pt_regs *regs);
+extern int do_signal(sigset_t *, struct pt_regs *);
+extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
+extern int unregister_ioctl32_conversion(unsigned int cmd);
+
+long long __ashrdi3(long long, int);
+long long __ashldi3(long long, int);
+long long __lshrdi3(long long, int);
+int abs(int);
+extern unsigned long ret_to_user_hook;
+
+extern struct pci_dev * iSeries_veth_dev;
+extern struct pci_dev * iSeries_vio_dev;
+
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(do_IRQ);
+EXPORT_SYMBOL(SystemResetException);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(smp_num_cpus);
+#endif /* CONFIG_SMP */
+
+EXPORT_SYMBOL(register_ioctl32_conversion);
+EXPORT_SYMBOL(unregister_ioctl32_conversion);
+
+EXPORT_SYMBOL(isa_io_base);
+EXPORT_SYMBOL(isa_mem_base);
+EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_dram_offset);
+
+EXPORT_SYMBOL(find_next_zero_bit);
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(naca);
+EXPORT_SYMBOL(__down);
+
+/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__strnlen_user);
+
+/*
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+EXPORT_SYMBOL(outsl);*/
+
+#ifdef CONFIG_MSCHUNKS
+EXPORT_SYMBOL(msChunks);
+#endif
+EXPORT_SYMBOL(reloc_offset);
+
+#ifdef CONFIG_PPC_ISERIES
+EXPORT_SYMBOL(iSeries_proc_callback);
+EXPORT_SYMBOL(HvCall0);
+EXPORT_SYMBOL(HvCall1);
+EXPORT_SYMBOL(HvCall2);
+EXPORT_SYMBOL(HvCall3);
+EXPORT_SYMBOL(HvCall4);
+EXPORT_SYMBOL(HvCall5);
+EXPORT_SYMBOL(HvCall6);
+EXPORT_SYMBOL(HvCall7);
+EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
+EXPORT_SYMBOL(HvLpEvent_registerHandler);
+EXPORT_SYMBOL(mf_allocateLpEvents);
+EXPORT_SYMBOL(mf_deallocateLpEvents);
+EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
+#endif
+
+EXPORT_SYMBOL(_insb);
+EXPORT_SYMBOL(_outsb);
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(_insw_ns);
+EXPORT_SYMBOL(_outsw_ns);
+EXPORT_SYMBOL(_insl_ns);
+EXPORT_SYMBOL(_outsl_ns);
+EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
+#ifdef CONFIG_PPC_ISERIES
+EXPORT_SYMBOL(iSeries_Write_Long);
+EXPORT_SYMBOL(iSeries_GetLocationData);
+EXPORT_SYMBOL(iSeries_Read_Long);
+EXPORT_SYMBOL(iSeries_Device_ToggleReset);
+EXPORT_SYMBOL(iSeries_Write_Word);
+EXPORT_SYMBOL(iSeries_memcpy_fromio);
+EXPORT_SYMBOL(iSeries_Read_Word);
+EXPORT_SYMBOL(iSeries_Read_Byte);
+EXPORT_SYMBOL(iSeries_Write_Byte);
+#endif /* CONFIG_PPC_ISERIES */
+#ifdef CONFIG_PPC_EEH
+EXPORT_SYMBOL(eeh_check_failure);
+EXPORT_SYMBOL(eeh_total_mmio_ffs);
+EXPORT_SYMBOL(eeh_total_mmio_reads);
+#endif /* CONFIG_PPC_EEH */
+#endif /* CONFIG_PCI */
+
+EXPORT_SYMBOL(iSeries_veth_dev);
+EXPORT_SYMBOL(iSeries_vio_dev);
+
+EXPORT_SYMBOL(start_thread);
+EXPORT_SYMBOL(kernel_thread);
+
+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(flush_icache_user_range);
+EXPORT_SYMBOL(flush_icache_page);
+EXPORT_SYMBOL(flush_dcache_page);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+#ifdef CONFIG_PPC_ISERIES
+EXPORT_SYMBOL(__no_use_restore_flags);
+EXPORT_SYMBOL(__no_use_save_flags);
+EXPORT_SYMBOL(__no_use_sti);
+EXPORT_SYMBOL(__no_use_cli);
+#endif
+#endif
+
+#ifndef CONFIG_MACH_SPECIFIC
+EXPORT_SYMBOL(_machine);
+#endif
+EXPORT_SYMBOL(ppc_md);
+
+EXPORT_SYMBOL(find_devices);
+EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_compatible_devices);
+EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(machine_is_compatible);
+EXPORT_SYMBOL(find_all_nodes);
+EXPORT_SYMBOL(get_property);
+
+#ifndef CONFIG_PPC_ISERIES
+EXPORT_SYMBOL(kd_mksound);
+EXPORT_SYMBOL_NOVERS(sys_ctrler); /* tibit */
+#endif
+#ifdef CONFIG_NVRAM
+EXPORT_SYMBOL(nvram_read_byte);
+EXPORT_SYMBOL(nvram_write_byte);
+#endif /* CONFIG_NVRAM */
+
+EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(memscan);
+EXPORT_SYMBOL_NOVERS(memcmp);
+
+EXPORT_SYMBOL(abs);
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(timer_interrupt);
+EXPORT_SYMBOL(irq_desc);
+void ppc_irq_dispatch_handler(struct pt_regs *, int);
+EXPORT_SYMBOL(ppc_irq_dispatch_handler);
+EXPORT_SYMBOL(get_wchan);
+EXPORT_SYMBOL(console_drivers);
+#ifdef CONFIG_XMON
+EXPORT_SYMBOL(xmon);
+#endif
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
+extern void (*debugger)(struct pt_regs *regs);
+extern int (*debugger_bpt)(struct pt_regs *regs);
+extern int (*debugger_sstep)(struct pt_regs *regs);
+extern int (*debugger_iabr_match)(struct pt_regs *regs);
+extern int (*debugger_dabr_match)(struct pt_regs *regs);
+extern void (*debugger_fault_handler)(struct pt_regs *regs);
+
+EXPORT_SYMBOL(debugger);
+EXPORT_SYMBOL(debugger_bpt);
+EXPORT_SYMBOL(debugger_sstep);
+EXPORT_SYMBOL(debugger_iabr_match);
+EXPORT_SYMBOL(debugger_dabr_match);
+EXPORT_SYMBOL(debugger_fault_handler);
+#endif
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
+
+EXPORT_SYMBOL(ret_to_user_hook);
+
+EXPORT_SYMBOL(tb_ticks_per_usec);
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/proc_pcifr.c linux-2.4.19-pre5/arch/ppc64/kernel/proc_pcifr.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/proc_pcifr.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/proc_pcifr.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,251 @@
+/************************************************************************/
+/* File pcifr_proc.c created by Allan Trautman on Thu Aug  2 2001.      */
+/************************************************************************/
+/* Supports the ../proc/ppc64/pcifr for the pci flight recorder.        */
+/* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+#include <stdarg.h>
+#include <linux/kernel.h>
+
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <asm/time.h>
+
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
+#include <linux/netdevice.h>
+
+#include <asm/flight_recorder.h>
+#include <asm/iSeries/iSeries_pci.h>
+#include "pci.h"
+
+void pci_Fr_TestCode(void);
+
+static spinlock_t proc_pcifr_lock;
+struct flightRecorder* PciFr = NULL;
+
+extern long Pci_Interrupt_Count;
+extern long Pci_Event_Count;
+extern long Pci_Io_Read_Count;
+extern long Pci_Io_Write_Count;
+extern long Pci_Cfg_Read_Count;
+extern long Pci_Cfg_Write_Count;
+extern long Pci_Error_Count;
+
+/************************************************************************/
+/* Forward declares.                                                    */
+/************************************************************************/
+static struct proc_dir_entry *pciFr_proc_root = NULL;
+int proc_pciFr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+int proc_pciFr_write_proc(struct file *file, const char *buffer, unsigned long count, void *data);
+
+static struct proc_dir_entry *pciDev_proc_root = NULL;
+int proc_pciDev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+int proc_pciDev_write_proc(struct file *file, const char *buffer, unsigned long count, void *data);
+
+/************************************************************************/
+/* Create entry ../proc/ppc64/pcifr                                     */
+/************************************************************************/
+void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root)
+{
+	if (proc_ppc64_root == NULL) return;
+
+	/* Read = User,Group,Other, Write User */
+	printk("PCI: Creating ../proc/ppc64/pcifr \n");
+	spin_lock(&proc_pcifr_lock);
+	pciFr_proc_root = create_proc_entry("pcifr", S_IFREG | S_IRUGO | S_IWUSR, proc_ppc64_root);
+	spin_unlock(&proc_pcifr_lock);
+
+	if (pciFr_proc_root == NULL) return;
+
+	pciFr_proc_root->nlink = 1;
+	pciFr_proc_root->data = (void *)0;
+	pciFr_proc_root->read_proc  = proc_pciFr_read_proc;
+	pciFr_proc_root->write_proc = proc_pciFr_write_proc;
+
+	PciFr = alloc_Flight_Recorder(NULL,"PciFr", 4096);
+
+	printk("PCI: Creating ../proc/ppc64/pci \n");
+	spin_lock(&proc_pcifr_lock);
+	pciDev_proc_root = create_proc_entry("pci", S_IFREG | S_IRUGO | S_IWUSR, proc_ppc64_root);
+	spin_unlock(&proc_pcifr_lock);
+
+	if (pciDev_proc_root == NULL) return;
+
+	pciDev_proc_root->nlink = 1;
+	pciDev_proc_root->data = (void *)0;
+	pciDev_proc_root->read_proc  = proc_pciDev_read_proc;
+	pciDev_proc_root->write_proc = proc_pciDev_write_proc;
+}
+
+static	char* PciFrBuffer = NULL;
+static  int   PciFrBufLen = 0;
+static  char* PciFrBufPtr = NULL;
+static  int   PciFileSize = 0;
+
+/*******************************************************************************/
+/* Read function for ../proc/ppc64/pcifr.                                      */
+/*  -> Function grabs a copy of the pcifr(could change) and writes the data to */
+/*     the caller.  Note, it may not all fit in the buffer.  The function      */
+/*     handles the repeated calls until all the data has been read.            */
+/* Tip:                                                                        */
+/* ./fs/proc/generic.c::proc_file_read is the caller of this routine.          */
+/*******************************************************************************/
+int proc_pciFr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	/* First call will have offset 0, get snapshot the pcifr          */
+	if( off == 0) {
+		spin_lock(&proc_pcifr_lock);
+		PciFrBuffer = (char*)kmalloc(PciFr->Size, GFP_KERNEL);
+		PciFrBufLen = fr_Dump(PciFr,PciFrBuffer, PciFr->Size);
+		PciFrBufPtr = PciFrBuffer;
+		PciFileSize = 0;
+	}
+	/* For the persistant folks, set eof and return zero length.      */
+	else if( PciFrBuffer == NULL) {
+		*eof = 1;
+		return 0;
+	}
+	/* - If there is more data than will fit, move what will fit.     */
+	/* - The rest will get moved on the next call.                    */
+	int MoveSize = PciFrBufLen;
+	if( MoveSize > count) MoveSize = count;
+
+	/* Move the data info the FileSystem buffer.                      */
+	memcpy(page+off,PciFrBufPtr,MoveSize);
+	PciFrBufPtr += MoveSize;
+	PciFileSize += MoveSize;
+	PciFrBufLen -= MoveSize;
+
+	/* If all the data has been moved, free the buffer and set EOF.   */
+	if( PciFrBufLen == 0) {
+		kfree(PciFrBuffer);
+		PciFrBuffer = NULL;
+		spin_unlock(&proc_pcifr_lock);
+		*eof = 1;
+	}
+	return PciFileSize;
+}
+/*******************************************************************************/
+/* Gets called when client writes to ../proc/ppc64/pcifr                       */
+/*******************************************************************************/
+int proc_pciFr_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	return count;
+}
+static  spinlock_t ProcBufferLock;
+static	char* ProcBuffer   = NULL;
+static  int   ProcBufSize  = 0;
+static  char* ProcBufPtr   = NULL;
+static  int   ProcFileSize = 0;
+
+/*******************************************************************************/
+/* Build Device Buffer for /proc/ppc64/pci                                     */
+/*******************************************************************************/
+static int build_PciDev_Buffer(int BufferSize) 
+{
+	ProcBuffer  = (char*)kmalloc(BufferSize, GFP_KERNEL);
+	ProcBufPtr  = ProcBuffer;
+
+	int BufLen  = 0;
+
+	BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Reads. %8ld  ",Pci_Io_Read_Count);
+	BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Writes %8ld\n",Pci_Io_Write_Count);
+
+	BufLen += sprintf(ProcBuffer+BufLen,"Pci Cfg Reads. %8ld  ",Pci_Cfg_Read_Count);
+	BufLen += sprintf(ProcBuffer+BufLen,"Pci Cfg Writes %8ld\n",Pci_Cfg_Write_Count);
+
+	BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Errors %8ld\n",Pci_Error_Count);
+	BufLen += sprintf(ProcBuffer+BufLen,"\n");
+
+	/***************************************************************************/
+	/* List the devices                                                        */
+	/***************************************************************************/
+	struct pci_dev*    PciDev;		    /* Device pointer              */
+	struct net_device* dev;		            /* net_device pointer          */
+	int    DeviceCount  = 0;
+	pci_for_each_dev(PciDev) {
+		if ( BufLen > BufferSize-128) {    /* Room for another line?       */
+			BufLen +=sprintf(ProcBuffer+BufLen,"Buffer Full\n");
+			break;
+		}
+		if( PCI_SLOT(PciDev->devfn) != 0) {
+			++DeviceCount;
+			BufLen += sprintf(ProcBuffer+BufLen,"%3d. ",DeviceCount);
+			if ( PciDev->sysdata != NULL ) {
+				BufLen += format_device_location(PciDev,ProcBuffer+BufLen,128);
+			}
+			else {
+				BufLen += sprintf(ProcBuffer+BufLen,"No Device Node!\n");
+			}
+			BufLen += sprintf(ProcBuffer+BufLen,"\n");
+
+			/* look for the net devices out */
+			for (dev = dev_base; dev != NULL; dev = dev->next) 	{
+				if (dev->base_addr == PciDev->resource[0].start ) {
+					BufLen += sprintf(ProcBuffer+BufLen, "     - Net device: %s\n", dev->name);
+					break;
+				} /* if */
+			} /* for */
+		} /* if(PCI_SLOT(PciDev->devfn) != 0)  */
+	}
+	return BufLen;
+}
+/*******************************************************************************/
+/* Get called when client reads the ../proc/ppc64/pcifr.                       */
+/*******************************************************************************/
+int proc_pciDev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	/* First call will have offset 0                                  */
+	if( off == 0) {
+		spin_lock(&ProcBufferLock);
+		ProcBufSize  = build_PciDev_Buffer(4096);
+		ProcFileSize = 0;
+	}
+	/* For the persistant folks, set eof and return zero length.      */
+	else if( ProcBuffer == NULL) {
+		*eof = 1;
+		return 0;
+	}
+	/* How much data can be moved                                     */
+	int MoveSize = ProcBufSize;
+	if( MoveSize > count) MoveSize = count;
+
+	/* Move the data info the FileSystem buffer.                      */
+	memcpy(page+off,ProcBufPtr,MoveSize);
+	ProcBufPtr   += MoveSize;
+	ProcBufSize  -= MoveSize;
+	ProcFileSize += MoveSize;
+
+	/* If all the data has been moved, free the buffer and set EOF.   */
+	if( ProcBufSize == 0) {
+		kfree(ProcBuffer );
+		ProcBuffer  = NULL;
+		spin_unlock(&ProcBufferLock);
+		*eof = 1;
+	}
+	return ProcFileSize;
+}
+/*******************************************************************************/
+/* Gets called when client writes to ../proc/ppc64/pcifr                       */
+/*******************************************************************************/
+int proc_pciDev_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	return count;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/proc_pmc.c linux-2.4.19-pre5/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/proc_pmc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/proc_pmc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,797 @@
+/*
+ * proc_pmc.c
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/* Change Activity:
+ * 2001       : mikec    : Created
+ * 2001/06/05 : engebret : Software event count support.
+ * 2001/08/03 : trautman : Added PCI Flight Recorder
+ * End Change Activity 
+ */
+
+#include <asm/proc_fs.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/HvCallXm.h>
+#include <asm/iSeries/IoHriMainStore.h>
+#include <asm/processor.h>
+#include <asm/time.h>
+#include <asm/iSeries/LparData.h>
+
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/pmc.h>
+#include <asm/uaccess.h>
+#include <asm/Naca.h>
+
+/* pci Flight Recorder AHT */
+extern void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root);
+
+static int proc_pmc_control_mode = 0;
+
+static struct proc_dir_entry *proc_ppc64_root = NULL;
+static struct proc_dir_entry *proc_ppc64_pmc_root = NULL;
+static struct proc_dir_entry *proc_ppc64_pmc_system_root = NULL;
+static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, };
+
+static spinlock_t proc_ppc64_lock;
+
+extern struct Naca *naca;
+
+int proc_ppc64_pmc_find_file(void *data);
+int proc_ppc64_pmc_read(char *page, char **start, off_t off,
+			int count, int *eof, char *buffer);
+int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off,
+			     int count, int *eof, void *data);
+int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
+			     int count, int *eof, void *data);
+int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
+			   int count, int *eof, void *data);
+
+static struct proc_dir_entry *pmc_proc_root = NULL;
+
+int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data);
+int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data);
+
+int proc_get_titanTod( char *page, char **start, off_t off, int count, int *eof, void *data);
+
+int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data);
+
+int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc1(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc2(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc3(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc4(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc5(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc6(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc7(  struct file *file, const char *buffer, unsigned long count, void *data);
+int proc_pmc_set_pmc8(  struct file *file, const char *buffer, unsigned long count, void *data);
+
+
+void proc_ppc64_init(void)
+{
+	unsigned long i;
+	struct proc_dir_entry *ent = NULL;
+	char buf[256];
+
+	printk("proc_ppc64: Creating /proc/ppc64/pmc\n");
+
+	/*
+	 * Create the root, system, and cpu directories as follows:
+	 *   /proc/ppc64/pmc/system 
+	 *   /proc/ppc64/pmc/cpu0 
+	 */
+	spin_lock(&proc_ppc64_lock);
+	proc_ppc64_root = proc_mkdir("ppc64", 0);
+	if (!proc_ppc64_root) return;
+	spin_unlock(&proc_ppc64_lock);
+
+	/* Create the /proc/ppc64/pcifr for the Pci Flight Recorder.	 */
+	proc_pciFr_init(proc_ppc64_root);
+
+#ifdef CONFIG_PPC_EEH
+	eeh_init_proc(proc_ppc64_root);
+#endif
+
+	proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root);
+
+	proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
+	for (i = 0; i < naca->processorCount; i++) {
+		sprintf(buf, "cpu%ld", i); 
+		proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root);
+	}
+
+
+	/* Create directories for the software counters. */
+	for (i = 0; i < naca->processorCount; i++) {
+		ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
+					proc_ppc64_pmc_cpu_root[i]);
+		if (ent) {
+			ent->nlink = 1;
+			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
+			ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
+			ent->write_proc = (void *)proc_ppc64_pmc_stab_read;
+		}
+
+		ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
+					proc_ppc64_pmc_cpu_root[i]);
+		if (ent) {
+			ent->nlink = 1;
+			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
+			ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
+			ent->write_proc = (void *)proc_ppc64_pmc_htab_read;
+		}
+	}
+
+	ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
+				proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->data = (void *)proc_ppc64_pmc_system_root;
+		ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
+		ent->write_proc = (void *)proc_ppc64_pmc_stab_read;
+	}
+
+	ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
+				proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->data = (void *)proc_ppc64_pmc_system_root;
+		ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
+		ent->write_proc = (void *)proc_ppc64_pmc_htab_read;
+	}
+
+	/* Create directories for the hardware counters. */
+	for (i = 0; i < naca->processorCount; i++) {
+		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
+					proc_ppc64_pmc_cpu_root[i]);
+		if (ent) {
+			ent->nlink = 1;
+			ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
+			ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
+			ent->write_proc = (void *)proc_ppc64_pmc_hw_read;
+		}
+	}
+
+	ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
+				proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->data = (void *)proc_ppc64_pmc_system_root;
+		ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
+		ent->write_proc = (void *)proc_ppc64_pmc_hw_read;
+	}
+}
+
+/*
+ * Find the requested 'file' given a proc token.
+ *
+ * Inputs: void * data: proc token
+ * Output: int        : (0, ..., +N) = CPU number.
+ *                      -1           = System.
+ */
+int proc_ppc64_pmc_find_file(void *data)
+{
+	int i;
+
+	if ((unsigned long)data == 
+	   (unsigned long) proc_ppc64_pmc_system_root) {
+		return(-1); 
+	} else {
+		for (i = 0; i < naca->processorCount; i++) {
+			if ((unsigned long)data ==
+			   (unsigned long)proc_ppc64_pmc_cpu_root[i]) {
+				return(i); 
+			}
+		}
+	}
+
+	/* On error, just default to a type of system. */
+	printk("proc_ppc64_pmc_find_file: failed to find file token.\n"); 
+	return(-1); 
+}
+
+int 
+proc_ppc64_pmc_read(char *page, char **start, off_t off, 
+		    int count, int *eof, char *buffer)
+{
+	int buffer_size, n;
+
+	if (count < 0) return 0;
+
+	if (buffer == NULL) {
+		*eof = 1;
+		return 0;
+	}
+
+	/* Check for read beyond EOF */
+	buffer_size = n = strlen(buffer);
+	if (off >= buffer_size) {
+		*eof = 1;
+		return 0;
+	}
+	if (n > (buffer_size - off)) n = buffer_size - off;
+
+	/* Never return more than was requested */
+	if (n > count) {
+		n = count;
+	} else {
+		*eof = 1;
+	}
+
+	memcpy(page, buffer + off, n);
+
+	*start = page;
+
+	return n;
+}
+
+int 
+proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, 
+			 int count, int *eof, void *data)
+{
+	int n, file;
+	char *buffer = NULL;
+
+	if (count < 0) return 0;
+	spin_lock(&proc_ppc64_lock);
+
+	/* Figure out which file is being request. */
+	file = proc_ppc64_pmc_find_file(data);
+
+	/* Update the counters and the text buffer representation. */
+	buffer = ppc64_pmc_stab(file);
+
+	/* Put the data into the requestor's buffer. */
+	n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); 
+
+	spin_unlock(&proc_ppc64_lock);
+	return n;
+}
+
+int 
+proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, 
+			 int count, int *eof, void *data)
+{
+	int n, file;
+	char *buffer = NULL;
+
+	if (count < 0) return 0;
+	spin_lock(&proc_ppc64_lock);
+
+	/* Figure out which file is being request. */
+	file = proc_ppc64_pmc_find_file(data);
+
+	/* Update the counters and the text buffer representation. */
+	buffer = ppc64_pmc_htab(file);
+
+	/* Put the data into the requestor's buffer. */
+	n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
+
+	spin_unlock(&proc_ppc64_lock);
+	return n;
+}
+
+int 
+proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
+			     int count, int *eof, void *data)
+{
+	int n, file;
+	char *buffer = NULL;
+
+	if (count < 0) return 0;
+	spin_lock(&proc_ppc64_lock);
+
+	/* Figure out which file is being request. */
+	file = proc_ppc64_pmc_find_file(data);
+
+	/* Update the counters and the text buffer representation. */
+	buffer = ppc64_pmc_hw(file);
+
+	/* Put the data into the requestor's buffer. */
+	n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
+
+	spin_unlock(&proc_ppc64_lock);
+	return n;
+}
+
+/* 
+ * DRENG the remainder of these functions still need work ...
+ */
+void pmc_proc_init(struct proc_dir_entry *iSeries_proc)
+{
+    struct proc_dir_entry *ent = NULL;
+
+    ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc);
+    if (!ent) return;
+    ent->nlink = 1;
+    ent->data = (void *)0;
+    ent->read_proc = proc_get_lpevents;
+    ent->write_proc = proc_reset_lpevents;
+
+    ent = create_proc_entry("titanTod", S_IFREG|S_IRUGO, iSeries_proc);
+    if (!ent) return;
+    ent->nlink = 1;
+    ent->data = (void *)0;
+    ent->read_proc = proc_get_titanTod;
+    ent->write_proc = NULL;
+
+    pmc_proc_root = proc_mkdir("pmc", iSeries_proc);
+    if (!pmc_proc_root) return;
+
+    ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
+    if (!ent) return;
+    ent->nlink = 1;
+    ent->data = (void *)0;
+    ent->read_proc = proc_pmc_get_control;
+    ent->write_proc = proc_pmc_set_control;
+
+}
+
+static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len)
+{
+	if ( len <= off+count)
+		*eof = 1;
+	*start = page+off;
+	len -= off;
+	if ( len > count )
+		len = count;
+	if ( len < 0 )
+		len = 0;
+	return len;
+}
+
+static char * lpEventTypes[9] = {
+	"Hypervisor\t\t",
+	"Machine Facilities\t",
+	"Session Manager\t",
+	"SPD I/O\t\t",
+	"Virtual Bus\t\t",
+	"PCI I/O\t\t",
+	"RIO I/O\t\t",
+	"Virtual Lan\t\t",
+	"Virtual I/O\t\t"
+	};
+	
+
+int proc_get_lpevents
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	unsigned i;
+	int len = 0;
+
+	len += sprintf( page+len, "LpEventQueue 0\n" );
+	len += sprintf( page+len, "  events processed:\t%lu\n",
+			(unsigned long)xItLpQueue.xLpIntCount );
+	for (i=0; i<9; ++i) {
+		len += sprintf( page+len, "    %s %10lu\n",
+			lpEventTypes[i],
+			(unsigned long)xItLpQueue.xLpIntCountByType[i] );
+	}
+	len += sprintf( page+len, "\n  events processed by processor:\n" );
+	for (i=0; i<naca->processorCount; ++i) {
+		len += sprintf( page+len, "    CPU%02d  %10u\n",
+			i, xPaca[i].lpEvent_count );
+	}
+
+	return pmc_calc_metrics( page, start, off, count, eof, len );
+
+}
+
+int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	return count;
+}
+
+static unsigned long startTitan = 0;
+static unsigned long startTb = 0;
+
+
+int proc_get_titanTod
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+	unsigned long tb0, titan_tod;
+
+	tb0 = get_tb();
+	titan_tod = HvCallXm_loadTod();
+
+	len += sprintf( page+len, "Titan\n" );
+	len += sprintf( page+len, "  time base =          %016lx\n", tb0 );
+	len += sprintf( page+len, "  titan tod =          %016lx\n", titan_tod );
+	len += sprintf( page+len, "  xProcFreq =          %016x\n", xIoHriProcessorVpd[0].xProcFreq );
+	len += sprintf( page+len, "  xTimeBaseFreq =      %016x\n", xIoHriProcessorVpd[0].xTimeBaseFreq );
+	len += sprintf( page+len, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy );
+	len += sprintf( page+len, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec );
+
+	if ( !startTitan ) {
+		startTitan = titan_tod;
+		startTb = tb0;
+	}
+	else {
+		unsigned long titan_usec = (titan_tod - startTitan) >> 12;
+		unsigned long tb_ticks = (tb0 - startTb);
+		unsigned long titan_jiffies = titan_usec / (1000000/HZ);
+		unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
+		unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec;
+		unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
+		unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
+		unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
+		unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec;
+		unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec;
+		
+		len += sprintf( page+len, "  titan elapsed = %lu uSec\n", titan_usec);
+		len += sprintf( page+len, "  tb elapsed    = %lu ticks\n", tb_ticks);
+		len += sprintf( page+len, "  titan jiffies = %lu.%04lu \n", titan_jiffies, titan_jiff_rem_usec );				
+		len += sprintf( page+len, "  tb jiffies    = %lu.%04lu\n", tb_jiffies, tb_jiff_rem_usec );
+		len += sprintf( page+len, "  new tb_ticks_per_jiffy = %lu\n", new_tb_ticks_per_jiffy );	
+
+	}
+	
+	return pmc_calc_metrics( page, start, off, count, eof, len );
+}
+	
+int proc_pmc_get_control
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+
+	if ( proc_pmc_control_mode == PMC_CONTROL_CPI ) {
+		unsigned long mach_cycles   = mfspr( PMC5 );
+		unsigned long inst_complete = mfspr( PMC4 );
+		unsigned long inst_dispatch = mfspr( PMC3 );
+		unsigned long thread_active_run = mfspr( PMC1 );
+		unsigned long thread_active  = mfspr( PMC2 );
+		unsigned long cpi = 0;
+		unsigned long cpithou = 0;
+		unsigned long remain;
+	
+		if ( inst_complete ) {
+			cpi = thread_active_run / inst_complete;
+			remain = thread_active_run % inst_complete;
+			if ( inst_complete > 1000000 ) 
+				cpithou = remain / ( inst_complete / 1000 );
+			else 
+				cpithou = ( remain * 1000 ) / inst_complete;
+		}
+		len += sprintf( page+len, "PMC CPI Mode\nRaw Counts\n" );
+		len += sprintf( page+len, "machine cycles           : %12lu\n", mach_cycles );
+		len += sprintf( page+len, "thread active cycles     : %12lu\n\n", thread_active );
+
+		len += sprintf( page+len, "instructions completed   : %12lu\n", inst_complete );
+		len += sprintf( page+len, "instructions dispatched  : %12lu\n", inst_dispatch );
+		len += sprintf( page+len, "thread active run cycles : %12lu\n", thread_active_run );
+
+		len += sprintf( page+len, "thread active run cycles/instructions completed\n" );
+		len += sprintf( page+len, "CPI = %lu.%03lu\n", cpi, cpithou );
+		
+	}
+	else if ( proc_pmc_control_mode == PMC_CONTROL_TLB ) {
+		len += sprintf( page+len, "PMC TLB Mode\n" );
+		len += sprintf( page+len, "I-miss count             : %12lu\n", mfspr( PMC1 ) );
+		len += sprintf( page+len, "I-miss latency           : %12lu\n", mfspr( PMC2 ) );
+		len += sprintf( page+len, "D-miss count             : %12lu\n", mfspr( PMC3 ) );
+		len += sprintf( page+len, "D-miss latency           : %12lu\n", mfspr( PMC4 ) );
+		len += sprintf( page+len, "IERAT miss count         : %12lu\n", mfspr( PMC5 ) );
+		len += sprintf( page+len, "D-reference count        : %12lu\n", mfspr( PMC6 ) );
+		len += sprintf( page+len, "miss PTEs searched       : %12lu\n", mfspr( PMC7 ) );
+		len += sprintf( page+len, "miss >8 PTEs searched    : %12lu\n", mfspr( PMC8 ) );
+	}
+	/* IMPLEMENT ME */
+	return pmc_calc_metrics( page, start, off, count, eof, len );
+}
+
+unsigned long proc_pmc_conv_int( const char *buf, unsigned count )
+{
+	const char * p;
+	char b0, b1;
+	unsigned v, multiplier, mult, i;
+	unsigned long val;
+	multiplier = 10;
+	p = buf;
+	if ( count >= 3 ) {
+		b0 = buf[0];
+		b1 = buf[1];
+		if ( ( b0 == '0' ) &&
+		     ( ( b1 == 'x' ) || ( b1 == 'X' ) ) ) {
+			p = buf + 2;
+			count -= 2;
+			multiplier = 16;
+		}
+			
+	}
+	val = 0;
+	for ( i=0; i<count; ++i ) {
+		b0 = *p++;
+		v = 0;
+		mult = multiplier;
+		if ( ( b0 >= '0' ) && ( b0 <= '9' ) ) 
+			v = b0 - '0';
+		else if ( multiplier == 16 ) {
+			if ( ( b0 >= 'a' ) && ( b0 <= 'f' ) )
+				v = b0 - 'a' + 10;
+			else if ( ( b0 >= 'A' ) && ( b0 <= 'F' ) )
+				v = b0 - 'A' + 10;
+			else 
+				mult = 1;
+		}
+		else
+			mult = 1;
+		val *= mult;
+		val += v;
+	}
+
+	return val;
+
+}
+
+static inline void proc_pmc_stop(void)
+{
+	/* Freeze all counters, leave everything else alone */
+	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
+}
+
+static inline void proc_pmc_start(void)
+{
+	/* Unfreeze all counters, leave everything else alone */
+	mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 );
+
+}
+
+static inline void proc_pmc_reset(void)
+{
+	/* Clear all the PMCs to zeros 
+	 * Assume a "stop" has already frozen the counters
+	 * Clear all the PMCs
+	 */
+	mtspr( PMC1, 0 );
+	mtspr( PMC2, 0 );
+	mtspr( PMC3, 0 );
+	mtspr( PMC4, 0 );
+	mtspr( PMC5, 0 );
+	mtspr( PMC6, 0 );
+	mtspr( PMC7, 0 );
+	mtspr( PMC8, 0 );
+
+}
+
+static inline void proc_pmc_cpi(void)
+{
+	/* Configure the PMC registers to count cycles and instructions */
+	/* so we can compute cpi */
+	/*
+	 * MMCRA[30]    = 1     Don't count in wait state (CTRL[31]=0)
+	 * MMCR0[6]     = 1     Freeze counters when any overflow
+	 * MMCR0[19:25] = 0x01  PMC1 counts Thread Active Run Cycles
+	 * MMCR0[26:31] = 0x05	PMC2 counts Thread Active Cycles
+	 * MMCR1[0:4]   = 0x07	PMC3 counts Instructions Dispatched
+	 * MMCR1[5:9]   = 0x03	PMC4 counts Instructions Completed
+	 * MMCR1[10:14] = 0x06	PMC5 counts Machine Cycles
+	 *
+	 */
+
+	proc_pmc_control_mode = PMC_CONTROL_CPI;
+	
+	/* Indicate to hypervisor that we are using the PMCs */
+	((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
+
+	/* Freeze all counters */
+	mtspr( MMCR0, 0x80000000 );
+	mtspr( MMCR1, 0x00000000 );
+	
+	/* Clear all the PMCs */
+	mtspr( PMC1, 0 );
+	mtspr( PMC2, 0 );
+	mtspr( PMC3, 0 );
+	mtspr( PMC4, 0 );
+	mtspr( PMC5, 0 );
+	mtspr( PMC6, 0 );
+	mtspr( PMC7, 0 );
+	mtspr( PMC8, 0 );
+
+	/* Freeze counters in Wait State (CTRL[31]=0) */
+	mtspr( MMCRA, 0x00000002 );
+
+	/* PMC3<-0x07, PMC4<-0x03, PMC5<-0x06 */
+	mtspr( MMCR1, 0x38cc0000 );
+
+	mb();
+	
+	/* PMC1<-0x01, PMC2<-0x05
+	 * Start all counters
+	 */
+	mtspr( MMCR0, 0x02000045 );
+	
+}
+
+static inline void proc_pmc_tlb(void)
+{
+	/* Configure the PMC registers to count tlb misses  */
+	/*
+	 * MMCR0[6]     = 1     Freeze counters when any overflow
+	 * MMCR0[19:25] = 0x55  Group count
+	 *   PMC1 counts  I misses
+	 *   PMC2 counts  I miss duration (latency)
+	 *   PMC3 counts  D misses
+	 *   PMC4 counts  D miss duration (latency)
+	 *   PMC5 counts  IERAT misses
+	 *   PMC6 counts  D references (including PMC7)
+	 *   PMC7 counts  miss PTEs searched
+	 *   PMC8 counts  miss >8 PTEs searched
+	 *   
+	 */
+
+	proc_pmc_control_mode = PMC_CONTROL_TLB;
+	
+	/* Indicate to hypervisor that we are using the PMCs */
+	((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
+
+	/* Freeze all counters */
+	mtspr( MMCR0, 0x80000000 );
+	mtspr( MMCR1, 0x00000000 );
+	
+	/* Clear all the PMCs */
+	mtspr( PMC1, 0 );
+	mtspr( PMC2, 0 );
+	mtspr( PMC3, 0 );
+	mtspr( PMC4, 0 );
+	mtspr( PMC5, 0 );
+	mtspr( PMC6, 0 );
+	mtspr( PMC7, 0 );
+	mtspr( PMC8, 0 );
+
+	mtspr( MMCRA, 0x00000000 );
+
+	mb();
+	
+	/* PMC1<-0x55
+	 * Start all counters
+	 */
+	mtspr( MMCR0, 0x02001540 );
+	
+}
+
+int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	if      ( ! strncmp( buffer, "stop", 4 ) )
+		proc_pmc_stop();
+	else if ( ! strncmp( buffer, "start", 5 ) )
+		proc_pmc_start();
+	else if ( ! strncmp( buffer, "reset", 5 ) )
+		proc_pmc_reset();
+	else if ( ! strncmp( buffer, "cpi", 3 ) )
+		proc_pmc_cpi();
+	else if ( ! strncmp( buffer, "tlb", 3 ) )
+		proc_pmc_tlb();
+	
+	/* IMPLEMENT ME */
+	return count;
+}
+
+int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	v = v & ~0x04000000;	/* Don't allow interrupts for now */
+	if ( v & ~0x80000000 ) 	/* Inform hypervisor we are using PMCs */
+		((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 1;
+	else
+		((struct Paca *)mfspr(SPRG3))->xLpPacaPtr->xPMCRegsInUse = 0;
+	mtspr( MMCR0, v );
+	
+	return count;	
+}
+
+int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( MMCR1, v );
+
+	return count;
+}
+
+int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	v = v & ~0x00008000;	/* Don't allow interrupts for now */
+	mtspr( MMCRA, v );
+
+	return count;
+}
+
+
+int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC1, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC2, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC3, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC4, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC5, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC6, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC7, v );
+
+	return count;
+}
+
+int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data )
+{
+	unsigned long v;
+	v = proc_pmc_conv_int( buffer, count );
+	mtspr( PMC8, v );
+
+	return count;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/process.c linux-2.4.19-pre5/arch/ppc64/kernel/process.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/process.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/process.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,621 @@
+/*
+ * 
+ *
+ *  linux/arch/ppc/kernel/process.c
+ *
+ *  Derived from "arch/i386/kernel/process.c"
+ *    Copyright (C) 1995  Linus Torvalds
+ *
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
+ *  Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/elf.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/prom.h>
+#include <asm/ppcdebug.h>
+#include <asm/machdep.h>
+#include <asm/iSeries/HvCallHpt.h>
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
+extern unsigned long _get_SP(void);
+
+struct task_struct *last_task_used_math = NULL;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+struct mm_struct ioremap_mm = { pgd             : ioremap_dir  
+                               ,page_table_lock : SPIN_LOCK_UNLOCKED };
+
+/* this is 16-byte aligned because it has a stack in it */
+union task_union __attribute((aligned(16))) init_task_union = {
+	INIT_TASK(init_task_union.task)
+};
+
+#ifdef CONFIG_SMP
+struct current_set_struct current_set[NR_CPUS] = {{&init_task, 0}, };
+#endif
+
+char *sysmap = NULL; 
+unsigned long sysmap_size = 0;
+
+extern char __toc_start;
+
+#undef SHOW_TASK_SWITCHES
+#undef CHECK_STACK
+
+#if defined(CHECK_STACK)
+unsigned long
+kernel_stack_top(struct task_struct *tsk)
+{
+	return ((unsigned long)tsk) + sizeof(union task_union);
+}
+
+unsigned long
+task_top(struct task_struct *tsk)
+{
+	return ((unsigned long)tsk) + sizeof(struct task_struct);
+}
+
+/* check to make sure the kernel stack is healthy */
+int check_stack(struct task_struct *tsk)
+{
+	unsigned long stack_top = kernel_stack_top(tsk);
+	unsigned long tsk_top = task_top(tsk);
+	int ret = 0;
+
+#if 0	
+	/* check thread magic */
+	if ( tsk->thread.magic != THREAD_MAGIC )
+	{
+		ret |= 1;
+		printk("thread.magic bad: %08x\n", tsk->thread.magic);
+	}
+#endif
+
+	if ( !tsk )
+		printk("check_stack(): tsk bad tsk %p\n",tsk);
+	
+	/* check if stored ksp is bad */
+	if ( (tsk->thread.ksp > stack_top) || (tsk->thread.ksp < tsk_top) )
+	{
+		printk("stack out of bounds: %s/%d\n"
+		       " tsk_top %08lx ksp %08lx stack_top %08lx\n",
+		       tsk->comm,tsk->pid,
+		       tsk_top, tsk->thread.ksp, stack_top);
+		ret |= 2;
+	}
+	
+	/* check if stack ptr RIGHT NOW is bad */
+	if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
+	{
+		printk("current stack ptr out of bounds: %s/%d\n"
+		       " tsk_top %08lx sp %08lx stack_top %08lx\n",
+		       current->comm,current->pid,
+		       tsk_top, _get_SP(), stack_top);
+		ret |= 4;
+	}
+
+#if 0	
+	/* check amount of free stack */
+	for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ )
+	{
+		if ( !i )
+			printk("check_stack(): i = %p\n", i);
+		if ( *i != 0 )
+		{
+			/* only notify if it's less than 900 bytes */
+			if ( (i - (unsigned long *)task_top(tsk))  < 900 )
+				printk("%d bytes free on stack\n",
+				       i - task_top(tsk));
+			break;
+		}
+	}
+#endif
+
+	if (ret)
+	{
+		panic("bad kernel stack");
+	}
+	return(ret);
+}
+#endif /* defined(CHECK_STACK) */
+
+void
+enable_kernel_fp(void)
+{
+#ifdef CONFIG_SMP
+	if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
+		giveup_fpu(current);
+	else
+		giveup_fpu(NULL);	/* just enables FP for kernel */
+#else
+	giveup_fpu(last_task_used_math);
+#endif /* CONFIG_SMP */
+}
+
+int
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+{
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+	memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
+	return 1;
+}
+
+void
+_switch_to(struct task_struct *prev, struct task_struct *new,
+	  struct task_struct **last)
+{
+	struct thread_struct *new_thread, *old_thread;
+	unsigned long s;
+	
+	__save_flags(s);
+	__cli();
+#if CHECK_STACK
+	check_stack(prev);
+	check_stack(new);
+#endif
+
+#ifdef SHOW_TASK_SWITCHES
+	printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
+	       prev->comm,prev->pid,
+	       new->comm,new->pid,new->thread.regs->nip,new->processor,
+	       new->fs->root,prev->fs->root);
+#endif
+#ifdef CONFIG_SMP
+	/* avoid complexity of lazy save/restore of fpu
+	 * by just saving it every time we switch out if
+	 * this task used the fpu during the last quantum.
+	 * 
+	 * If it tries to use the fpu again, it'll trap and
+	 * reload its fp regs.  So we don't have to do a restore
+	 * every switch, just a save.
+	 *  -- Cort
+	 */
+	if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) )
+		giveup_fpu(prev);
+
+	/* prev->last_processor = prev->processor; */
+	current_set[smp_processor_id()].task = new;
+#endif /* CONFIG_SMP */
+	new_thread = &new->thread;
+	old_thread = &current->thread;
+	*last = _switch(old_thread, new_thread);
+	__restore_flags(s);
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	int i;
+
+	printk("NIP: %016lX XER: %016lX LR: %016lX REGS: %p TRAP: %04lx    %s\n",
+	       regs->nip, regs->xer, regs->link, regs,regs->trap, print_tainted());
+	printk("MSR: %016lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+	printk("TASK = %p[%d] '%s' ",
+	       current, current->pid, current->comm);
+	printk("Last syscall: %ld ", current->thread.last_syscall);
+	printk("\nlast math %p ", last_task_used_math);
+	
+#ifdef CONFIG_SMP
+	/* printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); */
+#endif /* CONFIG_SMP */
+	
+	printk("\n");
+	for (i = 0;  i < 32;  i++)
+	{
+		long r;
+		if ((i % 4) == 0)
+		{
+			printk("GPR%02d: ", i);
+		}
+
+		if ( __get_user(r, &(regs->gpr[i])) )
+		    return;
+
+		printk("%016lX ", r);
+		if ((i % 4) == 3)
+		{
+			printk("\n");
+		}
+	}
+}
+
+void exit_thread(void)
+{
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+}
+
+void flush_thread(void)
+{
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+}
+
+void
+release_thread(struct task_struct *t)
+{
+}
+
+/*
+ * Copy a thread..
+ */
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+	    unsigned long unused,
+	    struct task_struct * p, struct pt_regs * regs)
+{
+	unsigned long msr;
+	struct pt_regs * childregs, *kregs;
+	extern void ret_from_fork(void);
+
+	/* Copy registers */
+	childregs = ((struct pt_regs *)
+		     ((unsigned long)p + sizeof(union task_union)
+		      - STACK_FRAME_OVERHEAD)) - 2;
+	*childregs = *regs;
+	childregs->gpr[3] = 0;  /* Result from fork() */
+	p->thread.regs = childregs;
+	p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+	p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
+	kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD);
+	/* The PPC64 compiler makes use of a TOC to contain function 
+	 * pointers.  The function (ret_from_except) is actually a pointer
+	 * to the TOC entry.  The first entry is a pointer to the actual
+	 * function.
+ 	 */
+	kregs->nip = *((unsigned long *)ret_from_fork);
+	asm volatile("mfmsr %0" : "=r" (msr):);
+	kregs->msr = msr;
+	kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
+	kregs->gpr[2] = (((unsigned long)&__toc_start) + 0x8000);
+	
+	if (usp >= (unsigned long) regs) {
+		/* Stack is in kernel space - must adjust */
+		childregs->gpr[1] = (unsigned long)(childregs + 1);
+		*((unsigned long *) childregs->gpr[1]) = 0;
+		childregs->gpr[13] = (unsigned long) p;
+	} else {
+		/* Provided stack is in user space */
+		childregs->gpr[1] = usp;
+	}
+	p->thread.last_syscall = -1;
+	  
+	/*
+	 * copy fpu info - assume lazy fpu switch now always
+	 *  -- Cort
+	 */
+	if (regs->msr & MSR_FP) {
+		giveup_fpu(current);
+		childregs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	}
+	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
+	p->thread.fpscr = current->thread.fpscr;
+
+	return 0;
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp)
+{
+	unsigned long entry, toc, load_addr = regs->gpr[2];
+
+	/* fdptr is a relocated pointer to the function descriptor for
+         * the elf _start routine.  The first entry in the function
+         * descriptor is the entry address of _start and the second
+         * entry is the TOC value we need to use.
+         */
+	set_fs(USER_DS);
+	__get_user(entry, (unsigned long *)fdptr);
+	__get_user(toc, (unsigned long *)fdptr+1);
+
+	/* Check whether the e_entry function descriptor entries
+	 * need to be relocated before we can use them.
+	 */
+	if ( load_addr != 0 ) {
+		entry += load_addr;
+		toc   += load_addr;
+	}
+
+	regs->nip = entry;
+	regs->gpr[1] = sp;
+	regs->gpr[2] = toc;
+	regs->msr = MSR_USER64;
+	if (last_task_used_math == current)
+		last_task_used_math = 0;
+	current->thread.fpscr = 0;
+}
+
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+			 struct pt_regs *regs)
+{
+	unsigned long clone_flags = p1;
+	int res;
+
+	PPCDBG(PPCDBG_SYS64, "sys_clone - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	res = do_fork(clone_flags, regs->gpr[1], regs, 0);
+#ifdef CONFIG_SMP
+	/* When we clone the idle task we keep the same pid but
+	 * the return value of 0 for both causes problems.
+	 * -- Cort
+	 */
+	if ((current->pid == 0) && (current == &init_task))
+		res = 1;
+#endif /* CONFIG_SMP */
+
+	PPCDBG(PPCDBG_SYS64, "sys_clone - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return res;
+}
+
+asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+			struct pt_regs *regs)
+{
+	int res;
+	
+	PPCDBG(PPCDBG_SYS64, "sys_fork - entered - pid=%ld comm=%s \n", current->pid, current->comm);
+
+	res = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
+
+#ifdef CONFIG_SMP
+	/* When we clone the idle task we keep the same pid but
+	 * the return value of 0 for both causes problems.
+	 * -- Cort
+	 */
+	if ((current->pid == 0) && (current == &init_task))
+		res = 1;
+#endif /* CONFIG_SMP */
+	
+	PPCDBG(PPCDBG_SYS64, "sys_fork - exited - pid=%ld comm=%s \n", current->pid, current->comm);
+
+	return res;
+}
+
+asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+			 struct pt_regs *regs)
+{
+  	PPCDBG(PPCDBG_SYS64, "sys_vfork - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
+}
+
+asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+			  unsigned long a3, unsigned long a4, unsigned long a5,
+			  struct pt_regs *regs)
+{
+	int error;
+	char * filename;
+
+	PPCDBG(PPCDBG_SYS64, "sys_execve - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	filename = getname((char *) a0);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	PPCDBG(PPCDBG_SYS64, "sys_execve - before do_execve : filename = %s\n", filename);
+
+	error = do_execve(filename, (char **) a1, (char **) a2, regs);
+
+	if (error == 0)
+		current->ptrace &= ~PT_DTRACE;
+	putname(filename);
+
+  out:
+	PPCDBG(PPCDBG_SYS64, "sys_execve - exited - pid=%ld current=%lx comm=%s error = %lx\n", current->pid, current, current->comm, error);
+
+	return error;
+}
+
+struct task_struct * alloc_task_struct(void)
+{
+	struct task_struct * new_task_ptr;
+    
+	new_task_ptr = ((struct task_struct *) 
+			__get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)));
+    
+	return new_task_ptr;
+}
+
+void free_task_struct(struct task_struct * task_ptr)
+{
+	free_pages((unsigned long)(task_ptr), get_order(THREAD_SIZE));
+}
+
+void initialize_paca_hardware_interrupt_stack(void)
+{
+	extern struct Naca *naca;
+
+	int i;
+	unsigned long stack;
+	unsigned long end_of_stack =0;
+
+	for (i=1; i < naca->processorCount; i++) {
+		/* Carve out storage for the hardware interrupt stack */
+		stack = __get_free_pages(GFP_KERNEL, get_order(8*PAGE_SIZE));
+
+		if ( !stack ) {     
+			printk("ERROR, cannot find space for hardware stack.\n");
+			panic(" no hardware stack ");
+		}
+
+
+		/* Store the stack value in the PACA for the processor */
+		xPaca[i].xHrdIntStack = stack + (8*PAGE_SIZE) - STACK_FRAME_OVERHEAD;
+		xPaca[i].xHrdIntCount = 0;
+
+	}
+
+	/*
+	 * __get_free_pages() might give us a page > KERNBASE+256M which
+	 * is mapped with large ptes so we can't set up the guard page.
+	 */
+	if (__is_processor(PV_POWER4))
+		return;
+
+	for (i=0; i < naca->processorCount; i++) {
+		/* set page at the top of stack to be protected - prevent overflow */
+		end_of_stack = xPaca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD);
+		ppc_md.hpte_updateboltedpp(PP_RXRX,end_of_stack);
+	}
+}
+
+extern char _stext[], _etext[];
+
+char * ppc_find_proc_name( unsigned * p, char * buf, unsigned buflen )
+{
+	unsigned long tb_flags;
+	unsigned short name_len;
+	unsigned long tb_start, code_start, code_ptr, code_offset;
+	unsigned code_len;
+	strcpy( buf, "Unknown" );
+	code_ptr = (unsigned long)p;
+	code_offset = 0;
+	if ( ( (unsigned long)p >= (unsigned long)_stext ) && ( (unsigned long)p <= (unsigned long)_etext ) ) {
+		while ( (unsigned long)p <= (unsigned long)_etext ) {
+			if ( *p == 0 ) {
+				tb_start = (unsigned long)p;
+				++p;	/* Point to traceback flags */
+				tb_flags = *((unsigned long *)p);
+				p += 2;	/* Skip over traceback flags */
+				if ( tb_flags & TB_NAME_PRESENT ) {
+					if ( tb_flags & TB_PARMINFO )
+						++p;	/* skip over parminfo data */
+					if ( tb_flags & TB_HAS_TBOFF ) {
+						code_len = *p;	/* get code length */
+						code_start = tb_start - code_len;
+						code_offset = code_ptr - code_start + 1;
+						if ( code_offset > 0x100000 )
+							break;
+						++p;		/* skip over code size */
+					}
+					name_len = *((unsigned short *)p);
+					if ( name_len > (buflen-20) )
+						name_len = buflen-20;
+					memcpy( buf, ((char *)p)+2, name_len );
+					buf[name_len] = 0;
+					if ( code_offset )
+						sprintf( buf+name_len, "+0x%lx", code_offset-1 ); 
+				}
+				break;
+			}
+			++p;
+		}
+	}
+	return buf;
+}
+
+void
+print_backtrace(unsigned long *sp)
+{
+	int cnt = 0;
+	unsigned long i;
+	char name_buf[256];
+
+	printk("Call backtrace: \n");
+	while (sp) {
+		if (__get_user( i, &sp[2] ))
+			break;
+		printk("%016lX ", i);
+		printk("%s\n", ppc_find_proc_name( (unsigned *)i, name_buf, 256 ));
+		if (cnt > 32) break;
+		if (__get_user(sp, (unsigned long **)sp))
+			break;
+	}
+	printk("\n");
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched    (*(unsigned long *)scheduling_functions_start_here)
+#define last_sched     (*(unsigned long *)scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long ip, sp;
+	unsigned long stack_page = (unsigned long)p;
+	int count = 0;
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+	sp = p->thread.ksp;
+	do {
+		sp = *(unsigned long *)sp;
+		if (sp < (stack_page + (2 * PAGE_SIZE)) ||
+		    sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE)))
+			return 0;
+		if (count > 0) {
+			ip = *(unsigned long *)(sp + 16);
+			if (ip < first_sched || ip >= last_sched)
+				return (ip & 0xFFFFFFFF);
+		}
+	} while (count++ < 16);
+	return 0;
+}
+
+void show_trace_task(struct task_struct *p)
+{
+	unsigned long ip, sp;
+	unsigned long stack_page = (unsigned long)p;
+	int count = 0;
+
+	if (!p)
+		return;
+
+	printk("Call Trace: ");
+	sp = p->thread.ksp;
+	do {
+		sp = *(unsigned long *)sp;
+		if (sp < (stack_page + (2 * PAGE_SIZE)) ||
+		    sp >= (stack_page + (THREAD_SIZE * PAGE_SIZE)))
+			break;
+		if (count > 0) {
+			ip = *(unsigned long *)(sp + 16);
+			printk("[%016lx] ", ip);
+		}
+	} while (count++ < 16);
+	printk("\n");
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/prom.c linux-2.4.19-pre5/arch/ppc64/kernel/prom.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/prom.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/prom.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,2351 @@
+/*
+ * 
+ *
+ * Procedures for interfacing to Open Firmware.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.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.
+ */
+
+#if 0
+#define DEBUG_YABOOT
+#endif
+
+#if 0
+#define DEBUG_PROM
+#endif
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/blk.h>
+
+#ifdef DEBUG_YABOOT
+#define call_yaboot(FUNC,...) \
+	do { \
+		if (FUNC) {					\
+			struct prom_t *_prom = PTRRELOC(&prom);	\
+			unsigned long prom_entry = _prom->entry;\
+			_prom->entry = (unsigned long)(FUNC);	\
+			enter_prom(__VA_ARGS__); 		\
+			_prom->entry = prom_entry;		\
+		}						\
+	} while (0)
+#else
+#define call_yaboot(FUNC,...) do { ; } while (0)
+#endif
+
+#include <asm/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/lmb.h>
+#include <asm/abs_addr.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/Naca.h>
+#include <asm/pci.h>
+#include "open_pic.h"
+#include <asm/bootinfo.h>
+#include <asm/ppcdebug.h>
+
+#ifdef CONFIG_FB
+#include <asm/linux_logo.h>
+#endif
+
+extern char _end[];
+
+/*
+ * prom_init() is called very early on, before the kernel text
+ * and data have been mapped to KERNELBASE.  At this point the code
+ * is running at whatever address it has been loaded at, so
+ * references to extern and static variables must be relocated
+ * explicitly.  The procedure reloc_offset() returns the address
+ * we're currently running at minus the address we were linked at.
+ * (Note that strings count as static variables.)
+ *
+ * Because OF may have mapped I/O devices into the area starting at
+ * KERNELBASE, particularly on CHRP machines, we can't safely call
+ * OF once the kernel has been mapped to KERNELBASE.  Therefore all
+ * OF calls should be done within prom_init(), and prom_init()
+ * and all routines called within it must be careful to relocate
+ * references as necessary.
+ *
+ * Note that the bss is cleared *after* prom_init runs, so we have
+ * to make sure that any static or extern variables it accesses
+ * are put in the data segment.
+ */
+
+
+#define PROM_BUG() do { \
+        prom_print(RELOC("kernel BUG at ")); \
+        prom_print(RELOC(__FILE__)); \
+        prom_print(RELOC(":")); \
+        prom_print_hex(__LINE__); \
+        prom_print(RELOC("!\n")); \
+        __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \
+} while (0)
+
+
+
+struct pci_reg_property {
+	struct pci_address addr;
+	u32 size_hi;
+	u32 size_lo;
+};
+
+
+struct isa_reg_property {
+	u32 space;
+	u32 address;
+	u32 size;
+};
+
+struct pci_intr_map {
+	struct pci_address addr;
+	u32 dunno;
+	phandle int_ctrler;
+	u32 intr;
+};
+
+
+typedef unsigned long interpret_func(struct device_node *, unsigned long,
+				     int, int);
+#if 0
+static interpret_func interpret_pci_props;
+#endif
+static unsigned long interpret_pci_props(struct device_node *, unsigned long,
+					 int, int);
+
+static interpret_func interpret_isa_props;
+static interpret_func interpret_root_props;
+
+#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
+#define FB_MAX	8
+#endif
+
+
+struct prom_t prom = {
+	0,			/* entry */
+	0,			/* chosen */
+	0,			/* cpu */
+	0,			/* stdout */
+	0,			/* disp_node */
+	{0,0,0,{0},NULL},	/* args */
+	0,			/* version */
+	32,			/* encode_phys_size */
+	0			/* bi_rec pointer */
+#ifdef DEBUG_YABOOT
+	,NULL			/* yaboot */
+#endif
+};
+
+
+char *prom_display_paths[FB_MAX] __initdata = { 0, };
+unsigned int prom_num_displays = 0;
+char *of_stdout_device = 0;
+
+extern struct rtas_t rtas;
+extern unsigned long klimit;
+extern unsigned long embedded_sysmap_end;
+extern struct Naca *naca;
+extern struct lmb lmb;
+#ifdef CONFIG_MSCHUNKS
+extern struct msChunks msChunks;
+#endif /* CONFIG_MSCHUNKS */
+
+#define MAX_PHB 16 * 3  // 16 Towers * 3 PHBs/tower
+struct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}};
+
+char *bootpath = 0;
+char *bootdevice = 0;
+
+struct device_node *allnodes = 0;
+
+#define UNDEFINED_IRQ 0xffff
+unsigned short real_irq_to_virt_map[NR_HW_IRQS];
+unsigned short virt_irq_to_real_map[NR_IRQS];
+int last_virt_irq = 2;	/* index of last virt_irq.  Skip through IPI */
+
+static unsigned long call_prom(const char *service, int nargs, int nret, ...);
+static void prom_exit(void);
+static unsigned long copy_device_tree(unsigned long);
+static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
+				  unsigned long, struct device_node ***);
+static unsigned long finish_node(struct device_node *, unsigned long,
+				 interpret_func *, int, int);
+static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
+static unsigned long check_display(unsigned long);
+static int prom_next_node(phandle *);
+static struct bi_record * prom_bi_rec_verify(struct bi_record *);
+static unsigned long prom_bi_rec_reserve(unsigned long);
+static struct device_node *find_phandle(phandle);
+
+#ifdef CONFIG_MSCHUNKS
+static unsigned long prom_initialize_mschunks(unsigned long);
+#ifdef DEBUG_PROM
+void prom_dump_mschunks_mapping(void);
+#endif /* DEBUG_PROM */
+#endif /* CONFIG_MSCHUNKS */
+#ifdef DEBUG_PROM
+void prom_dump_lmb(void);
+#endif
+
+extern unsigned long reloc_offset(void);
+
+extern void enter_prom(void *dummy,...);
+
+void cacheable_memzero(void *, unsigned int);
+
+extern char cmd_line[512];	/* XXX */
+unsigned long dev_tree_size;
+
+#ifdef CONFIG_HMT
+struct {
+	unsigned int pir;
+	unsigned int threadid;
+} hmt_thread_data[NR_CPUS] = {0};
+#endif /* CONFIG_HMT */
+
+char testString[] = "LINUX\n"; 
+
+
+/* This is the one and *ONLY* place where we actually call open
+ * firmware from, since we need to make sure we're running in 32b
+ * mode when we do.  We switch back to 64b mode upon return.
+ */
+
+static unsigned long __init
+call_prom(const char *service, int nargs, int nret, ...)
+{
+	int i;
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+	va_list list;
+        
+	_prom->args.service = (u32)LONG_LSW(service);
+	_prom->args.nargs = nargs;
+	_prom->args.nret = nret;
+        _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]);
+
+        va_start(list, nret);
+	for (i=0; i < nargs ;i++)
+		_prom->args.args[i] = (prom_arg_t)LONG_LSW(va_arg(list, unsigned long));
+        va_end(list);
+
+	for (i=0; i < nret ;i++)
+		_prom->args.rets[i] = 0;
+
+	enter_prom(&_prom->args);
+
+	return (unsigned long)((nret > 0) ? _prom->args.rets[0] : 0);
+}
+
+
+static void __init
+prom_exit()
+{
+	unsigned long offset = reloc_offset();
+
+	call_prom(RELOC("exit"), 0, 0);
+
+	for (;;)			/* should never get here */
+		;
+}
+
+void __init
+prom_enter(void)
+{
+	unsigned long offset = reloc_offset();
+
+	call_prom(RELOC("enter"), 0, 0);
+}
+
+
+void __init
+prom_print(const char *msg)
+{
+	const char *p, *q;
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+
+	if (_prom->stdout == 0)
+		return;
+
+	for (p = msg; *p != 0; p = q) {
+		for (q = p; *q != 0 && *q != '\n'; ++q)
+			;
+		if (q > p)
+			call_prom(RELOC("write"), 3, 1, _prom->stdout,
+				  p, q - p);
+		if (*q != 0) {
+			++q;
+			call_prom(RELOC("write"), 3, 1, _prom->stdout,
+				  RELOC("\r\n"), 2);
+		}
+	}
+}
+
+void
+prom_print_hex(unsigned long val)
+{
+        int i, nibbles = sizeof(val)*2;
+        char buf[sizeof(val)*2+1];
+
+        for (i = nibbles-1;  i >= 0;  i--) {
+                buf[i] = (val & 0xf) + '0';
+                if (buf[i] > '9')
+                    buf[i] += ('a'-'0'-10);
+                val >>= 4;
+        }
+        buf[nibbles] = '\0';
+	prom_print(buf);
+}
+
+void
+prom_print_nl(void)
+{
+	unsigned long offset = reloc_offset();
+	prom_print(RELOC("\n"));
+}
+
+
+static unsigned long
+prom_initialize_naca(unsigned long mem)
+{
+	phandle node;
+	char type[64];
+        unsigned long num_cpus = 0;
+        unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+        struct Naca *_naca = RELOC(naca);
+
+#ifdef DEBUG_PROM
+	prom_print(RELOC("prom_initialize_naca: start...\n"));
+#endif
+
+	_naca->pftSize = 0;	/* ilog2 of htab size.  computed below. */
+
+        for (node = 0; prom_next_node(&node); ) {
+                type[0] = 0;
+                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+                          type, sizeof(type));
+
+                if (!strcmp(type, RELOC("cpu"))) {
+			num_cpus += 1;
+
+			/* We're assuming *all* of the CPUs have the same
+			 * d-cache and i-cache sizes... -Peter
+			 */
+			if ( num_cpus == 1 ) {
+				u32 size;
+
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("d-cache-line-size"),
+					  &size, sizeof(size));
+
+				_naca->dCacheL1LineSize     = size;
+				_naca->dCacheL1LogLineSize  = __ilog2(size);
+				_naca->dCacheL1LinesPerPage = PAGE_SIZE / size;
+
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("i-cache-line-size"),
+					  &size, sizeof(size));
+
+				_naca->iCacheL1LineSize     = size;
+				_naca->iCacheL1LogLineSize  = __ilog2(size);
+				_naca->iCacheL1LinesPerPage = PAGE_SIZE / size;
+
+				if (RELOC(_machine) == _MACH_pSeriesLP) {
+					u32 pft_size[2];
+					call_prom(RELOC("getprop"), 4, 1, node, 
+						  RELOC("ibm,pft-size"),
+						  &pft_size, sizeof(pft_size));
+				/* pft_size[0] is the NUMA CEC cookie */
+					_naca->pftSize = pft_size[1];
+				}
+			}
+                } else if (!strcmp(type, RELOC("serial"))) {
+			phandle isa, pci;
+			struct isa_reg_property reg;
+			union pci_range ranges;
+
+			type[0] = 0;
+			call_prom(RELOC("getprop"), 4, 1, node,
+				  RELOC("ibm,aix-loc"), type, sizeof(type));
+
+			if (strcmp(type, RELOC("S1")))
+				continue;
+
+			call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
+				  &reg, sizeof(reg));
+
+			isa = call_prom(RELOC("parent"), 1, 1, node);
+			if (!isa)
+				PROM_BUG();
+			pci = call_prom(RELOC("parent"), 1, 1, isa);
+			if (!pci)
+				PROM_BUG();
+
+			call_prom(RELOC("getprop"), 4, 1, pci, RELOC("ranges"),
+				  &ranges, sizeof(ranges));
+
+			if ( _prom->encode_phys_size == 32 )
+				_naca->serialPortAddr = ranges.pci32.phys+reg.address;
+			else {
+				_naca->serialPortAddr = 
+					((((unsigned long)ranges.pci64.phys_hi) << 32) |
+					 (ranges.pci64.phys_lo)) + reg.address;
+			}
+                }
+	}
+
+	_naca->interrupt_controller = IC_INVALID;
+        for (node = 0; prom_next_node(&node); ) {
+                type[0] = 0;
+                call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
+                          type, sizeof(type));
+                if (strcmp(type, RELOC("interrupt-controller"))) {
+			continue;
+		}
+                call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
+                          type, sizeof(type));
+                if (strstr(type, RELOC("open-pic"))) {
+			_naca->interrupt_controller = IC_OPEN_PIC;
+		} else if (strstr(type, RELOC("ppc-xicp"))) {
+			_naca->interrupt_controller = IC_PPC_XIC;
+		} else {
+			prom_print(RELOC("prom: failed to recognize interrupt-controller\n"));
+		}
+		break;
+	}
+
+	if (_naca->interrupt_controller == IC_INVALID) {
+		prom_print(RELOC("prom: failed to find interrupt-controller\n"));
+		PROM_BUG();
+	}
+
+	/* We gotta have at least 1 cpu... */
+        if ( (_naca->processorCount = num_cpus) < 1 )
+                PROM_BUG();
+
+	_naca->physicalMemorySize = lmb_phys_mem_size();
+
+	if (RELOC(_machine) == _MACH_pSeries) {
+		unsigned long rnd_mem_size, pteg_count;
+
+		/* round mem_size up to next power of 2 */
+		rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize);
+		if (rnd_mem_size < _naca->physicalMemorySize)
+			rnd_mem_size <<= 1;
+
+		/* # pages / 2 */
+		pteg_count = (rnd_mem_size >> (12 + 1));
+
+		_naca->pftSize = __ilog2(pteg_count << 7);
+	}
+
+	if (_naca->pftSize == 0) {
+		prom_print(RELOC("prom: failed to compute pftSize!\n"));
+		PROM_BUG();
+	}
+
+	/* 
+	 * Hardcode to GP size.  I am not sure where to get this info
+	 * in general, as there does not appear to be a slb-size OF
+	 * entry.  At least in Condor and earlier.  DRENG 
+	 */
+	_naca->slb_size = 64;
+
+#ifdef DEBUG_PROM
+        prom_print(RELOC("naca->processorCount       = 0x"));
+        prom_print_hex(_naca->processorCount);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->physicalMemorySize   = 0x"));
+        prom_print_hex(_naca->physicalMemorySize);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->pftSize              = 0x"));
+        prom_print_hex(_naca->pftSize);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->dCacheL1LineSize     = 0x"));
+        prom_print_hex(_naca->dCacheL1LineSize);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->dCacheL1LogLineSize  = 0x"));
+        prom_print_hex(_naca->dCacheL1LogLineSize);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x"));
+        prom_print_hex(_naca->dCacheL1LinesPerPage);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->iCacheL1LineSize     = 0x"));
+        prom_print_hex(_naca->iCacheL1LineSize);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->iCacheL1LogLineSize  = 0x"));
+        prom_print_hex(_naca->iCacheL1LogLineSize);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x"));
+        prom_print_hex(_naca->iCacheL1LinesPerPage);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->serialPortAddr       = 0x"));
+        prom_print_hex(_naca->serialPortAddr);
+        prom_print_nl();
+
+        prom_print(RELOC("naca->interrupt_controller = 0x"));
+        prom_print_hex(_naca->interrupt_controller);
+        prom_print_nl();
+
+        prom_print(RELOC("_machine                   = 0x"));
+        prom_print_hex(RELOC(_machine));
+        prom_print_nl();
+
+	prom_print(RELOC("prom_initialize_naca: end...\n"));
+#endif
+
+	return mem;
+}
+
+
+static unsigned long __init
+prom_initialize_lmb(unsigned long mem)
+{
+	phandle node;
+	char type[64];
+        unsigned long i, offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+	union lmb_reg_property reg;
+	unsigned long lmb_base, lmb_size;
+	unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
+
+#ifdef CONFIG_MSCHUNKS
+	unsigned long max_addr = 0;
+#if 1
+	/* Fix me: 630 3G-4G IO hack here... -Peter (PPPBBB) */
+	unsigned long io_base = 3UL<<30;
+	unsigned long io_size = 1UL<<30;
+	unsigned long have_630 = 1;	/* assume we have a 630 */
+
+#else
+	unsigned long io_base = <real io base here>;
+	unsigned long io_size = <real io size here>;
+#endif
+#endif /* CONFIG_MSCHUNKS */
+
+	lmb_init();
+
+        for (node = 0; prom_next_node(&node); ) {
+                type[0] = 0;
+                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+                          type, sizeof(type));
+
+                if (strcmp(type, RELOC("memory")))
+			continue;
+
+		num_regs = call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
+			&reg, sizeof(reg)) / bytes_per_reg;
+
+		for (i=0; i < num_regs ;i++) {
+			if (_prom->encode_phys_size == 32) {
+				lmb_base = reg.addr32[i].address;
+				lmb_size = reg.addr32[i].size;
+			} else {
+				lmb_base = reg.addr64[i].address;
+				lmb_size = reg.addr64[i].size;
+			}
+
+#ifdef CONFIG_MSCHUNKS
+			if ( lmb_addrs_overlap(lmb_base,lmb_size,
+						io_base,io_size) ) {
+				/* If we really have dram here, then we don't
+			 	 * have a 630! -Peter
+			 	 */
+				have_630 = 0;
+			}
+#endif /* CONFIG_MSCHUNKS */
+			if ( lmb_add(lmb_base, lmb_size) < 0 )
+				prom_print(RELOC("Too many LMB's, discarding this one...\n"));
+#ifdef CONFIG_MSCHUNKS
+			else if ( max_addr < (lmb_base+lmb_size-1) )
+				max_addr = lmb_base+lmb_size-1;
+#endif /* CONFIG_MSCHUNKS */
+		}
+
+	}
+
+#ifdef CONFIG_MSCHUNKS
+	if ( have_630 && lmb_addrs_overlap(0,max_addr,io_base,io_size) )
+		lmb_add_io(io_base, io_size);
+#endif /* CONFIG_MSCHUNKS */
+
+	lmb_analyze();
+#ifdef DEBUG_PROM
+	prom_dump_lmb();
+#endif /* DEBUG_PROM */
+
+#ifdef CONFIG_MSCHUNKS
+	mem = prom_initialize_mschunks(mem);
+#ifdef DEBUG_PROM
+	prom_dump_mschunks_mapping();
+#endif /* DEBUG_PROM */
+#endif /* CONFIG_MSCHUNKS */
+
+	return mem;
+}
+
+
+static unsigned long __init
+prom_instantiate_rtas(unsigned long mem)
+{
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+	struct rtas_t *_rtas = PTRRELOC(&rtas);
+	ihandle prom_rtas;
+        u32 getprop_rval;
+
+#ifdef DEBUG_PROM
+	prom_print(RELOC("prom_instantiate_rtas: start...\n"));
+#endif
+	prom_rtas = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
+	if (prom_rtas != (ihandle) -1) {
+		char hypertas_funcs[1024];
+		int  rc; 
+		
+		if ((rc = call_prom(RELOC("getprop"), 
+				  4, 1, prom_rtas,
+				  RELOC("ibm,hypertas-functions"), 
+				  hypertas_funcs, 
+				  sizeof(hypertas_funcs))) > 0) {
+			RELOC(_machine) = _MACH_pSeriesLP;
+		}
+
+		call_prom(RELOC("getprop"), 
+			  4, 1, prom_rtas,
+			  RELOC("rtas-size"), 
+			  &getprop_rval, 
+			  sizeof(getprop_rval));
+	        _rtas->size = getprop_rval;
+		prom_print(RELOC("instantiating rtas"));
+		if (_rtas->size != 0) {
+			/*
+			 * Ask OF for some space for RTAS.
+			 * Actually OF has bugs so we just arbitrarily
+			 * use memory at the 6MB point.
+			 */
+			// The new code...
+			mem = PAGE_ALIGN(mem);
+			_rtas->base = mem + offset - KERNELBASE;
+
+			mem += _rtas->size;
+			prom_print(RELOC(" at 0x"));
+			prom_print_hex(_rtas->base);
+
+			prom_rtas = (ihandle)call_prom(RELOC("open"), 
+					      	1, 1, RELOC("/rtas"));
+			prom_print(RELOC("..."));
+
+			if ((long)call_prom(RELOC("call-method"), 3, 2,
+						      RELOC("instantiate-rtas"),
+						      prom_rtas,
+						      _rtas->base) >= 0) {
+				_rtas->entry = (long)_prom->args.rets[1];
+			}
+		}
+
+		if (_rtas->entry <= 0) {
+			prom_print(RELOC(" failed\n"));
+		} else {
+			prom_print(RELOC(" done\n"));
+		}
+
+#ifdef DEBUG_PROM
+        	prom_print(RELOC("rtas->base                 = 0x"));
+        	prom_print_hex(_rtas->base);
+        	prom_print_nl();
+        	prom_print(RELOC("rtas->entry                = 0x"));
+        	prom_print_hex(_rtas->entry);
+        	prom_print_nl();
+        	prom_print(RELOC("rtas->size                 = 0x"));
+        	prom_print_hex(_rtas->size);
+        	prom_print_nl();
+#endif
+	}
+#ifdef DEBUG_PROM
+	prom_print(RELOC("prom_instantiate_rtas: end...\n"));
+#endif
+
+	return mem;
+}
+
+unsigned long prom_strtoul(const char *cp)
+{
+	unsigned long result = 0,value;
+
+	while (*cp) {
+		value = *cp-'0';
+		result = result*10 + value;
+		cp++;
+	} 
+
+	return result;
+}
+
+
+#ifdef CONFIG_MSCHUNKS
+static unsigned long
+prom_initialize_mschunks(unsigned long mem)
+{
+        unsigned long offset = reloc_offset();
+	struct lmb *_lmb  = PTRRELOC(&lmb);
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+	unsigned long i, pchunk = 0;
+	unsigned long addr_range = _lmb->memory.size + _lmb->memory.iosize;
+	unsigned long chunk_size = _lmb->memory.lcd_size;
+
+
+	mem = msChunks_alloc(mem, addr_range / chunk_size, chunk_size);
+
+	/* First create phys -> abs mapping for memory/dram */
+	for (i=0; i < _lmb->memory.cnt ;i++) {
+		unsigned long base = _lmb->memory.region[i].base;
+		unsigned long size = _lmb->memory.region[i].size;
+		unsigned long achunk = addr_to_chunk(base);
+		unsigned long end_achunk = addr_to_chunk(base+size);
+
+		if(_lmb->memory.region[i].type != LMB_MEMORY_AREA)
+			continue;
+
+		_lmb->memory.region[i].physbase = chunk_to_addr(pchunk);
+		for (; achunk < end_achunk ;) {
+			PTRRELOC(_msChunks->abs)[pchunk++] = achunk++;
+		}
+	}
+
+	/* Now create phys -> abs mapping for IO */
+	for (i=0; i < _lmb->memory.cnt ;i++) {
+		unsigned long base = _lmb->memory.region[i].base;
+		unsigned long size = _lmb->memory.region[i].size;
+		unsigned long achunk = addr_to_chunk(base);
+		unsigned long end_achunk = addr_to_chunk(base+size);
+
+		if(_lmb->memory.region[i].type != LMB_IO_AREA)
+			continue;
+
+		_lmb->memory.region[i].physbase = chunk_to_addr(pchunk);
+		for (; achunk < end_achunk ;) {
+			PTRRELOC(_msChunks->abs)[pchunk++] = achunk++;
+		}
+	}
+
+	return mem;
+}
+
+#ifdef DEBUG_PROM
+void
+prom_dump_mschunks_mapping(void)
+{
+        unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+	unsigned long chunk;
+
+        prom_print(RELOC("\nprom_dump_mschunks_mapping:\n"));
+        prom_print(RELOC("    msChunks.num_chunks         = 0x"));
+        prom_print_hex(_msChunks->num_chunks);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.chunk_size         = 0x"));
+        prom_print_hex(_msChunks->chunk_size);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.chunk_shift        = 0x"));
+        prom_print_hex(_msChunks->chunk_shift);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.chunk_mask         = 0x"));
+        prom_print_hex(_msChunks->chunk_mask);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.abs                = 0x"));
+        prom_print_hex(_msChunks->abs);
+	prom_print_nl();
+
+        prom_print(RELOC("    msChunks mapping:\n"));
+	for(chunk=0; chunk < _msChunks->num_chunks ;chunk++) {
+        	prom_print(RELOC("        phys 0x"));
+        	prom_print_hex(chunk);
+        	prom_print(RELOC(" -> abs 0x"));
+        	prom_print_hex(PTRRELOC(_msChunks->abs)[chunk]);
+		prom_print_nl();
+	}
+
+}
+#endif /* DEBUG_PROM */
+#endif /* CONFIG_MSCHUNKS */
+
+#ifdef DEBUG_PROM
+void
+prom_dump_lmb(void)
+{
+        unsigned long i;
+        unsigned long offset = reloc_offset();
+	struct lmb *_lmb  = PTRRELOC(&lmb);
+
+        prom_print(RELOC("\nprom_dump_lmb:\n"));
+        prom_print(RELOC("    memory.cnt                  = 0x"));
+        prom_print_hex(_lmb->memory.cnt);
+	prom_print_nl();
+        prom_print(RELOC("    memory.size                 = 0x"));
+        prom_print_hex(_lmb->memory.size);
+	prom_print_nl();
+        prom_print(RELOC("    memory.lcd_size             = 0x"));
+        prom_print_hex(_lmb->memory.lcd_size);
+	prom_print_nl();
+        for (i=0; i < _lmb->memory.cnt ;i++) {
+                prom_print(RELOC("    memory.region[0x"));
+		prom_print_hex(i);
+		prom_print(RELOC("].base       = 0x"));
+                prom_print_hex(_lmb->memory.region[i].base);
+		prom_print_nl();
+                prom_print(RELOC("                      .physbase = 0x"));
+                prom_print_hex(_lmb->memory.region[i].physbase);
+		prom_print_nl();
+                prom_print(RELOC("                      .size     = 0x"));
+                prom_print_hex(_lmb->memory.region[i].size);
+		prom_print_nl();
+                prom_print(RELOC("                      .type     = 0x"));
+                prom_print_hex(_lmb->memory.region[i].type);
+		prom_print_nl();
+        }
+
+	prom_print_nl();
+        prom_print(RELOC("    reserved.cnt                  = 0x"));
+        prom_print_hex(_lmb->reserved.cnt);
+	prom_print_nl();
+        prom_print(RELOC("    reserved.size                 = 0x"));
+        prom_print_hex(_lmb->reserved.size);
+	prom_print_nl();
+        prom_print(RELOC("    reserved.lcd_size             = 0x"));
+        prom_print_hex(_lmb->reserved.lcd_size);
+	prom_print_nl();
+        for (i=0; i < _lmb->reserved.cnt ;i++) {
+                prom_print(RELOC("    reserved.region[0x"));
+		prom_print_hex(i);
+		prom_print(RELOC("].base       = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].base);
+		prom_print_nl();
+                prom_print(RELOC("                      .physbase = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].physbase);
+		prom_print_nl();
+                prom_print(RELOC("                      .size     = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].size);
+		prom_print_nl();
+                prom_print(RELOC("                      .type     = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].type);
+		prom_print_nl();
+        }
+}
+#endif /* DEBUG_PROM */
+
+
+void
+prom_initialize_tce_table(void)
+{
+	phandle node;
+	ihandle phb_node;
+        unsigned long offset = reloc_offset();
+	char compatible[64], path[64], type[64];
+	unsigned long i, table = 0;
+	unsigned long base, vbase, align;
+	unsigned int minalign, minsize;
+	struct _of_tce_table *prom_tce_table = RELOC(of_tce_table);
+	unsigned long tce_entry, *tce_entryp;
+
+#ifdef DEBUG_PROM
+	prom_print(RELOC("starting prom_initialize_tce_table\n"));
+#endif
+
+	/* Search all nodes looking for PHBs. */
+	for (node = 0; prom_next_node(&node); ) {
+		compatible[0] = 0;
+		type[0] = 0;
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
+			  compatible, sizeof(compatible));
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+			  type, sizeof(type));
+
+		if ((compatible[0] == 0) ||
+		   ((strstr(compatible, RELOC("python")) == NULL) &&
+		    (strstr(compatible, RELOC("Speedwagon")) == NULL))) {
+			continue;
+		}
+		if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) {
+			continue;
+		}
+
+		if (call_prom(RELOC("getprop"), 4, 1, node, 
+			     RELOC("tce-table-minalign"), &minalign, 
+			     sizeof(minalign)) < 0) {
+			minalign = 0;
+		}
+
+		if (call_prom(RELOC("getprop"), 4, 1, node, 
+			     RELOC("tce-table-minsize"), &minsize, 
+			     sizeof(minsize)) < 0) {
+			minsize = 4UL << 20;
+		}
+
+		/* Even though we read what OF wants, we just set the table
+		 * size to 4 MB.  This is enough to map 2GB of PCI DMA space.
+		 * By doing this, we avoid the pitfalls of trying to DMA to
+		 * MMIO space and the DMA alias hole.
+		 */
+		minsize = 4UL << 20;
+
+		/* Align to the greater of the align or size */
+		align = (minalign < minsize) ? minsize : minalign;
+
+		/* Carve out storage for the TCE table. */
+		base = lmb_alloc(minsize, align);
+
+		if ( !base ) {
+			prom_print(RELOC("ERROR, cannot find space for TCE table.\n"));
+			prom_exit();
+		}
+
+		vbase = absolute_to_virt(base);
+
+		/* Save away the TCE table attributes for later use. */
+		prom_tce_table[table].node = node;
+		prom_tce_table[table].base = vbase;
+		prom_tce_table[table].size = minsize;
+
+#ifdef DEBUG_PROM
+		prom_print(RELOC("TCE table: 0x"));
+		prom_print_hex(table);
+		prom_print_nl();
+
+		prom_print(RELOC("\tnode = 0x"));
+		prom_print_hex(node);
+		prom_print_nl();
+
+		prom_print(RELOC("\tbase = 0x"));
+		prom_print_hex(vbase);
+		prom_print_nl();
+
+		prom_print(RELOC("\tsize = 0x"));
+		prom_print_hex(minsize);
+		prom_print_nl();
+#endif
+
+		/* Initialize the table to have a one-to-one mapping
+		 * over the allocated size.
+		 */
+		tce_entryp = (unsigned long *)base;
+		for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
+			tce_entry = (i << PAGE_SHIFT);
+			tce_entry |= 0x3;
+			*tce_entryp = tce_entry;
+		}
+
+		/* Call OF to setup the TCE hardware */
+		if (call_prom(RELOC("package-to-path"), 3, 1, node,
+                             path, 255) <= 0) {
+                        prom_print(RELOC("package-to-path failed\n"));
+                } else {
+                        prom_print(RELOC("opened "));
+                        prom_print(path);
+                        prom_print_nl();
+                }
+
+                phb_node = (ihandle)call_prom(RELOC("open"), 1, 1, path);
+                if ( (long)phb_node <= 0) {
+                        prom_print(RELOC("open failed\n"));
+                } else {
+                        prom_print(RELOC("open success\n"));
+                }
+                call_prom(RELOC("call-method"), 6, 0,
+                             RELOC("set-64-bit-addressing"),
+			     phb_node,
+			     -1,
+                             minsize, 
+                             base & 0xffffffff,
+                             (base >> 32) & 0xffffffff);
+                call_prom(RELOC("close"), 1, 0, phb_node);
+
+		table++;
+	}
+
+	/* Flag the first invalid entry */
+	prom_tce_table[table].node = 0;
+#ifdef DEBUG_PROM
+	prom_print(RELOC("ending prom_initialize_tce_table\n"));
+#endif
+}
+
+/*
+ * With CHRP SMP we need to use the OF to start the other
+ * processors so we can't wait until smp_boot_cpus (the OF is
+ * trashed by then) so we have to put the processors into
+ * a holding pattern controlled by the kernel (not OF) before
+ * we destroy the OF.
+ *
+ * This uses a chunk of low memory, puts some holding pattern
+ * code there and sends the other processors off to there until
+ * smp_boot_cpus tells them to do something.  The holding pattern
+ * checks that address until its cpu # is there, when it is that
+ * cpu jumps to __secondary_start().  smp_boot_cpus() takes care
+ * of setting those values.
+ *
+ * We also use physical address 0x4 here to tell when a cpu
+ * is in its holding pattern code.
+ *
+ * Fixup comment... DRENG / PPPBBB - Peter
+ *
+ * -- Cort
+ */
+static void
+prom_hold_cpus(unsigned long mem)
+{
+	unsigned long i;
+	unsigned int reg;
+	phandle node;
+	unsigned long offset = reloc_offset();
+	char type[64], *path;
+	int cpuid = 0;
+	extern void __secondary_hold(void);
+        extern unsigned long __secondary_hold_spinloop;
+        extern unsigned long __secondary_hold_acknowledge;
+        unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
+        unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
+        unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
+        struct Naca *_naca = RELOC(naca);
+	struct Paca *_xPaca = PTRRELOC(&xPaca[0]);
+	struct prom_t *_prom = PTRRELOC(&prom);
+
+	/* Initially, we must have one active CPU. */
+	_naca->processorCount = 1;
+
+#ifdef DEBUG_PROM
+	prom_print(RELOC("prom_hold_cpus: start...\n"));
+	prom_print(RELOC("    1) spinloop       = 0x"));
+	prom_print_hex(spinloop);
+	prom_print_nl();
+	prom_print(RELOC("    1) *spinloop      = 0x"));
+	prom_print_hex(*spinloop);
+	prom_print_nl();
+	prom_print(RELOC("    1) acknowledge    = 0x"));
+	prom_print_hex(acknowledge);
+	prom_print_nl();
+	prom_print(RELOC("    1) *acknowledge   = 0x"));
+	prom_print_hex(*acknowledge);
+	prom_print_nl();
+	prom_print(RELOC("    1) secondary_hold = 0x"));
+	prom_print_hex(secondary_hold);
+	prom_print_nl();
+#endif
+
+        /* Set the common spinloop variable, so all of the secondary cpus
+	 * will block when they are awakened from their OF spinloop.
+	 * This must occur for both SMP and non SMP kernels, since OF will
+	 * be trashed when we move the kernel.
+         */
+        *spinloop = 0;
+
+#ifdef CONFIG_HMT
+	for (i=0; i < NR_CPUS; i++) {
+		RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
+	}
+#endif
+	/* look for cpus */
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+			  type, sizeof(type));
+		if (strcmp(type, RELOC("cpu")) != 0)
+			continue;
+
+		/* Skip non-configured cpus. */
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("status"),
+			  type, sizeof(type));
+		if (strcmp(type, RELOC("okay")) != 0)
+			continue;
+
+                reg = -1;
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
+			  &reg, sizeof(reg));
+
+		/* Only need to start secondary procs, not ourself. */
+		if ( reg == _prom->cpu )
+			continue;
+
+		path = (char *) mem;
+		memset(path, 0, 256);
+		if ((long) call_prom(RELOC("package-to-path"), 3, 1,
+				     node, path, 255) < 0)
+			continue;
+
+		cpuid++;
+
+#ifdef DEBUG_PROM
+		prom_print_nl();
+		prom_print(RELOC("cpuid        = 0x"));
+		prom_print_hex(cpuid);
+		prom_print_nl();
+		prom_print(RELOC("cpu hw idx   = 0x"));
+		prom_print_hex(reg);
+		prom_print_nl();
+#endif
+		_xPaca[cpuid].xHwProcNum = reg;
+
+		prom_print(RELOC("starting cpu "));
+		prom_print(path);
+
+		/* Init the acknowledge var which will be reset by
+		 * the secondary cpu when it awakens from its OF
+		 * spinloop.
+		 */
+		*acknowledge = (unsigned long)-1;
+
+#ifdef DEBUG_PROM
+		prom_print(RELOC("    3) spinloop       = 0x"));
+		prom_print_hex(spinloop);
+		prom_print_nl();
+		prom_print(RELOC("    3) *spinloop      = 0x"));
+		prom_print_hex(*spinloop);
+		prom_print_nl();
+		prom_print(RELOC("    3) acknowledge    = 0x"));
+		prom_print_hex(acknowledge);
+		prom_print_nl();
+		prom_print(RELOC("    3) *acknowledge   = 0x"));
+		prom_print_hex(*acknowledge);
+		prom_print_nl();
+		prom_print(RELOC("    3) secondary_hold = 0x"));
+		prom_print_hex(secondary_hold);
+		prom_print_nl();
+		prom_print(RELOC("    3) cpuid = 0x"));
+		prom_print_hex(cpuid);
+		prom_print_nl();
+#endif
+		call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid);
+		prom_print(RELOC("..."));
+		for ( i = 0 ; (i < 100000000) && 
+			      (*acknowledge == ((unsigned long)-1)); i++ ) ;
+#ifdef DEBUG_PROM
+		{
+			unsigned long *p = 0x0;
+			prom_print(RELOC("    4) 0x0 = 0x"));
+			prom_print_hex(*p);
+			prom_print_nl();
+		}
+#endif
+		if (*acknowledge == cpuid) {
+			prom_print(RELOC("ok\n"));
+			/* Set the number of active processors. */
+			_naca->processorCount++;
+		} else {
+			prom_print(RELOC("failed: "));
+			prom_print_hex(*acknowledge);
+			prom_print_nl();
+		}
+	}
+#ifdef CONFIG_HMT
+	/* Only enable HMT on processors that provide support. */
+	if (__is_processor(PV_PULSAR) || 
+	    __is_processor(PV_ICESTAR) ||
+	    __is_processor(PV_SSTAR)) {
+		prom_print(RELOC("    starting secondary threads\n"));
+
+		for (i=0; i < _naca->processorCount ;i++) {
+			unsigned long threadid = _naca->processorCount*2-1-i;
+			
+			if (i == 0) {
+				unsigned long pir = _get_PIR();
+				if (__is_processor(PV_PULSAR)) {
+					RELOC(hmt_thread_data)[i].pir = 
+						pir & 0x1f;
+				} else {
+					RELOC(hmt_thread_data)[i].pir = 
+						pir & 0x3ff;
+				}
+			}
+			
+			RELOC(hmt_thread_data)[i].threadid = threadid;
+#ifdef DEBUG_PROM
+			prom_print(RELOC("        cpuid 0x"));
+			prom_print_hex(i);
+			prom_print(RELOC(" maps to threadid 0x"));
+			prom_print_hex(threadid);
+			prom_print_nl();
+			prom_print(RELOC(" pir 0x"));
+			prom_print_hex(RELOC(hmt_thread_data)[i].pir);
+			prom_print_nl();
+#endif
+			_xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1;
+		}
+		_naca->processorCount *= 2;
+	} else {
+		prom_print(RELOC("Processor is not HMT capable\n"));
+	}
+#endif
+	
+#ifdef DEBUG_PROM
+	prom_print(RELOC("prom_hold_cpus: end...\n"));
+#endif
+}
+
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+
+unsigned long __init
+prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
+	  unsigned long r6, unsigned long r7, yaboot_debug_t *yaboot)
+{
+	int chrp = 0;
+	unsigned long mem;
+	ihandle prom_mmu, prom_op, prom_root, prom_cpu;
+	phandle cpu_pkg;
+	unsigned long offset = reloc_offset();
+	long l;
+	char *p, *d;
+ 	unsigned long phys;
+        u32 getprop_rval;
+        struct Naca   *_naca = RELOC(naca);
+	struct Paca *_xPaca = PTRRELOC(&xPaca[0]);
+	struct prom_t *_prom = PTRRELOC(&prom);
+
+	/* Default machine type. */
+	RELOC(_machine) = _MACH_pSeries;
+	/* Reset klimit to take into account the embedded system map */
+	if (RELOC(embedded_sysmap_end))
+		RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
+
+	/* Get a handle to the prom entry point before anything else */
+	_prom->entry = pp;
+	_prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6);
+	if ( _prom->bi_recs != NULL ) {
+		RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + _prom->bi_recs->data[1]);
+	}
+
+#ifdef DEBUG_YABOOT
+	call_yaboot(yaboot->dummy,offset>>32,offset&0xffffffff);
+	call_yaboot(yaboot->printf, RELOC("offset = 0x%08x%08x\n"), LONG_MSW(offset), LONG_LSW(offset));
+#endif
+
+ 	/* Default */
+ 	phys = KERNELBASE - offset;
+
+#ifdef DEBUG_YABOOT
+	call_yaboot(yaboot->printf, RELOC("phys = 0x%08x%08x\n"), LONG_MSW(phys), LONG_LSW(phys));
+#endif
+
+
+#ifdef DEBUG_YABOOT
+	_prom->yaboot = yaboot;
+	call_yaboot(yaboot->printf, RELOC("pp = 0x%08x%08x\n"), LONG_MSW(pp), LONG_LSW(pp));
+	call_yaboot(yaboot->printf, RELOC("prom = 0x%08x%08x\n"), LONG_MSW(_prom->entry), LONG_LSW(_prom->entry));
+#endif
+
+	/* First get a handle for the stdout device */
+	_prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1,
+				       RELOC("/chosen"));
+
+#ifdef DEBUG_YABOOT
+	call_yaboot(yaboot->printf, RELOC("prom->chosen = 0x%08x%08x\n"), LONG_MSW(_prom->chosen), LONG_LSW(_prom->chosen));
+#endif
+
+	if ((long)_prom->chosen <= 0)
+		prom_exit();
+
+        if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
+			    RELOC("stdout"), &getprop_rval,
+			    sizeof(getprop_rval)) <= 0)
+                prom_exit();
+
+        _prom->stdout = (ihandle)(unsigned long)getprop_rval;
+
+#ifdef DEBUG_YABOOT
+        if (_prom->stdout == 0) {
+	    call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout));
+        }
+
+	call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout));
+#endif
+
+#ifdef DEBUG_YABOOT
+	call_yaboot(yaboot->printf, RELOC("Location: 0x11\n"));
+#endif
+
+	mem = RELOC(klimit) - offset; 
+#ifdef DEBUG_YABOOT
+	call_yaboot(yaboot->printf, RELOC("Location: 0x11b\n"));
+#endif
+
+	/* Get the full OF pathname of the stdout device */
+	p = (char *) mem;
+	memset(p, 0, 256);
+	call_prom(RELOC("instance-to-path"), 3, 1, _prom->stdout, p, 255);
+	RELOC(of_stdout_device) = PTRUNRELOC(p);
+	mem += strlen(p) + 1;
+
+	getprop_rval = 1;
+	prom_root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
+	if (prom_root != (ihandle)-1) {
+                call_prom(RELOC("getprop"), 4, 1,
+                    prom_root, RELOC("#size-cells"),
+		    &getprop_rval, sizeof(getprop_rval));
+	}
+	_prom->encode_phys_size = (getprop_rval==1) ? 32 : 64;
+
+#ifdef DEBUG_PROM
+	prom_print(RELOC("DRENG:    Detect OF version...\n"));
+#endif
+	/* Find the OF version */
+	prom_op = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));
+	if (prom_op != (ihandle)-1) {
+		char model[64];
+		long sz;
+		sz = (long)call_prom(RELOC("getprop"), 4, 1, prom_op,
+				    RELOC("model"), model, 64);
+		if (sz > 0) {
+			char *c;
+			/* hack to skip the ibm chrp firmware # */
+			if ( strncmp(model,RELOC("IBM"),3) ) {
+				for (c = model; *c; c++)
+					if (*c >= '0' && *c <= '9') {
+						_prom->version = *c - '0';
+						break;
+					}
+			}
+			else
+				chrp = 1;
+		}
+	}
+	if (_prom->version >= 3)
+		prom_print(RELOC("OF Version 3 detected.\n"));
+
+
+	/* Determine which cpu is actually running right _now_ */
+        if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
+			    RELOC("cpu"), &getprop_rval,
+			    sizeof(getprop_rval)) <= 0)
+                prom_exit();
+
+	prom_cpu = (ihandle)(unsigned long)getprop_rval;
+	cpu_pkg = call_prom(RELOC("instance-to-package"), 1, 1, prom_cpu);
+	call_prom(RELOC("getprop"), 4, 1,
+		cpu_pkg, RELOC("reg"),
+		&getprop_rval, sizeof(getprop_rval));
+	_prom->cpu = (int)(unsigned long)getprop_rval;
+	_xPaca[0].xHwProcNum = _prom->cpu;
+
+#ifdef DEBUG_PROM
+  	prom_print(RELOC("Booting CPU hw index = 0x"));
+  	prom_print_hex(_prom->cpu);
+  	prom_print_nl();
+#endif
+
+	/* Get the boot device and translate it to a full OF pathname. */
+	p = (char *) mem;
+	l = (long) call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
+			    RELOC("bootpath"), p, 1<<20);
+	if (l > 0) {
+		p[l] = 0;	/* should already be null-terminated */
+		RELOC(bootpath) = PTRUNRELOC(p);
+		mem += l + 1;
+		d = (char *) mem;
+		*d = 0;
+		call_prom(RELOC("canon"), 3, 1, p, d, 1<<20);
+		RELOC(bootdevice) = PTRUNRELOC(d);
+		mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1);
+	}
+
+	mem = prom_initialize_lmb(mem);
+
+	mem = prom_bi_rec_reserve(mem);
+
+	mem = prom_instantiate_rtas(mem);
+        
+        /* Initialize some system info into the Naca early... */
+        mem = prom_initialize_naca(mem);
+
+        /* If we are on an SMP machine, then we *MUST* do the
+         * following, regardless of whether we have an SMP
+         * kernel or not.
+         */
+        if ( _naca->processorCount > 1 )
+	        prom_hold_cpus(mem);
+
+	mem = check_display(mem);
+
+#ifdef DEBUG_PROM
+	prom_print(RELOC("copying OF device tree...\n"));
+#endif
+	mem = copy_device_tree(mem);
+
+	RELOC(klimit) = mem + offset;
+
+	lmb_reserve(0, __pa(RELOC(klimit)));
+
+	if (RELOC(_machine) == _MACH_pSeries)
+		prom_initialize_tce_table();
+
+ 	if ((long) call_prom(RELOC("getprop"), 4, 1,
+				_prom->chosen,
+				RELOC("mmu"),
+				&getprop_rval,
+				sizeof(getprop_rval)) <= 0) {	
+		prom_print(RELOC(" no MMU found\n"));
+                prom_exit();
+	}
+
+	/* We assume the phys. address size is 3 cells */
+	RELOC(prom_mmu) = (ihandle)(unsigned long)getprop_rval;
+
+	if ((long)call_prom(RELOC("call-method"), 4, 4,
+				RELOC("translate"),
+				prom_mmu,
+				(void *)(KERNELBASE - offset),
+				(void *)1) != 0) {
+		prom_print(RELOC(" (translate failed) "));
+	} else {
+		prom_print(RELOC(" (translate ok) "));
+		phys = (unsigned long)_prom->args.rets[3];
+	}
+
+	/* If OpenFirmware version >= 3, then use quiesce call */
+	if (_prom->version >= 3) {
+		prom_print(RELOC("Calling quiesce ...\n"));
+		call_prom(RELOC("quiesce"), 0, 0);
+		phys = KERNELBASE - offset;
+	}
+
+	prom_print(RELOC("returning from prom_init\n"));
+	return phys;
+}
+
+
+static int
+prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+	unsigned long offset = reloc_offset();
+
+	return (int)(long)call_prom(RELOC("call-method"), 6, 1,
+		                    RELOC("color!"),
+                                    ih,
+                                    (void *)(long) i,
+                                    (void *)(long) b,
+                                    (void *)(long) g,
+                                    (void *)(long) r );
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF will probably fall over if we do that
+ * we've taken over the MMU.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static unsigned long __init
+check_display(unsigned long mem)
+{
+	phandle node;
+	ihandle ih;
+	int i;
+	unsigned long offset = reloc_offset();
+        struct prom_t *_prom = PTRRELOC(&prom);
+	char type[64], *path;
+	static unsigned char default_colors[] = {
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0xaa,
+		0x00, 0xaa, 0x00,
+		0x00, 0xaa, 0xaa,
+		0xaa, 0x00, 0x00,
+		0xaa, 0x00, 0xaa,
+		0xaa, 0xaa, 0x00,
+		0xaa, 0xaa, 0xaa,
+		0x55, 0x55, 0x55,
+		0x55, 0x55, 0xff,
+		0x55, 0xff, 0x55,
+		0x55, 0xff, 0xff,
+		0xff, 0x55, 0x55,
+		0xff, 0x55, 0xff,
+		0xff, 0xff, 0x55,
+		0xff, 0xff, 0xff
+	};
+
+	_prom->disp_node = 0;
+
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+			  type, sizeof(type));
+		if (strcmp(type, RELOC("display")) != 0)
+			continue;
+		/* It seems OF doesn't null-terminate the path :-( */
+		path = (char *) mem;
+		memset(path, 0, 256);
+		if ((long) call_prom(RELOC("package-to-path"), 3, 1,
+				    node, path, 255) < 0)
+			continue;
+		prom_print(RELOC("opening display "));
+		prom_print(path);
+		ih = (ihandle)call_prom(RELOC("open"), 1, 1, path);
+		if (ih == (ihandle)0 || ih == (ihandle)-1) {
+			prom_print(RELOC("... failed\n"));
+			continue;
+		}
+		prom_print(RELOC("... ok\n"));
+
+		if (_prom->disp_node == 0)
+			_prom->disp_node = (ihandle)(unsigned long)node;
+
+		/* Setup a useable color table when the appropriate
+		 * method is available. Should update this to set-colors */
+		for (i = 0; i < 32; i++)
+			if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
+					   RELOC(default_colors)[i*3+1],
+					   RELOC(default_colors)[i*3+2]) != 0)
+				break;
+
+#ifdef CONFIG_FB
+		for (i = 0; i < LINUX_LOGO_COLORS; i++)
+			if (prom_set_color(ih, i + 32,
+					   RELOC(linux_logo_red)[i],
+					   RELOC(linux_logo_green)[i],
+					   RELOC(linux_logo_blue)[i]) != 0)
+				break;
+#endif /* CONFIG_FB */
+
+		/*
+		 * If this display is the device that OF is using for stdout,
+		 * move it to the front of the list.
+		 */
+		mem += strlen(path) + 1;
+		i = RELOC(prom_num_displays)++;
+		if (RELOC(of_stdout_device) != 0 && i > 0
+		    && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {
+			for (; i > 0; --i)
+				RELOC(prom_display_paths[i]) = RELOC(prom_display_paths[i-1]);
+		}
+		RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
+		if (RELOC(prom_num_displays) >= FB_MAX)
+			break;
+	}
+	return DOUBLEWORD_ALIGN(mem);
+}
+
+void
+virt_irq_init(void)
+{
+	int i;
+	for (i = 0; i < NR_IRQS; i++)
+		virt_irq_to_real_map[i] = UNDEFINED_IRQ;
+	for (i = 0; i < NR_HW_IRQS; i++)
+		real_irq_to_virt_map[i] = UNDEFINED_IRQ;
+}
+
+/* Create a mapping for a real_irq if it doesn't already exist.
+ * Return the virtual irq as a convenience.
+ */
+unsigned long
+virt_irq_create_mapping(unsigned long real_irq)
+{
+	unsigned long virq;
+	if (naca->interrupt_controller == IC_OPEN_PIC)
+		return real_irq;	/* no mapping for openpic (for now) */
+	virq = real_irq_to_virt(real_irq);
+	if (virq == UNDEFINED_IRQ) {
+		/* Assign a virtual IRQ number */
+		if (real_irq < NR_IRQS && virt_irq_to_real(real_irq) == UNDEFINED_IRQ) {
+			/* A 1-1 mapping will work. */
+			virq = real_irq;
+		} else {
+			while (last_virt_irq < NR_IRQS &&
+			       virt_irq_to_real(++last_virt_irq) != UNDEFINED_IRQ)
+				/* skip irq's in use */;
+			if (last_virt_irq >= NR_IRQS)
+				panic("Too many IRQs are required on this system.  NR_IRQS=%d\n", NR_IRQS);
+			virq = last_virt_irq;
+		}
+		virt_irq_to_real_map[virq] = real_irq;
+		real_irq_to_virt_map[real_irq] = virq;
+	}
+	return virq;
+}
+
+
+static int __init
+prom_next_node(phandle *nodep)
+{
+	phandle node;
+	unsigned long offset = reloc_offset();
+
+	if ((node = *nodep) != 0
+	    && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0)
+		return 1;
+	if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
+		return 1;
+	for (;;) {
+		if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0)
+			return 0;
+		if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
+			return 1;
+	}
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+static unsigned long __init
+copy_device_tree(unsigned long mem_start)
+{
+	phandle root;
+	unsigned long new_start;
+	struct device_node **allnextp;
+	unsigned long offset = reloc_offset();
+	unsigned long mem_end = mem_start + (8<<20);
+
+	root = call_prom(RELOC("peer"), 1, 1, (phandle)0);
+	if (root == (phandle)0) {
+		prom_print(RELOC("couldn't get device tree root\n"));
+		prom_exit();
+	}
+	allnextp = &RELOC(allnodes);
+	mem_start = DOUBLEWORD_ALIGN(mem_start);
+	new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
+	*allnextp = 0;
+	return new_start;
+}
+
+__init
+static unsigned long
+inspect_node(phandle node, struct device_node *dad,
+	     unsigned long mem_start, unsigned long mem_end,
+	     struct device_node ***allnextpp)
+{
+	int l;
+	phandle child;
+	struct device_node *np;
+	struct property *pp, **prev_propp;
+	char *prev_name, *namep;
+	unsigned char *valp;
+	unsigned long offset = reloc_offset();
+
+	np = (struct device_node *) mem_start;
+	mem_start += sizeof(struct device_node);
+	memset(np, 0, sizeof(*np));
+	np->node = node;
+	**allnextpp = PTRUNRELOC(np);
+	*allnextpp = &np->allnext;
+	if (dad != 0) {
+		np->parent = PTRUNRELOC(dad);
+		/* we temporarily use the `next' field as `last_child'. */
+		if (dad->next == 0)
+			dad->child = PTRUNRELOC(np);
+		else
+			dad->next->sibling = PTRUNRELOC(np);
+		dad->next = np;
+	}
+
+	/* get and store all properties */
+	prev_propp = &np->properties;
+	prev_name = RELOC("");
+	for (;;) {
+		pp = (struct property *) mem_start;
+		namep = (char *) (pp + 1);
+		pp->name = PTRUNRELOC(namep);
+		if ((long) call_prom(RELOC("nextprop"), 3, 1, node, prev_name,
+				    namep) <= 0)
+			break;
+		mem_start = DOUBLEWORD_ALIGN((unsigned long)namep + strlen(namep) + 1);
+		prev_name = namep;
+		valp = (unsigned char *) mem_start;
+		pp->value = PTRUNRELOC(valp);
+		pp->length = (int)(long)
+			call_prom(RELOC("getprop"), 4, 1, node, namep,
+				  valp, mem_end - mem_start);
+		if (pp->length < 0)
+			continue;
+		mem_start = DOUBLEWORD_ALIGN(mem_start + pp->length);
+		*prev_propp = PTRUNRELOC(pp);
+		prev_propp = &pp->next;
+	}
+	*prev_propp = 0;
+
+	/* get the node's full name */
+	l = (long) call_prom(RELOC("package-to-path"), 3, 1, node,
+			    (char *) mem_start, mem_end - mem_start);
+	if (l >= 0) {
+		np->full_name = PTRUNRELOC((char *) mem_start);
+		*(char *)(mem_start + l) = 0;
+		mem_start = DOUBLEWORD_ALIGN(mem_start + l + 1);
+	}
+
+	/* do all our children */
+	child = call_prom(RELOC("child"), 1, 1, node);
+	while (child != (phandle)0) {
+		mem_start = inspect_node(child, np, mem_start, mem_end,
+					 allnextpp);
+		child = call_prom(RELOC("peer"), 1, 1, child);
+	}
+
+	return mem_start;
+}
+
+/*
+ * finish_device_tree is called once things are running normally
+ * (i.e. with text and data mapped to the address they were linked at).
+ * It traverses the device tree and fills in the name, type,
+ * {n_}addrs and {n_}intrs fields of each node.
+ */
+void __init
+finish_device_tree(void)
+{
+	unsigned long mem = klimit;
+
+	virt_irq_init();
+
+	mem = finish_node(allnodes, mem, NULL, 0, 0);
+	dev_tree_size = mem - (unsigned long) allnodes;
+
+	mem = _ALIGN(mem, PAGE_SIZE);
+	lmb_reserve(__pa(klimit), mem-klimit);
+
+	klimit = mem;
+
+	rtas.dev = find_devices("rtas");
+}
+
+static unsigned long __init
+finish_node(struct device_node *np, unsigned long mem_start,
+	    interpret_func *ifunc, int naddrc, int nsizec)
+{
+	struct device_node *child;
+	int *ip;
+
+	np->name = get_property(np, "name", 0);
+	np->type = get_property(np, "device_type", 0);
+
+	/* get the device addresses and interrupts */
+	if (ifunc != NULL) {
+	  mem_start = ifunc(np, mem_start, naddrc, nsizec);
+	}
+	mem_start = finish_node_interrupts(np, mem_start);
+
+	/* Look for #address-cells and #size-cells properties. */
+	ip = (int *) get_property(np, "#address-cells", 0);
+	if (ip != NULL)
+		naddrc = *ip;
+	ip = (int *) get_property(np, "#size-cells", 0);
+	if (ip != NULL)
+		nsizec = *ip;
+
+	/* the f50 sets the name to 'display' and 'compatible' to what we
+	 * expect for the name -- Cort
+	 */
+	ifunc = NULL;
+	if (!strcmp(np->name, "display"))
+		np->name = get_property(np, "compatible", 0);
+
+	if (!strcmp(np->name, "device-tree") || np->parent == NULL)
+		ifunc = interpret_root_props;
+	else if (np->type == 0)
+		ifunc = NULL;
+	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
+		ifunc = interpret_pci_props;
+	else if (!strcmp(np->type, "isa"))
+		ifunc = interpret_isa_props;
+
+	for (child = np->child; child != NULL; child = child->sibling)
+		mem_start = finish_node(child, mem_start, ifunc,
+					naddrc, nsizec);
+
+	return mem_start;
+}
+
+/* This routine walks the interrupt tree for a given device node and gather 
+ * all necessary informations according to the draft interrupt mapping
+ * for CHRP. The current version was only tested on Apple "Core99" machines
+ * and may not handle cascaded controllers correctly.
+ */
+__init
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+	/* Finish this node */
+	unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
+	phandle *parent, map_parent;
+	struct device_node *node, *parent_node;
+	int l, isize, ipsize, asize, map_size, regpsize;
+
+	/* Currently, we don't look at all nodes with no "interrupts" property */
+
+	interrupts = (unsigned int *)get_property(np, "interrupts", &l);
+	if (interrupts == NULL)
+		return mem_start;
+	ipsize = l>>2;
+
+	reg = (unsigned int *)get_property(np, "reg", &l);
+	regpsize = l>>2;
+
+	/* We assume default interrupt cell size is 1 (bugus ?) */
+	isize = 1;
+	node = np;
+	
+	do {
+	    /* We adjust the cell size if the current parent contains an #interrupt-cells
+	     * property */
+	    isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
+	    if (isizep)
+	    	isize = *isizep;
+
+	    /* We don't do interrupt cascade (ISA) for now, we stop on the first 
+	     * controller found
+	     */
+	    if (get_property(node, "interrupt-controller", &l)) {
+	    	int i,j;
+
+	    	np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = ipsize / isize;
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		for (i = 0; i < np->n_intrs; ++i) {
+		    np->intrs[i].line = openpic_to_irq(virt_irq_create_mapping(*interrupts++));
+		    np->intrs[i].sense = 1;
+		    if (isize > 1)
+		        np->intrs[i].sense = *interrupts++;
+		    for (j=2; j<isize; j++)
+		    	interrupts++;
+		}
+		return mem_start;
+	    }
+	    /* We lookup for an interrupt-map. This code can only handle one interrupt
+	     * per device in the map. We also don't handle #address-cells in the parent
+	     * I skip the pci node itself here, may not be necessary but I don't like it's
+	     * reg property.
+	     */
+	    if (np != node)
+	        map = (unsigned int *)get_property(node, "interrupt-map", &l);
+	     else
+	     	map = NULL;
+	    if (map && l) {
+	    	int i, found, temp_isize, temp_asize;
+	        map_size = l>>2;
+	        map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
+	        asizep = (unsigned int *)get_property(node, "#address-cells", &l);
+	        if (asizep && l == sizeof(unsigned int))
+	            asize = *asizep;
+	        else
+	            asize = 0;
+	        found = 0;
+	        while (map_size>0 && !found) {
+	            found = 1;
+	            for (i=0; i<asize; i++) {
+	            	unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
+	            	if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
+	           	    found = 0;
+	           	map++;
+	           	map_size--;
+	            }
+	            for (i=0; i<isize; i++) {
+	            	unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
+	            	if ((mask & *map) != (mask & interrupts[i]))
+	            	    found = 0;
+	            	map++;
+	            	map_size--;
+	            }
+	            map_parent = *((phandle *)map);
+	            map+=1; map_size-=1;
+	            parent_node = find_phandle(map_parent);
+	            temp_isize = isize;
+		    temp_asize = 0;
+	            if (parent_node) {
+			isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
+	    		if (isizep)
+	    		    temp_isize = *isizep;
+			asizep = (unsigned int *)get_property(parent_node, "#address-cells", &l);
+			if (asizep && l == sizeof(unsigned int))
+				temp_asize = *asizep;
+	            }
+	            if (!found) {
+			map += temp_isize + temp_asize;
+			map_size -= temp_isize + temp_asize;
+	            }
+	        }
+	        if (found) {
+		    /* Mapped to a new parent.  Use the reg and interrupts specified in
+		     * the map as the new search parameters.  Then search from the parent.
+		     */
+	            node = parent_node;
+		    reg = map;
+		    regpsize = temp_asize;
+		    interrupts = map + temp_asize;
+		    ipsize = temp_isize;
+		    continue;
+	        }
+	    }
+	    /* We look for an explicit interrupt-parent.
+	     */
+	    parent = (phandle *)get_property(node, "interrupt-parent", &l);
+	    if (parent && (l == sizeof(phandle)) &&
+	    	(parent_node = find_phandle(*parent))) {
+	    	node = parent_node;
+	    	continue;
+	    }
+	    /* Default, get real parent */
+	    node = node->parent;
+	} while (node);
+
+	return mem_start;
+}
+
+int
+prom_n_addr_cells(struct device_node* np)
+{
+	int* ip;
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = (int *) get_property(np, "#address-cells", 0);
+		if (ip != NULL)
+			return *ip;
+	} while (np->parent);
+	/* No #address-cells property for the root node, default to 1 */
+	return 1;
+}
+
+int
+prom_n_size_cells(struct device_node* np)
+{
+	int* ip;
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = (int *) get_property(np, "#size-cells", 0);
+		if (ip != NULL)
+			return *ip;
+	} while (np->parent);
+	/* No #size-cells property for the root node, default to 1 */
+	return 1;
+}
+
+static unsigned long __init
+interpret_pci_props(struct device_node *np, unsigned long mem_start,
+		    int naddrc, int nsizec)
+{
+	struct address_range *adr;
+	struct pci_reg_property *pci_addrs;
+	int i, l;
+
+	pci_addrs = (struct pci_reg_property *)
+		get_property(np, "assigned-addresses", &l);
+	if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+			adr[i].space = pci_addrs[i].addr.a_hi;
+			adr[i].address = pci_addrs[i].addr.a_lo;
+			adr[i].size = pci_addrs[i].size_lo;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_isa_props(struct device_node *np, unsigned long mem_start,
+		    int naddrc, int nsizec)
+{
+	struct isa_reg_property *rp;
+	struct address_range *adr;
+	int i, l;
+
+	rp = (struct isa_reg_property *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct reg_property)) >= 0) {
+			adr[i].space = rp[i].space;
+			adr[i].address = rp[i].address
+				+ (adr[i].space? 0: _ISA_MEM_BASE);
+			adr[i].size = rp[i].size;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_root_props(struct device_node *np, unsigned long mem_start,
+		     int naddrc, int nsizec)
+{
+	struct address_range *adr;
+	int i, l;
+	unsigned int *rp;
+	int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
+
+	rp = (unsigned int *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= rpsize) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= rpsize) >= 0) {
+			adr[i].space = 0;
+			adr[i].address = rp[naddrc - 1];
+			adr[i].size = rp[naddrc + nsizec - 1];
+			++i;
+			rp += naddrc + nsizec;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	return mem_start;
+}
+
+/*
+ * Work out the sense (active-low level / active-high edge)
+ * of each interrupt from the device tree.
+ */
+void __init
+prom_get_irq_senses(unsigned char *senses, int off, int max)
+{
+	struct device_node *np;
+	int i, j;
+
+	/* default to level-triggered */
+	memset(senses, 1, max - off);
+
+	for (np = allnodes; np != 0; np = np->allnext) {
+		for (j = 0; j < np->n_intrs; j++) {
+			i = np->intrs[j].line;
+			if (i >= off && i < max)
+				senses[i-off] = np->intrs[j].sense;
+		}
+	}
+}
+
+/*
+ * Construct and return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Construct and return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Returns all nodes linked together
+ */
+struct device_node * __openfirmware
+find_all_nodes(void)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		*prevp = np;
+		prevp = &np->next;
+	}
+	*prevp = 0;
+	return head;
+}
+
+/* Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int
+device_is_compatible(struct device_node *device, const char *compat)
+{
+	const char* cp;
+	int cplen, l;
+
+	cp = (char *) get_property(device, "compatible", &cplen);
+	if (cp == NULL)
+		return 0;
+	while (cplen > 0) {
+		if (strncasecmp(cp, compat, strlen(compat)) == 0)
+			return 1;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+int
+machine_is_compatible(const char *compat)
+{
+	struct device_node *root;
+	
+	root = find_path_device("/");
+	if (root == 0)
+		return 0;
+	return device_is_compatible(root, compat);
+}
+
+/*
+ * Construct and return a list of the device_nodes with a given type
+ * and compatible property.
+ */
+struct device_node *
+find_compatible_devices(const char *type, const char *compat)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (type != NULL
+		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
+			continue;
+		if (device_is_compatible(np, compat)) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+	struct device_node *np;
+
+	for (np = allnodes; np != 0; np = np->allnext)
+		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+			return np;
+	return NULL;
+}
+
+/*
+ * Find the device_node with a given phandle.
+ */
+static struct device_node * __init
+find_phandle(phandle ph)
+{
+	struct device_node *np;
+
+	for (np = allnodes; np != 0; np = np->allnext)
+		if (np->node == ph)
+			return np;
+	return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+	struct property *pp;
+
+	for (pp = np->properties; pp != 0; pp = pp->next)
+		if (strcmp(pp->name, name) == 0) {
+			if (lenp != 0)
+				*lenp = pp->length;
+			return pp->value;
+		}
+	return 0;
+}
+
+/*
+ * Add a property to a node
+ */
+void __openfirmware
+prom_add_property(struct device_node* np, struct property* prop)
+{
+	struct property **next = &np->properties;
+
+	prop->next = NULL;	
+	while (*next)
+		next = &(*next)->next;
+	*next = prop;
+}
+
+#if 0
+void __openfirmware
+print_properties(struct device_node *np)
+{
+	struct property *pp;
+	char *cp;
+	int i, n;
+
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		printk(KERN_INFO "%s", pp->name);
+		for (i = strlen(pp->name); i < 16; ++i)
+			printk(" ");
+		cp = (char *) pp->value;
+		for (i = pp->length; i > 0; --i, ++cp)
+			if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+			    || (i == 1 && *cp != 0))
+				break;
+		if (i == 0 && pp->length > 1) {
+			/* looks like a string */
+			printk(" %s\n", (char *) pp->value);
+		} else {
+			/* dump it in hex */
+			n = pp->length;
+			if (n > 64)
+				n = 64;
+			if (pp->length % 4 == 0) {
+				unsigned int *p = (unsigned int *) pp->value;
+
+				n /= 4;
+				for (i = 0; i < n; ++i) {
+					if (i != 0 && (i % 4) == 0)
+						printk("\n                ");
+					printk(" %08x", *p++);
+				}
+			} else {
+				unsigned char *bp = pp->value;
+
+				for (i = 0; i < n; ++i) {
+					if (i != 0 && (i % 16) == 0)
+						printk("\n                ");
+					printk(" %02x", *bp++);
+				}
+			}
+			printk("\n");
+			if (pp->length > 64)
+				printk("                 ... (length = %d)\n",
+				       pp->length);
+		}
+	}
+}
+#endif
+
+
+void __init
+abort()
+{
+#ifdef CONFIG_XMON
+	xmon(NULL);
+#endif
+	for (;;)
+		prom_exit();
+}
+
+
+/* Verify bi_recs are good */
+static struct bi_record *
+prom_bi_rec_verify(struct bi_record *bi_recs)
+{
+	struct bi_record *first, *last;
+
+	if ( bi_recs == NULL || bi_recs->tag != BI_FIRST )
+		return NULL;
+
+	last = (struct bi_record *)bi_recs->data[0];
+	if ( last == NULL || last->tag != BI_LAST )
+		return NULL;
+
+	first = (struct bi_record *)last->data[0];
+	if ( first == NULL || first != bi_recs )
+		return NULL;
+
+	return bi_recs;
+}
+
+static unsigned long
+prom_bi_rec_reserve(unsigned long mem)
+{
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+	struct bi_record *rec;
+
+	if ( _prom->bi_recs != NULL) {
+
+		for ( rec=_prom->bi_recs;
+		      rec->tag != BI_LAST;
+		      rec=bi_rec_next(rec) ) {
+			switch (rec->tag) {
+#ifdef CONFIG_BLK_DEV_INITRD
+			case BI_INITRD:
+				lmb_reserve(rec->data[0], rec->data[1]);
+				break;
+#endif /* CONFIG_BLK_DEV_INITRD */
+			}
+		}
+		/* The next use of this field will be after relocation
+	 	 * is enabled, so convert this physical address into a
+	 	 * virtual address.
+	 	 */
+		_prom->bi_recs = PTRUNRELOC(_prom->bi_recs);
+	}
+
+	return mem;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ptrace.c linux-2.4.19-pre5/arch/ppc64/kernel/ptrace.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ptrace.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ptrace.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,341 @@
+/*
+ *  linux/arch/ppc/kernel/ptrace.c
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/m68k/kernel/ptrace.c"
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@hq.fsmlabs.com)
+ * and Paul Mackerras (paulus@linuxcare.com.au).
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+#define MSR_DEBUGCHANGE	(MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline unsigned long get_reg(struct task_struct *task, int regno)
+{
+	if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
+		return ((unsigned long *)task->thread.regs)[regno];
+	return (0);
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+			  unsigned long data)
+{
+	if (regno < PT_SOFTE) {
+		if (regno == PT_MSR)
+			data = (data & MSR_DEBUGCHANGE)
+				| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
+		((unsigned long *)task->thread.regs)[regno] = data;
+		return 0;
+	}
+	return -EIO;
+}
+
+static inline void
+set_single_step(struct task_struct *task)
+{
+	struct pt_regs *regs = task->thread.regs;
+	if (regs != NULL)
+		regs->msr |= MSR_SE;
+}
+
+static inline void
+clear_single_step(struct task_struct *task)
+{
+	struct pt_regs *regs = task->thread.regs;
+	if (regs != NULL)
+		regs->msr &= ~MSR_SE;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	/* make sure the single step bit is not set. */
+	clear_single_step(child);
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret = -EPERM;
+
+	lock_kernel();
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+	ret = -ESRCH;
+	if (!(child->ptrace & PT_PTRACED))
+		goto out_tsk;
+	if (child->state != TASK_STOPPED) {
+		if (request != PTRACE_KILL)
+			goto out_tsk;
+	}
+	if (child->p_pptr != current)
+		goto out_tsk;
+
+	switch (request) {
+	/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		unsigned long index, tmp;
+
+		ret = -EIO;
+		/* convert to index and check */
+		index = (unsigned long) addr >> 3;
+		if ((addr & 7) || index > PT_FPSCR)
+			break;
+
+		if (index < PT_FPR0) {
+			tmp = get_reg(child, (int) index);
+		} else {
+			if (child->thread.regs->msr & MSR_FP)
+				giveup_fpu(child);
+			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
+		}
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* If I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+			break;
+		ret = -EIO;
+		break;
+
+	/* write the word at location addr in the USER area */
+	case PTRACE_POKEUSR: {
+		unsigned long index;
+
+		ret = -EIO;
+		/* convert to index and check */
+		index = (unsigned long) addr >> 3;
+		if ((addr & 7) || index > PT_FPSCR)
+			break;
+
+		if (index == PT_ORIG_R3)
+			break;
+		if (index < PT_FPR0) {
+			ret = put_reg(child, index, data);
+		} else {
+			if (child->thread.regs->msr & MSR_FP)
+				giveup_fpu(child);
+			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
+			ret = 0;
+		}
+		break;
+	}
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			child->ptrace |= PT_TRACESYS;
+		else
+			child->ptrace &= ~PT_TRACESYS;
+		child->exit_code = data;
+		/* make sure the single step bit is not set. */
+		clear_single_step(child);
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL: {
+		ret = 0;
+		if (child->state == TASK_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		/* make sure the single step bit is not set. */
+		clear_single_step(child);
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		child->ptrace &= ~PT_TRACESYS;
+		set_single_step(child);
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_DETACH:
+		ret = ptrace_detach(child, data);
+		break;
+
+	case PPC_PTRACE_GETREGS:
+	{ /* Get GPRs 0 - 31. */
+		u64 tmp;
+		u64 cntr;
+		ret = 0; 
+		for (cntr=0; cntr<32 && ret==0; ++cntr)
+		{
+			tmp = ((u64*)child->thread.regs)[cntr];
+			ret = put_user(tmp, (u64*)(data+cntr));
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETREGS:
+	{ /* Set GPRs 0 - 31. */
+		u64 cntr;
+		ret = 0; 
+		for (cntr=0; cntr<32 && ret==0; ++cntr)
+		{
+			ret = put_reg(child, cntr, *(u64*)(data+cntr));
+		}
+		break;
+	}
+
+	case PPC_PTRACE_GETFPREGS:
+	{ /* Get FPRs 0 - 31. */
+		u64 tmp;
+		u64 cntr;
+		ret = -EIO;
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+		ret = 0; 
+		for (cntr=0; cntr<32 && ret==0; ++cntr)
+		{
+			tmp = ((u64*)child->thread.fpr)[cntr];
+			ret = put_user(tmp, (u64*)(data+cntr));
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETFPREGS:
+	{ /* Get FPRs 0 - 31. */
+		u64 cntr;
+		ret = -EIO;
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+		for (cntr=0; cntr<32; ++cntr)
+		{
+			((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr);
+		}
+		ret = 0; 
+		break;
+	}
+
+	default:
+		ret = -EIO;
+		break;
+	}
+out_tsk:
+	free_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+void syscall_trace(void)
+{
+  if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
+			!= (PT_PTRACED|PT_TRACESYS))
+		return;
+	current->exit_code = SIGTRAP;
+	current->state = TASK_STOPPED;
+	notify_parent(current, SIGCHLD);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ptrace32.c linux-2.4.19-pre5/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ptrace32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ptrace32.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,401 @@
+/*
+ *  linux/arch/ppc/kernel/ptrace32.c
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/m68k/kernel/ptrace.c"
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@hq.fsmlabs.com)
+ * and Paul Mackerras (paulus@linuxcare.com.au).
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+#define MSR_DEBUGCHANGE	(MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline unsigned long get_reg(struct task_struct *task, int regno)
+{
+	if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
+		return ((unsigned long *)task->thread.regs)[regno];
+	return (0);
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ * (Put DATA into task TASK's register REGNO.)
+ */
+static inline int put_reg(struct task_struct *task, int regno, unsigned long data)
+{
+	if (regno < PT_SOFTE) 
+  {
+		if (regno == PT_MSR)
+			data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
+		((unsigned long *)task->thread.regs)[regno] = data;
+		return 0;
+	}
+	return -EIO;
+}
+
+static inline void
+set_single_step(struct task_struct *task)
+{
+	struct pt_regs *regs = task->thread.regs;
+	if (regs != NULL)
+		regs->msr |= MSR_SE;
+}
+
+static inline void
+clear_single_step(struct task_struct *task)
+{
+	struct pt_regs *regs = task->thread.regs;
+	if (regs != NULL)
+		regs->msr &= ~MSR_SE;
+}
+
+int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
+{
+	struct task_struct *child;
+	int ret  = -EPERM;
+  
+	lock_kernel();
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+	ret = -ESRCH;
+	if (!(child->ptrace & PT_PTRACED))
+		goto out_tsk;
+	if (child->state != TASK_STOPPED) {
+		if (request != PTRACE_KILL)
+			goto out_tsk;
+	}
+	if (child->p_pptr != current)
+		goto out_tsk;
+
+	switch (request)
+	{
+	/* Read word at location ADDR */
+	/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: 
+	{
+		unsigned int  tmp_mem_value;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp_mem_value, sizeof(tmp_mem_value), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp_mem_value))
+			break;
+		ret = put_user(tmp_mem_value, (u32*)data);  // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
+		break;
+	}
+
+	/* Read 4 bytes of the other process' storage */
+	/*  data is a pointer specifying where the user wants the 4 bytes copied into */
+	/*  addr is a pointer in the user's storage that contains an 8 byte address in the other process of the 4 bytes that is to be read */
+	/* (this is run in a 32-bit process looking at a 64-bit process) */
+	/* when I and D space are separate, these will need to be fixed. */
+	case PPC_PTRACE_PEEKTEXT_3264:
+	case PPC_PTRACE_PEEKDATA_3264: 
+	{
+		u32  tmp_mem_value;
+		int  copied;
+		u32* addrOthers;
+
+		ret = -EIO;
+
+		/* Get the addr in the other process that we want to read */
+		if (get_user(addrOthers,(u32**)addr) != 0)
+			break;
+
+		copied = access_process_vm(child, (u64)addrOthers, &tmp_mem_value, sizeof(tmp_mem_value), 0);
+		if (copied != sizeof(tmp_mem_value))
+			break;
+		ret = put_user(tmp_mem_value, (u32*)data);  // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
+		break;
+	}
+
+	/* Read a register (specified by ADDR) out of the "user area" */
+	case PTRACE_PEEKUSR: {
+		int index;
+		unsigned int reg32bits;
+		unsigned long tmp_reg_value;
+
+		ret = -EIO;
+		/* convert to index and check */
+		index = (unsigned long) addr >> 2;
+		if ((addr & 3) || index > PT_FPSCR32)
+			break;
+
+		if (index < PT_FPR0) {
+			tmp_reg_value = get_reg(child,  index);
+		} else {
+			if (child->thread.regs->msr & MSR_FP)
+				giveup_fpu(child);
+			/* the user space code considers the floating point to be 
+			 *   an array of unsigned int (32 bits) - the index passed 
+			 *   in is based on this assumption.
+			 */
+			tmp_reg_value = ((unsigned int *)child->thread.fpr)[index - PT_FPR0];
+		}
+		reg32bits = tmp_reg_value;
+		ret = put_user(reg32bits, (u32*)data);  // copy 4 bytes of data into the user location specified by the 8 byte pointer in "data".
+		break;
+	}
+  
+	/* Read 4 bytes out of the other process' pt_regs area */
+	/*  data is a pointer specifying where the user wants the 4 bytes copied into */
+	/*  addr is the offset into the other process' pt_regs structure that is to be read */
+	/* (this is run in a 32-bit process looking at a 64-bit process) */
+	case PPC_PTRACE_PEEKUSR_3264:
+	{
+		u32 index;
+		u32 reg32bits;
+		u64 tmp_reg_value;
+		u32 numReg;
+		u32 part;
+
+		ret = -EIO;
+		/* Determine which register the user wants */
+		index = (u64)addr >> 2;  /* Divide addr by 4 */
+		numReg = index / 2;
+		/* Determine which part of the register the user wants */
+		if (index % 2)
+			part = 1;  /* want the 2nd half of the register (right-most). */
+		else
+			part = 0;  /* want the 1st half of the register (left-most). */
+
+		/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
+		if ((addr & 3) || numReg > PT_FPSCR)
+			break;
+
+		if (numReg >= PT_FPR0)
+		{
+			if (child->thread.regs->msr & MSR_FP)
+				giveup_fpu(child);
+		}
+		tmp_reg_value = get_reg(child, numReg);
+		reg32bits = ((u32*)&tmp_reg_value)[part];
+		ret = put_user(reg32bits, (u32*)data);  /* copy 4 bytes of data into the user location specified by the 8 byte pointer in "data". */
+		break;
+	}
+
+	/* Write the word at location ADDR */
+	/* If I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA: {
+		unsigned int tmp_value_to_write;
+		tmp_value_to_write =  data;
+		ret = 0;
+		if (access_process_vm(child, addr, &tmp_value_to_write, sizeof(tmp_value_to_write), 1) == sizeof(tmp_value_to_write))
+			break;
+		ret = -EIO;
+		break;
+	}
+
+	/* Write 4 bytes into the other process' storage */
+	/*  data is the 4 bytes that the user wants written */
+	/*  addr is a pointer in the user's storage that contains an 8 byte address in the other process where the 4 bytes that is to be written */
+	/* (this is run in a 32-bit process looking at a 64-bit process) */
+	/* when I and D space are separate, these will need to be fixed. */
+	case PPC_PTRACE_POKETEXT_3264:
+	case PPC_PTRACE_POKEDATA_3264:
+	{
+		u32  tmp_value_to_write = data;
+		u32* addrOthers;
+		int  bytesWritten;
+
+		/* Get the addr in the other process that we want to write into */
+		ret = -EIO;
+		if (get_user(addrOthers,(u32**)addr) != 0)
+			break;
+
+		ret = 0;
+		bytesWritten = access_process_vm(child, (u64)addrOthers, &tmp_value_to_write, sizeof(tmp_value_to_write), 1);
+		if (bytesWritten == sizeof(tmp_value_to_write))
+			break;
+		ret = -EIO;
+		break;
+	}
+
+	/* Write DATA into location ADDR within the USER area  */
+	case PTRACE_POKEUSR: {
+		unsigned long index;
+
+		ret = -EIO;
+
+		/* convert to index and check */
+		index = (unsigned long) addr >> 2;
+		if ((addr & 3) || index > PT_FPSCR32)
+			break;
+
+		if (index == PT_ORIG_R3)
+			break;
+
+
+		if (index < PT_FPR0) {
+			ret = put_reg(child, index, data);
+		} else {
+			if (child->thread.regs->msr & MSR_FP)
+				giveup_fpu(child);
+      /* the user space code considers the floating point to be 
+       *   an array of unsigned int (32 bits) - the index passed 
+       *   in is based on this assumption.
+       */
+
+			((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data;
+			ret = 0;
+		}
+		break;
+	}
+
+	/* Write 4 bytes into the other process' pt_regs area */
+	/*  data is the 4 bytes that the user wants written */
+	/*  addr is the offset into the other process' pt_regs structure that is to be written into */
+	/* (this is run in a 32-bit process looking at a 64-bit process) */
+	case PPC_PTRACE_POKEUSR_3264:
+	{
+		u32 index;
+		u32 numReg;
+
+		ret = -EIO;
+
+		/* Determine which register the user wants */
+		index = (u64)addr >> 2;  /* Divide addr by 4 */
+		numReg = index / 2;
+
+		/* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
+		if ((addr & 3) || numReg > PT_FPSCR)
+			break;
+		/* Insure it is a register we let them change */
+		if ((numReg == PT_ORIG_R3) || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
+			break;
+
+		if (numReg >= PT_FPR0)
+		{
+			if (child->thread.regs->msr & MSR_FP)
+				giveup_fpu(child);
+		}
+
+		if (numReg == PT_MSR)
+			data = (data & MSR_DEBUGCHANGE) | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
+
+		((u32*)child->thread.regs)[index] = data;
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			child->ptrace |= PT_TRACESYS;
+		else
+			child->ptrace &= ~PT_TRACESYS;
+		child->exit_code = data;
+		/* make sure the single step bit is not set. */
+		clear_single_step(child);
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	/*
+	 * make the child exit.  Best I can do is send it a sigkill. 
+	 * perhaps it should be put in the status that it wants to 
+	 * exit.
+	 */
+	case PTRACE_KILL: {
+		ret = 0;
+		if (child->state == TASK_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		/* make sure the single step bit is not set. */
+		clear_single_step(child);
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		child->ptrace &= ~PT_TRACESYS;
+		set_single_step(child);
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_DETACH:
+		ret = ptrace_detach(child, data);
+		break;
+
+	default:
+		ret = -EIO;
+		break;
+	}
+out_tsk:
+	free_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/ras.c linux-2.4.19-pre5/arch/ppc64/kernel/ras.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/ras.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/ras.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,165 @@
+
+/*
+ * ras.c
+ * Copyright (C) 2001 Dave Engebretsen IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Change Activity:
+ * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support.
+ * End Change Activity 
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/threads.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <linux/random.h>
+#include <linux/sysrq.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/cache.h>
+#include <asm/prom.h>
+#include <asm/ptrace.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/machdep.h>
+#include <asm/rtas.h>
+#include <asm/ppcdebug.h>
+
+static void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+void init_ras_IRQ(void);
+
+/* #define DEBUG */
+
+/*
+ * Initialize handlers for the set of interrupts caused by hardware errors
+ * and power system events.
+ */
+void init_ras_IRQ(void) {
+	struct device_node *np;
+	unsigned int *ireg, len, i;
+
+	if((np = find_path_device("/event-sources/internal-errors")) &&
+	   (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", 
+						&len))) {
+		for(i=0; i<(len / sizeof(*ireg)); i++) {
+			request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, 
+				    &ras_error_interrupt, 0, 
+				    "RAS_ERROR", NULL);
+			ireg++;
+		}
+	}
+
+	if((np = find_path_device("/event-sources/epow-events")) &&
+	   (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", 
+						&len))) {
+		for(i=0; i<(len / sizeof(*ireg)); i++) {
+			request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, 
+				    &ras_epow_interrupt, 0, 
+				    "RAS_EPOW", NULL);
+			ireg++;
+		}
+	}
+}
+
+/*
+ * Handle power subsystem events (EPOW).
+ *
+ * Presently we just log the event has occured.  This should be fixed
+ * to examine the type of power failure and take appropriate action where
+ * the time horizon permits something useful to be done.
+ */
+static void
+ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct rtas_error_log log_entry;
+	unsigned int size = sizeof(log_entry);
+	long status = 0xdeadbeef;
+
+	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
+			   0x500, irq, 
+			   EPOW_WARNING | POWERMGM_EVENTS, 
+			   1,  /* Time Critical */
+			   __pa(&log_entry), size);
+
+	udbg_printf("EPOW <0x%lx 0x%lx>\n", 
+		    *((unsigned long *)&log_entry), status); 
+	printk(KERN_WARNING 
+	       "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status);
+}
+
+/*
+ * Handle hardware error interrupts.
+ *
+ * RTAS check-exception is called to collect data on the exception.  If
+ * the error is deemed recoverable, we log a warning and return.
+ * For nonrecoverable errors, an error is logged and we stop all processing
+ * as quickly as possible in order to prevent propagation of the failure.
+ */
+static void
+ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct rtas_error_log log_entry;
+	unsigned int size = sizeof(log_entry);
+	long status = 0xdeadbeef;
+
+	status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 
+			   0x500, irq, 
+			   INTERNAL_ERROR, 
+			   1, /* Time Critical */
+			   __pa(&log_entry), size);
+
+	if((status != 1) && 
+	   (log_entry.severity >= SEVERITY_ERROR_SYNC)) {
+		udbg_printf("HW Error <0x%lx 0x%lx>\n",
+			    *((unsigned long *)&log_entry), status);
+		printk(KERN_EMERG 
+		       "Error: Fatal hardware error <0x%lx 0x%lx>\n",
+		       *((unsigned long *)&log_entry), status);
+
+#ifndef DEBUG
+		/* Don't actually power off when debugging so we can test
+		 * without actually failing while injecting errors.
+		 */
+		ppc_md.power_off();
+#endif
+	} else {
+		udbg_printf("Recoverable HW Error <0x%lx 0x%lx>\n",
+			    *((unsigned long *)&log_entry), status); 
+		printk(KERN_WARNING 
+		       "Warning: Recoverable hardware error <0x%lx 0x%lx>\n",
+		       *((unsigned long *)&log_entry), status);
+
+		return;
+	}
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/rtas-proc.c linux-2.4.19-pre5/arch/ppc64/kernel/rtas-proc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/rtas-proc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/rtas-proc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,796 @@
+/*
+ *   arch/ppc64/kernel/rtas-proc.c
+ *   Copyright (C) 2000 Tilmann Bitterberg
+ *   (tilmann@bitterberg.de)
+ *
+ *   RTAS (Runtime Abstraction Services) stuff
+ *   Intention is to provide a clean user interface
+ *   to use the RTAS.
+ *
+ *   TODO:
+ *   Split off a header file and maybe move it to a different
+ *   location. Write Documentation on what the /proc/rtas/ entries
+ *   actually do.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <linux/time.h>
+#include <linux/string.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/machdep.h> /* for ppc_md */
+#include <asm/time.h>
+
+/* Token for Sensors */
+#define KEY_SWITCH		0x0001
+#define ENCLOSURE_SWITCH	0x0002
+#define THERMAL_SENSOR		0x0003
+#define LID_STATUS		0x0004
+#define POWER_SOURCE		0x0005
+#define BATTERY_VOLTAGE		0x0006
+#define BATTERY_REMAINING	0x0007
+#define BATTERY_PERCENTAGE	0x0008
+#define EPOW_SENSOR		0x0009
+#define BATTERY_CYCLESTATE	0x000a
+#define BATTERY_CHARGING	0x000b
+
+/* IBM specific sensors */
+#define IBM_SURVEILLANCE	0x2328 /* 9000 */
+#define IBM_FANRPM		0x2329 /* 9001 */
+#define IBM_VOLTAGE		0x232a /* 9002 */
+#define IBM_DRCONNECTOR		0x232b /* 9003 */
+#define IBM_POWERSUPPLY		0x232c /* 9004 */
+#define IBM_INTQUEUE		0x232d /* 9005 */
+
+/* Status return values */
+#define SENSOR_CRITICAL_HIGH	13
+#define SENSOR_WARNING_HIGH	12
+#define SENSOR_NORMAL		11
+#define SENSOR_WARNING_LOW	10
+#define SENSOR_CRITICAL_LOW	 9
+#define SENSOR_SUCCESS		 0
+#define SENSOR_HW_ERROR		-1
+#define SENSOR_BUSY		-2
+#define SENSOR_NOT_EXIST	-3
+#define SENSOR_DR_ENTITY	-9000
+
+/* Location Codes */
+#define LOC_SCSI_DEV_ADDR	'A'
+#define LOC_SCSI_DEV_LOC	'B'
+#define LOC_CPU			'C'
+#define LOC_DISKETTE		'D'
+#define LOC_ETHERNET		'E'
+#define LOC_FAN			'F'
+#define LOC_GRAPHICS		'G'
+/* reserved / not used		'H' */
+#define LOC_IO_ADAPTER		'I'
+/* reserved / not used		'J' */
+#define LOC_KEYBOARD		'K'
+#define LOC_LCD			'L'
+#define LOC_MEMORY		'M'
+#define LOC_NV_MEMORY		'N'
+#define LOC_MOUSE		'O'
+#define LOC_PLANAR		'P'
+#define LOC_OTHER_IO		'Q'
+#define LOC_PARALLEL		'R'
+#define LOC_SERIAL		'S'
+#define LOC_DEAD_RING		'T'
+#define LOC_RACKMOUNTED		'U' /* for _u_nit is rack mounted */
+#define LOC_VOLTAGE		'V'
+#define LOC_SWITCH_ADAPTER	'W'
+#define LOC_OTHER		'X'
+#define LOC_FIRMWARE		'Y'
+#define LOC_SCSI		'Z'
+
+/* Tokens for indicators */
+#define TONE_FREQUENCY		0x0001 /* 0 - 1000 (HZ)*/
+#define TONE_VOLUME		0x0002 /* 0 - 100 (%) */
+#define SYSTEM_POWER_STATE	0x0003 
+#define WARNING_LIGHT		0x0004
+#define DISK_ACTIVITY_LIGHT	0x0005
+#define HEX_DISPLAY_UNIT	0x0006
+#define BATTERY_WARNING_TIME	0x0007
+#define CONDITION_CYCLE_REQUEST	0x0008
+#define SURVEILLANCE_INDICATOR	0x2328 /* 9000 */
+#define DR_ACTION		0x2329 /* 9001 */
+#define DR_INDICATOR		0x232a /* 9002 */
+/* 9003 - 9004: Vendor specific */
+#define GLOBAL_INTERRUPT_QUEUE	0x232d /* 9005 */
+/* 9006 - 9999: Vendor specific */
+
+/* other */
+#define MAX_SENSORS		 17  /* I only know of 17 sensors */    
+#define MAX_LINELENGTH          256
+#define SENSOR_PREFIX		"ibm,sensor-"
+#define cel_to_fahr(x)		((x*9/5)+32)
+
+
+/* Globals */
+static struct proc_dir_entry *proc_rtas;
+static struct rtas_sensors sensors;
+static struct device_node *rtas_node;
+static unsigned long power_on_time = 0; /* Save the time the user set */
+static char progress_led[MAX_LINELENGTH];
+
+static unsigned long rtas_tone_frequency = 1000;
+static unsigned long rtas_tone_volume = 0;
+
+/* ****************STRUCTS******************************************* */
+struct individual_sensor {
+	unsigned int token;
+	unsigned int quant;
+};
+
+struct rtas_sensors {
+        struct individual_sensor sensor[MAX_SENSORS];
+	unsigned int quant;
+};
+
+/* ****************************************************************** */
+/* Declarations */
+static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data);
+static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+
+static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos);
+
+struct file_operations ppc_rtas_poweron_operations = {
+	read:		ppc_rtas_poweron_read,
+	write:		ppc_rtas_poweron_write
+};
+struct file_operations ppc_rtas_progress_operations = {
+	read:		ppc_rtas_progress_read,
+	write:		ppc_rtas_progress_write
+};
+
+struct file_operations ppc_rtas_clock_operations = {
+	read:		ppc_rtas_clock_read,
+	write:		ppc_rtas_clock_write
+};
+
+struct file_operations ppc_rtas_tone_freq_operations = {
+	read:		ppc_rtas_tone_freq_read,
+	write:		ppc_rtas_tone_freq_write
+};
+struct file_operations ppc_rtas_tone_volume_operations = {
+	read:		ppc_rtas_tone_volume_read,
+	write:		ppc_rtas_tone_volume_write
+};
+
+int ppc_rtas_find_all_sensors (void);
+int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
+		int error, char * buf);
+char * ppc_rtas_process_error(int error);
+int get_location_code(struct individual_sensor s, char * buf);
+int check_location_string (char *c, char * buf);
+int check_location (char *c, int idx, char * buf);
+
+/* ****************************************************************** */
+/* MAIN                                                               */
+/* ****************************************************************** */
+void proc_rtas_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	rtas_node = find_devices("rtas");
+	if ((rtas_node == 0) || (_machine == _MACH_iSeries)) {
+		return;
+	}
+	
+	proc_rtas = proc_mkdir("rtas", 0);
+	if (proc_rtas == 0)
+		return;
+
+	/* /proc/rtas entries */
+
+	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
+	if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
+
+	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
+
+	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
+
+	create_proc_read_entry("sensors", S_IRUGO, proc_rtas, 
+			ppc_rtas_sensor_read, NULL);
+	
+	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
+
+	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
+	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+}
+
+/* ****************************************************************** */
+/* POWER-ON-TIME                                                      */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	struct rtc_time tm;
+	unsigned long nowtime;
+	char *dest;
+	int error;
+
+	nowtime = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_poweron_write: Invalid time\n");
+		return count;
+	}
+	power_on_time = nowtime; /* save the time */
+
+	to_tm(nowtime, &tm);
+
+	error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 
+			tm.tm_year, tm.tm_mon, tm.tm_mday, 
+			tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n;
+	if (power_on_time == 0)
+		n = sprintf(buf, "Power on time not set\n");
+	else
+		n = sprintf(buf, "%lu\n", power_on_time);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+
+/* ****************************************************************** */
+/* PROGRESS                                                           */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	unsigned long hex;
+
+	strcpy(progress_led, buf); /* save the string */
+	/* Lets see if the user passed hexdigits */
+	hex = simple_strtoul(buf, NULL, 10);
+	
+	ppc_md.progress ((char *)buf, hex);
+	return count;
+
+	/* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n = 0;
+	if (progress_led != NULL)
+		n = sprintf (buf, "%s\n", progress_led);
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+
+/* ****************************************************************** */
+/* CLOCK                                                              */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
+		size_t count, loff_t *ppos)
+{
+	struct rtc_time tm;
+	unsigned long nowtime;
+	char *dest;
+	int error;
+
+	nowtime = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_clock_write: Invalid time\n");
+		return count;
+	}
+
+	to_tm(nowtime, &tm);
+	error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, 
+			tm.tm_year, tm.tm_mon, tm.tm_mday, 
+			tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting the clock returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, 
+		size_t count, loff_t *ppos)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned long *ret = kmalloc(4*8, GFP_KERNEL);
+	int n, error;
+
+	error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
+	
+	year = ret[0]; mon  = ret[1]; day  = ret[2];
+	hour = ret[3]; min  = ret[4]; sec  = ret[5];
+
+	if (error != 0){
+		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
+				ppc_rtas_process_error(error));
+		n = sprintf (buf, "0");
+	} else { 
+		n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
+	}
+	kfree(ret);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+
+/* ****************************************************************** */
+/* SENSOR STUFF                                                       */
+/* ****************************************************************** */
+static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data)
+{
+	int i,j,n;
+	unsigned long ret;
+	int state, error;
+	char *buffer;
+	int get_sensor_state = rtas_token("get-sensor-state");
+
+	if (count < 0)
+		return -EINVAL;
+
+	/* May not be enough */
+	buffer = kmalloc(MAX_LINELENGTH*MAX_SENSORS, GFP_KERNEL);
+
+	if (!buffer)
+		return -ENOMEM;
+
+	memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS);
+
+	n  = sprintf ( buffer  , "RTAS (RunTime Abstraction Services) Sensor Information\n");
+	n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
+	n += sprintf ( buffer+n, "********************************************************\n");
+
+	if (ppc_rtas_find_all_sensors() != 0) {
+		n += sprintf ( buffer+n, "\nNo sensors are available\n");
+		goto return_string;
+	}
+
+	for (i=0; i<sensors.quant; i++) {
+		j = sensors.sensor[i].quant;
+		/* A sensor may have multiple instances */
+		while (j >= 0) {
+			error =	rtas_call(get_sensor_state, 2, 2, &ret, 
+				  sensors.sensor[i].token, sensors.sensor[i].quant-j);
+			state = (int) ret;
+			n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n );
+			n += sprintf (buffer+n, "\n");
+			j--;
+		} /* while */
+	} /* for */
+
+return_string:
+	if (off >= strlen(buffer)) {
+		*eof = 1;
+		kfree(buffer);
+		return 0;
+	}
+	if (n > strlen(buffer) - off)
+		n = strlen(buffer) - off;
+	if (n > count)
+		n = count;
+	else
+		*eof = 1;
+	memcpy(buf, buffer + off, n);
+	*start = buf;
+	kfree(buffer);
+	return n;
+}
+
+/* ****************************************************************** */
+
+int ppc_rtas_find_all_sensors (void)
+{
+	unsigned long *utmp;
+	int len, i, j;
+
+	utmp = (unsigned long *) get_property(rtas_node, "rtas-sensors", &len);
+	if (utmp == NULL) {
+		printk (KERN_ERR "error: could not get rtas-sensors\n");
+		return 1;
+	}
+
+	sensors.quant = len / 8;      /* int + int */
+
+	for (i=0, j=0; j<sensors.quant; i+=2, j++) {
+		sensors.sensor[j].token = utmp[i];
+		sensors.sensor[j].quant = utmp[i+1];
+	}
+	return 0;
+}
+
+/* ****************************************************************** */
+/*
+ * Builds a string of what rtas returned
+ */
+char * ppc_rtas_process_error(int error)
+{
+	switch (error) {
+		case SENSOR_CRITICAL_HIGH:
+			return "(critical high)";
+		case SENSOR_WARNING_HIGH:
+			return "(warning high)";
+		case SENSOR_NORMAL:
+			return "(normal)";
+		case SENSOR_WARNING_LOW:
+			return "(warning low)";
+		case SENSOR_CRITICAL_LOW:
+			return "(critical low)";
+		case SENSOR_SUCCESS:
+			return "(read ok)";
+		case SENSOR_HW_ERROR:
+			return "(hardware error)";
+		case SENSOR_BUSY:
+			return "(busy)";
+		case SENSOR_NOT_EXIST:
+			return "(non existant)";
+		case SENSOR_DR_ENTITY:
+			return "(dr entity removed)";
+		default:
+			return "(UNKNOWN)";
+	}
+}
+
+/* ****************************************************************** */
+/*
+ * Builds a string out of what the sensor said
+ */
+
+int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
+		int error, char * buf) 
+{
+	/* Defined return vales */
+	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", "Mainenance" };
+	const char * enclosure_switch[]  = { "Closed", "Open" };
+	const char * lid_status[]        = { " ", "Open", "Closed" };
+	const char * power_source[]      = { "AC\t", "Battery", "AC & Battery" };
+	const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
+	const char * epow_sensor[]       = { 
+		"EPOW Reset", "Cooling warning", "Power warning",
+		"System shutdown", "System halt", "EPOW main enclosure",
+		"EPOW power off" };
+	const char * battery_cyclestate[]  = { "None", "In progress", "Requested" };
+	const char * battery_charging[]    = { "Charging", "Discharching", "No current flow" };
+	const char * ibm_drconnector[]     = { "Empty", "Present" };
+	const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
+
+	int have_strings = 0;
+	int temperature = 0;
+	int unknown = 0;
+	int n = 0;
+
+	/* What kind of sensor do we have here? */
+	switch (s.token) {
+		case KEY_SWITCH:
+			n += sprintf(buf+n, "Key switch:\t");
+			n += sprintf(buf+n, "%s\t", key_switch[state]);
+			have_strings = 1;
+			break;
+		case ENCLOSURE_SWITCH:
+			n += sprintf(buf+n, "Enclosure switch:\t");
+			n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
+			have_strings = 1;
+			break;
+		case THERMAL_SENSOR:
+			n += sprintf(buf+n, "Temp. (°C/°F):\t");
+			temperature = 1;
+			break;
+		case LID_STATUS:
+			n += sprintf(buf+n, "Lid status:\t");
+			n += sprintf(buf+n, "%s\t", lid_status[state]);
+			have_strings = 1;
+			break;
+		case POWER_SOURCE:
+			n += sprintf(buf+n, "Power source:\t");
+			n += sprintf(buf+n, "%s\t", power_source[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_VOLTAGE:
+			n += sprintf(buf+n, "Battery voltage:\t");
+			break;
+		case BATTERY_REMAINING:
+			n += sprintf(buf+n, "Battery remaining:\t");
+			n += sprintf(buf+n, "%s\t", battery_remaining[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_PERCENTAGE:
+			n += sprintf(buf+n, "Battery percentage:\t");
+			break;
+		case EPOW_SENSOR:
+			n += sprintf(buf+n, "EPOW Sensor:\t");
+			n += sprintf(buf+n, "%s\t", epow_sensor[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_CYCLESTATE:
+			n += sprintf(buf+n, "Battery cyclestate:\t");
+			n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
+			have_strings = 1;
+			break;
+		case BATTERY_CHARGING:
+			n += sprintf(buf+n, "Battery Charging:\t");
+			n += sprintf(buf+n, "%s\t", battery_charging[state]);
+			have_strings = 1;
+			break;
+		case IBM_SURVEILLANCE:
+			n += sprintf(buf+n, "Surveillance:\t");
+			break;
+		case IBM_FANRPM:
+			n += sprintf(buf+n, "Fan (rpm):\t");
+			break;
+		case IBM_VOLTAGE:
+			n += sprintf(buf+n, "Voltage (mv):\t");
+			break;
+		case IBM_DRCONNECTOR:
+			n += sprintf(buf+n, "DR connector:\t");
+			n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
+			have_strings = 1;
+			break;
+		case IBM_POWERSUPPLY:
+			n += sprintf(buf+n, "Powersupply:\t");
+			break;
+		case IBM_INTQUEUE:
+			n += sprintf(buf+n, "Interrupt queue:\t");
+			n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
+			have_strings = 1;
+			break;
+		default:
+			n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
+					s.token);
+			unknown = 1;
+			have_strings = 1;
+			break;
+	}
+	if (have_strings == 0) {
+		if (temperature) {
+			n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
+		} else
+			n += sprintf(buf+n, "%10d\t", state);
+	}
+	if (unknown == 0) {
+		n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
+		n += get_location_code(s, buf+n);
+	}
+	return n;
+}
+
+/* ****************************************************************** */
+
+int check_location (char *c, int idx, char * buf)
+{
+	int n = 0;
+
+	switch (*(c+idx)) {
+		case LOC_PLANAR:
+			n += sprintf ( buf, "Planar #%c", *(c+idx+1));
+			break;
+		case LOC_CPU:
+			n += sprintf ( buf, "CPU #%c", *(c+idx+1));
+			break;
+		case LOC_FAN:
+			n += sprintf ( buf, "Fan #%c", *(c+idx+1));
+			break;
+		case LOC_RACKMOUNTED:
+			n += sprintf ( buf, "Rack #%c", *(c+idx+1));
+			break;
+		case LOC_VOLTAGE:
+			n += sprintf ( buf, "Voltage #%c", *(c+idx+1));
+			break;
+		case LOC_LCD:
+			n += sprintf ( buf, "LCD #%c", *(c+idx+1));
+			break;
+		case '.':
+			n += sprintf ( buf, "- %c", *(c+idx+1));
+		default:
+			n += sprintf ( buf, "Unknown location");
+			break;
+	}
+	return n;
+}
+
+
+/* ****************************************************************** */
+/* 
+ * Format: 
+ * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
+ * the '.' may be an abbrevation
+ */
+int check_location_string (char *c, char *buf)
+{
+	int n=0,i=0;
+
+	while (c[i]) {
+		if (isalpha(c[i]) || c[i] == '.') {
+			 n += check_location(c, i, buf+n);
+		}
+		else if (c[i] == '/' || c[i] == '-')
+			n += sprintf(buf+n, " at ");
+		i++;
+	}
+	return n;
+}
+
+
+/* ****************************************************************** */
+
+int get_location_code(struct individual_sensor s, char * buffer)
+{
+	char rstr[512], tmp[10], tmp2[10];
+	int n=0, i=0, llen, len;
+	/* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */
+	char *ret;
+
+	static int pos = 0; /* remember position where buffer was */
+
+	/* construct the sensor number like 0003 */
+	/* fill with zeros */
+	n = sprintf(tmp, "%d", s.token);
+	len = strlen(tmp);
+	while (strlen(tmp) < 4)
+		n += sprintf (tmp+n, "0");
+	
+	/* invert the string */
+	while (tmp[i]) {
+		if (i<len)
+			tmp2[4-len+i] = tmp[i];
+		else
+			tmp2[3-i] = tmp[i];
+		i++;
+	}
+	tmp2[4] = '\0';
+
+	sprintf (rstr, SENSOR_PREFIX"%s", tmp2);
+
+	ret = (char *) get_property(rtas_node, rstr, &llen);
+
+	n=0;
+	if (ret[0] == '\0')
+		n += sprintf ( buffer+n, "--- ");/* does not have a location */
+	else {
+		char t[50];
+		ret += pos;
+
+		n += check_location_string(ret, buffer + n);
+		n += sprintf ( buffer+n, " ");
+		/* see how many characters we have printed */
+		sprintf ( t, "%s ", ret);
+
+		pos += strlen(t);
+		if (pos >= llen) pos=0;
+	}
+	return n;
+}
+/* ****************************************************************** */
+/* INDICATORS - Tone Frequency                                        */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	unsigned long freq;
+	char *dest;
+	int error;
+	freq = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
+		return count;
+	}
+	if (freq < 0) freq = 0;
+	rtas_tone_frequency = freq; /* save it for later */
+	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
+			TONE_FREQUENCY, 0, freq);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n;
+	n = sprintf(buf, "%lu\n", rtas_tone_frequency);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
+/* ****************************************************************** */
+/* INDICATORS - Tone Volume                                           */
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
+		size_t count, loff_t *ppos)
+{
+	unsigned long volume;
+	char *dest;
+	int error;
+	volume = simple_strtoul(buf, &dest, 10);
+	if (*dest != '\0' && *dest != '\n') {
+		printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
+		return count;
+	}
+	if (volume < 0) volume = 0;
+	if (volume > 100) volume = 100;
+	
+        rtas_tone_volume = volume; /* save it for later */
+	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
+			TONE_VOLUME, 0, volume);
+	if (error != 0)
+		printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
+				ppc_rtas_process_error(error));
+	return count;
+}
+/* ****************************************************************** */
+static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
+		size_t count, loff_t *ppos)
+{
+	int n;
+	n = sprintf(buf, "%lu\n", rtas_tone_volume);
+
+	if (*ppos >= strlen(buf))
+		return 0;
+	if (n > strlen(buf) - *ppos)
+		n = strlen(buf) - *ppos;
+	if (n > count)
+		n = count;
+	*ppos += n;
+	return n;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/rtas.c linux-2.4.19-pre5/arch/ppc64/kernel/rtas.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/rtas.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/rtas.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,209 @@
+/*
+ *
+ * Procedures for interfacing to the RTAS on CHRP machines.
+ *
+ * Peter Bergner, IBM	March 2001.
+ * Copyright (C) 2001 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <stdarg.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include <asm/init.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/semaphore.h>
+#include <asm/machdep.h>
+#include <asm/Paca.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/udbg.h>
+
+/*
+ * prom_init() is called very early on, before the kernel text
+ * and data have been mapped to KERNELBASE.  At this point the code
+ * is running at whatever address it has been loaded at, so
+ * references to extern and static variables must be relocated
+ * explicitly.  The procedure reloc_offset() returns the address
+ * we're currently running at minus the address we were linked at.
+ * (Note that strings count as static variables.)
+ *
+ * Because OF may have mapped I/O devices into the area starting at
+ * KERNELBASE, particularly on CHRP machines, we can't safely call
+ * OF once the kernel has been mapped to KERNELBASE.  Therefore all
+ * OF calls should be done within prom_init(), and prom_init()
+ * and all routines called within it must be careful to relocate
+ * references as necessary.
+ *
+ * Note that the bss is cleared *after* prom_init runs, so we have
+ * to make sure that any static or extern variables it accesses
+ * are put in the data segment.
+ */
+
+struct rtas_t rtas = { 
+	lock: SPIN_LOCK_UNLOCKED
+};
+
+extern unsigned long reloc_offset(void);
+
+void
+phys_call_rtas(int token, int nargs, int nret, ...)
+{
+	va_list list;
+	unsigned long offset = reloc_offset();
+	struct rtas_args *rtas = PTRRELOC(&(get_paca()->xRtas));
+	int i;
+
+	rtas->token = token;
+	rtas->nargs = nargs;
+	rtas->nret  = nret;
+	rtas->rets  = (rtas_arg_t *)PTRRELOC(&(rtas->args[nargs]));
+
+	va_start(list, nret);
+	for (i = 0; i < nargs; i++)
+	  rtas->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
+	va_end(list);
+
+        enter_rtas(rtas);	
+}
+
+void
+phys_call_rtas_display_status(char c)
+{
+	unsigned long offset = reloc_offset();
+	struct rtas_args *rtas = PTRRELOC(&(get_paca()->xRtas));
+
+	rtas->token = 10;
+	rtas->nargs = 1;
+	rtas->nret  = 1;
+	rtas->rets  = (rtas_arg_t *)PTRRELOC(&(rtas->args[1]));
+	rtas->args[0] = (int)c;
+
+	enter_rtas(rtas);	
+}
+
+void
+call_rtas_display_status(char c)
+{
+	struct rtas_args *rtas = &(get_paca()->xRtas);
+
+	rtas->token = 10;
+	rtas->nargs = 1;
+	rtas->nret  = 1;
+	rtas->rets  = (rtas_arg_t *)&(rtas->args[1]);
+	rtas->args[0] = (int)c;
+
+	enter_rtas((void *)__pa((unsigned long)rtas));	
+}
+
+#if 0
+#define DEBUG_RTAS
+#endif
+__openfirmware
+int
+rtas_token(const char *service)
+{
+	int *tokp;
+	if (rtas.dev == NULL) {
+#ifdef DEBUG_RTAS
+		udbg_printf("\tNo rtas device in device-tree...\n");
+#endif /* DEBUG_RTAS */
+		return RTAS_UNKNOWN_SERVICE;
+	}
+	tokp = (int *) get_property(rtas.dev, service, NULL);
+	return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
+}
+
+__openfirmware
+long
+rtas_call(int token, int nargs, int nret,
+	  unsigned long *outputs, ...)
+{
+	va_list list;
+	int i;
+	unsigned long s;
+	struct rtas_args *rtas_args = &(get_paca()->xRtas);
+
+#ifdef DEBUG_RTAS
+	udbg_printf("Entering rtas_call\n");
+	udbg_printf("\ttoken    = 0x%x\n", token);
+	udbg_printf("\tnargs    = %d\n", nargs);
+	udbg_printf("\tnret     = %d\n", nret);
+	udbg_printf("\t&outputs = 0x%lx\n", outputs);
+#endif /* DEBUG_RTAS */
+	if (token == RTAS_UNKNOWN_SERVICE)
+		return -1;
+
+	rtas_args->token = token;
+	rtas_args->nargs = nargs;
+	rtas_args->nret  = nret;
+	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
+	va_start(list, outputs);
+	for (i = 0; i < nargs; ++i) {
+	  rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
+#ifdef DEBUG_RTAS
+	  udbg_printf("\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
+#endif /* DEBUG_RTAS */
+	}
+	va_end(list);
+
+	for (i = 0; i < nret; ++i)
+	  rtas_args->rets[i] = 0;
+
+#if 0   /* Gotta do something different here, use global lock for now... */
+	spin_lock_irqsave(&rtas_args->lock, s);
+#else
+	spin_lock_irqsave(&rtas.lock, s);
+#endif
+#ifdef DEBUG_RTAS
+	udbg_printf("\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args));
+#endif /* DEBUG_RTAS */
+	enter_rtas((void *)__pa((unsigned long)rtas_args));
+#ifdef DEBUG_RTAS
+	udbg_printf("\treturned from rtas ...\n");
+#endif /* DEBUG_RTAS */
+#if 0   /* Gotta do something different here, use global lock for now... */
+	spin_unlock_irqrestore(&rtas_args->lock, s);
+#else
+	spin_unlock_irqrestore(&rtas.lock, s);
+#endif
+#ifdef DEBUG_RTAS
+	for(i=0; i < nret ;i++)
+	  udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
+#endif /* DEBUG_RTAS */
+
+	if (nret > 1 && outputs != NULL)
+		for (i = 0; i < nret-1; ++i)
+			outputs[i] = rtas_args->rets[i+1];
+	return (ulong)((nret > 0) ? rtas_args->rets[0] : 0);
+}
+
+void __chrp
+rtas_restart(char *cmd)
+{
+        printk("RTAS system-reboot returned %ld\n",
+	       rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
+        for (;;);
+}
+
+void __chrp
+rtas_power_off(void)
+{
+        /* allow power on only with power button press */
+        printk("RTAS power-off returned %ld\n",
+               rtas_call(rtas_token("power-off"), 2, 1, NULL,0xffffffff,0xffffffff));
+        for (;;);
+}
+
+void __chrp
+rtas_halt(void)
+{
+        rtas_power_off();
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/rtasd.c linux-2.4.19-pre5/arch/ppc64/kernel/rtasd.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/rtasd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/rtasd.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * 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.
+ *
+ * Communication to userspace based on kernel/printk.c
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+
+#if 0
+#define DEBUG(A...)	printk(KERN_ERR A)
+#else
+#define DEBUG(A...)
+#endif
+
+static spinlock_t rtas_log_lock = SPIN_LOCK_UNLOCKED;
+
+DECLARE_WAIT_QUEUE_HEAD(rtas_log_wait);
+
+#define LOG_NUMBER		64		/* must be a power of two */
+#define LOG_NUMBER_MASK		(LOG_NUMBER-1)
+
+static char *rtas_log_buf;
+static unsigned long rtas_log_start;
+static unsigned long rtas_log_size;
+
+static int surveillance_requested;
+static unsigned int rtas_event_scan_rate;
+static unsigned int rtas_error_log_max;
+
+#define EVENT_SCAN_ALL_EVENTS	0xf0000000
+#define SURVEILLANCE_TOKEN	9000
+#define SURVEILLANCE_TIMEOUT	1
+#define SURVEILLANCE_SCANRATE	1
+
+/*
+ * Since we use 32 bit RTAS, the physical address of this must be below
+ * 4G or else bad things happen. Allocate this in the kernel data and
+ * make it big enough.
+ */
+#define RTAS_ERROR_LOG_MAX 1024
+static unsigned char logdata[RTAS_ERROR_LOG_MAX];
+
+static int rtas_log_open(struct inode * inode, struct file * file)
+{
+	return 0;
+}
+
+static int rtas_log_release(struct inode * inode, struct file * file)
+{
+	return 0;
+}
+
+static ssize_t rtas_log_read(struct file * file, char * buf,
+			 size_t count, loff_t *ppos)
+{
+	int error;
+	char *tmp;
+	unsigned long offset;
+
+	if (!buf || count < rtas_error_log_max)
+		return -EINVAL;
+
+	count = rtas_error_log_max;
+
+	error = verify_area(VERIFY_WRITE, buf, count);
+	if (error)
+		return -EINVAL;
+
+	tmp = kmalloc(rtas_error_log_max, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	error = wait_event_interruptible(rtas_log_wait, rtas_log_size);
+	if (error)
+		goto out;
+
+	spin_lock(&rtas_log_lock);
+	offset = rtas_error_log_max * (rtas_log_start & LOG_NUMBER_MASK);
+	memcpy(tmp, &rtas_log_buf[offset], count);
+	rtas_log_start += 1;
+	rtas_log_size -= 1;
+	spin_unlock(&rtas_log_lock);
+
+	copy_to_user(buf, tmp, count);
+	error = count;
+
+out:
+	kfree(tmp);
+	return error;
+}
+
+static unsigned int rtas_log_poll(struct file *file, poll_table * wait)
+{
+	poll_wait(file, &rtas_log_wait, wait);
+	if (rtas_log_size)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+struct file_operations proc_rtas_log_operations = {
+	read:		rtas_log_read,
+	poll:		rtas_log_poll,
+	open:		rtas_log_open,
+	release:	rtas_log_release,
+};
+
+static void log_rtas(char *buf)
+{
+	unsigned long offset;
+
+	DEBUG("logging rtas event\n");
+
+	spin_lock(&rtas_log_lock);
+
+	offset = rtas_error_log_max *
+			((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK);
+
+	memcpy(&rtas_log_buf[offset], buf, rtas_error_log_max);
+
+	if (rtas_log_size < LOG_NUMBER)
+		rtas_log_size += 1;
+	else
+		rtas_log_start += 1;
+
+	spin_unlock(&rtas_log_lock);
+	wake_up_interruptible(&rtas_log_wait);
+}
+
+static int enable_surveillance(void)
+{
+	int error;
+
+	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, SURVEILLANCE_TOKEN,
+			0, SURVEILLANCE_TIMEOUT);
+
+	if (error) {
+		printk(KERN_ERR "rtasd: could not enable surveillance\n");
+		return -1;
+	}
+
+	rtas_event_scan_rate = SURVEILLANCE_SCANRATE;
+
+	return 0;
+}
+
+static int get_eventscan_parms(void)
+{
+	struct device_node *node;
+	int *ip;
+
+	node = find_path_device("/rtas");
+
+	ip = (int *)get_property(node, "rtas-event-scan-rate", NULL);
+	if (ip == NULL) {
+		printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
+		return -1;
+	}
+	rtas_event_scan_rate = *ip;
+	DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate);
+
+	ip = (int *)get_property(node, "rtas-error-log-max", NULL);
+	if (ip == NULL) {
+		printk(KERN_ERR "rtasd: no rtas-error-log-max\n");
+		return -1;
+	}
+	rtas_error_log_max = *ip;
+	DEBUG("rtas-error-log-max %d\n", rtas_error_log_max);
+
+	if (rtas_error_log_max > RTAS_ERROR_LOG_MAX) {
+		printk(KERN_ERR "rtasd: truncated error log from %d to %d bytes\n", rtas_error_log_max, RTAS_ERROR_LOG_MAX);
+		rtas_error_log_max = RTAS_ERROR_LOG_MAX;
+	}
+
+	return 0;
+}
+
+extern long sys_sched_get_priority_max(int policy);
+
+static int rtasd(void *unused)
+{
+	int cpu = 0;
+	int error;
+	int first_pass = 1;
+	int event_scan = rtas_token("event-scan");
+
+	if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1)
+		goto error;
+
+	rtas_log_buf = vmalloc(rtas_error_log_max*LOG_NUMBER);
+	if (!rtas_log_buf) {
+		printk(KERN_ERR "rtasd: no memory\n");
+		goto error;
+	}
+
+	DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2);
+
+	daemonize();
+	sigfillset(&current->blocked);
+	sprintf(current->comm, "rtasd");
+
+	/* Rusty unreal time task */
+	current->policy = SCHED_FIFO;
+	current->nice = sys_sched_get_priority_max(SCHED_FIFO) + 1;
+
+	cpu = 0;
+	current->cpus_allowed = 1UL << cpu_logical_map(cpu);
+	schedule();
+
+	while(1) {
+		do {
+			memset(logdata, 0, rtas_error_log_max);
+			error = rtas_call(event_scan, 4, 1, NULL,
+					EVENT_SCAN_ALL_EVENTS, 0,
+					__pa(logdata), rtas_error_log_max);
+			if (error == -1) {
+				printk(KERN_ERR "event-scan failed\n");
+				break;
+			}
+
+			if (error == 0)
+				log_rtas(logdata);
+
+		} while(error == 0);
+
+		DEBUG("watchdog scheduled on cpu %d\n", smp_processor_id());
+
+		cpu++;
+		if (cpu >= smp_num_cpus) {
+
+			if (first_pass && surveillance_requested) {
+				DEBUG("enabling surveillance\n");
+				if (enable_surveillance())
+					goto error_vfree;
+				DEBUG("surveillance enabled\n");
+			}
+
+			first_pass = 0;
+			cpu = 0;
+		}
+
+		current->cpus_allowed = 1UL << cpu_logical_map(cpu);
+
+		/* Check all cpus for pending events before sleeping*/
+		if (first_pass) {
+			schedule();
+		} else {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout((HZ*60/rtas_event_scan_rate) / 2);
+		}
+	}
+
+error_vfree:
+	vfree(rtas_log_buf);
+error:
+	/* Should delete proc entries */
+	return -EINVAL;
+}
+
+static void __init rtas_init(void)
+{
+	struct proc_dir_entry *rtas_dir, *entry;
+
+	rtas_dir = proc_mkdir("rtas", 0);
+	if (!rtas_dir) {
+		printk(KERN_ERR "Failed to create rtas proc directory\n");
+	} else {
+		entry = create_proc_entry("error_log", S_IRUSR, rtas_dir);
+		if (entry)
+			entry->proc_fops = &proc_rtas_log_operations;
+		else
+			printk(KERN_ERR "Failed to create rtas/error_log proc entry\n");
+	}
+
+	if (kernel_thread(rtasd, 0, CLONE_FS) < 0)
+		printk(KERN_ERR "Failed to start RTAS daemon\n");
+
+	printk(KERN_ERR "RTAS daemon started\n");
+}
+
+static int __init surveillance_setup(char *str)
+{
+	int i;
+
+	if (get_option(&str,&i)) {
+		if (i == 1)
+			surveillance_requested = 1;
+	}
+
+	return 1;
+}
+
+__initcall(rtas_init);
+__setup("surveillance=", surveillance_setup);
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/rtc.c linux-2.4.19-pre5/arch/ppc64/kernel/rtc.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/rtc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/rtc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,382 @@
+/*
+ *	Real Time Clock interface for PPC64.
+ *
+ *	Based on rtc.c by Paul Gortmaker
+ *
+ *	This driver allows use of the real time clock
+ *	from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the
+ *	/proc/driver/rtc pseudo-file for status information.
+ *
+ * 	Interface does not support RTC interrupts nor an alarm.
+ *
+ *	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.
+ *
+ *      1.0	Mike Corrigan:    IBM iSeries rtc support
+ *      1.1	Dave Engebretsen: IBM pSeries rtc support
+ */
+
+#define RTC_VERSION		"1.1"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/time.h>
+
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/mf.h>
+#include <asm/machdep.h>
+#include <asm/iSeries/ItSpCommArea.h>
+
+extern int piranha_simulator;
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin);
+
+static ssize_t rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos);
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg);
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data);
+
+/*
+ *	If this driver ever becomes modularised, it will be really nice
+ *	to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900;	/* year corresponding to 0x00	*/
+
+static const unsigned char days_in_mo[] = 
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ *	Now all the various file operations that we export.
+ */
+
+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	return -EIO;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	struct rtc_time wtime; 
+
+	switch (cmd) {
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+	{
+		ppc_md.get_rtc_time(&wtime);
+		break;
+	}
+	case RTC_SET_TIME:	/* Set the RTC */
+	{
+		struct rtc_time rtc_tm;
+		unsigned char mon, day, hrs, min, sec, leap_yr;
+		unsigned int yrs;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		yrs = rtc_tm.tm_year;
+		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+		day = rtc_tm.tm_mday;
+		hrs = rtc_tm.tm_hour;
+		min = rtc_tm.tm_min;
+		sec = rtc_tm.tm_sec;
+
+		if (yrs < 70)
+			return -EINVAL;
+
+		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+		if ((mon > 12) || (day == 0))
+			return -EINVAL;
+
+		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+			return -EINVAL;
+			
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+			return -EINVAL;
+
+		if ( yrs > 169 )
+			return -EINVAL;
+
+		ppc_md.set_rtc_time(&rtc_tm);
+		
+		return 0;
+	}
+	case RTC_EPOCH_READ:	/* Read the epoch.	*/
+	{
+		return put_user (epoch, (unsigned long *)arg);
+	}
+	case RTC_EPOCH_SET:	/* Set the epoch.	*/
+	{
+		/* 
+		 * There were no RTC clocks before 1900.
+		 */
+		if (arg < 1900)
+			return -EINVAL;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		epoch = arg;
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+static struct file_operations rtc_fops = {
+	owner:		THIS_MODULE,
+	llseek:		rtc_llseek,
+	read:		rtc_read,
+	ioctl:		rtc_ioctl,
+	open:		rtc_open,
+	release:	rtc_release,
+};
+
+static struct miscdevice rtc_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+static int __init rtc_init(void)
+{
+	misc_register(&rtc_dev);
+	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
+
+	printk(KERN_INFO "i/pSeries Real Time Clock Driver v" RTC_VERSION "\n");
+
+	return 0;
+}
+
+static void __exit rtc_exit (void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister(&rtc_dev);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+EXPORT_NO_SYMBOLS;
+
+/*
+ *	Info exported via "/proc/driver/rtc".
+ */
+
+static int rtc_proc_output (char *buf)
+{
+	
+	char *p;
+	struct rtc_time tm;
+	
+	p = buf;
+
+	ppc_md.get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+	 	     "rtc_epoch\t: %04lu\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
+
+	p += sprintf(p,
+		     "DST_enable\t: no\n"
+		     "BCD\t\t: yes\n"
+		     "24hr\t\t: yes\n" );
+
+	return  p - buf;
+}
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+        int len = rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+/*
+ * Get the RTC from the virtual service processor
+ * This requires flowing LpEvents to the primary partition
+ */
+void iSeries_get_rtc_time(struct rtc_time *rtc_tm)
+{
+	if (piranha_simulator)
+		return;
+
+	mf_getRtc(rtc_tm);
+	rtc_tm->tm_mon--;
+}
+
+
+void pSeries_get_rtc_time(struct rtc_time *rtc_tm)
+{
+        unsigned long ret[8];
+        int error;
+	int count;
+
+	/*
+	 * error -2 is clock busy, we keep retrying a few times to see
+	 * if it will come good  -- paulus
+	 */
+	count = 0;
+	do {
+		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, (void *)&ret);
+	} while (error == -2 && ++count < 1000);
+
+        if (error != 0) {
+                printk(KERN_WARNING "error: reading the clock failed (%d)\n",
+		       error);
+		return;
+        }
+
+	rtc_tm->tm_sec = ret[5];
+	rtc_tm->tm_min = ret[4];
+	rtc_tm->tm_hour = ret[3];
+	rtc_tm->tm_mday = ret[2];
+	rtc_tm->tm_mon = ret[1] - 1;
+	rtc_tm->tm_year = ret[0] - 1900;
+}
+
+int pSeries_set_rtc_time(struct rtc_time *tm)
+{
+        int error;
+	int count;
+
+	/*
+	 * error -2 is clock busy, we keep retrying a few times to see
+	 * if it will come good  -- paulus
+	 */
+	count = 0;
+	do {
+	        error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
+				  tm->tm_year + 1900, tm->tm_mon + 1, 
+				  tm->tm_mday, tm->tm_hour, tm->tm_min, 
+				  tm->tm_sec, 0);
+	} while (error == -2 && ++count < 1000);
+
+        if (error != 0)
+                printk(KERN_WARNING "error: setting the clock failed (%d)\n",
+		       error); 
+
+        return 0;
+}
+
+/*
+ * Set the RTC in the virtual service processor
+ * This requires flowing LpEvents to the primary partition
+ */
+int iSeries_set_rtc_time(struct rtc_time *tm)
+{
+	mf_setRtc(tm);
+	return 0;
+}
+
+void iSeries_get_boot_time(struct rtc_time *tm)
+{
+	unsigned long time;
+	static unsigned long lastsec = 1;
+
+	u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart));
+	u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1);
+	int year = 1970;
+	int year1 = ( dataWord1 >> 24 ) & 0x000000FF;
+	int year2 = ( dataWord1 >> 16 ) & 0x000000FF;
+	int sec = ( dataWord1 >> 8 ) & 0x000000FF;
+	int min = dataWord1 & 0x000000FF;
+	int hour = ( dataWord2 >> 24 ) & 0x000000FF;
+	int day = ( dataWord2 >> 8 ) & 0x000000FF;
+	int mon = dataWord2 & 0x000000FF;
+
+	if ( piranha_simulator )
+		return;
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year1);
+	BCD_TO_BIN(year2);
+	year = year1 * 100 + year2;
+
+	time = mktime(year, mon, day, hour, min, sec);
+	time += ( jiffies / HZ );
+
+	/* Now THIS is a nasty hack!
+	* It ensures that the first two calls get different answers.  
+	* That way the loop in init_time (time.c) will not think
+	* the clock is stuck.
+	*/
+	if ( lastsec ) {
+		time -= lastsec;
+		--lastsec;
+	}
+
+	to_tm(time, tm); 
+	tm->tm_year -= 1900;
+	tm->tm_mon  -= 1;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/semaphore.c linux-2.4.19-pre5/arch/ppc64/kernel/semaphore.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/semaphore.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/semaphore.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,130 @@
+/*
+ * 
+ *
+ * PowerPC-specific semaphore code.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * April 2001 - Reworked by Paul Mackerras <paulus@samba.org>
+ * to eliminate the SMP races in the old version between the updates
+ * of `count' and `waking'.  Now we use negative `count' values to
+ * indicate that some process(es) are waiting for the semaphore.
+ */
+
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+/*
+ * Atomically update sem->count.
+ * This does the equivalent of the following:
+ *
+ *	old_count = sem->count;
+ *	tmp = MAX(old_count, 0) + incr;
+ *	sem->count = tmp;
+ *	return old_count;
+ */
+static inline int __sem_update_count(struct semaphore *sem, int incr)
+{
+	int old_count, tmp;
+
+	__asm__ __volatile__("\n"
+"1:	lwarx	%0,0,%3\n"
+"	srawi	%1,%0,31\n"
+"	andc	%1,%0,%1\n"
+"	add	%1,%1,%4\n"
+"	stwcx.	%1,0,%3\n"
+"	bne	1b"
+	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
+	: "r" (&sem->count), "r" (incr), "m" (sem->count)
+	: "cc");
+
+	return old_count;
+}
+
+void __up(struct semaphore *sem)
+{
+	/*
+	 * Note that we incremented count in up() before we came here,
+	 * but that was ineffective since the result was <= 0, and
+	 * any negative value of count is equivalent to 0.
+	 * This ends up setting count to 1, unless count is now > 0
+	 * (i.e. because some other cpu has called up() in the meantime),
+	 * in which case we just increment count.
+	 */
+	__sem_update_count(sem, 1);
+	wake_up(&sem->wait);
+}
+
+/*
+ * Note that when we come in to __down or __down_interruptible,
+ * we have already decremented count, but that decrement was
+ * ineffective since the result was < 0, and any negative value
+ * of count is equivalent to 0.
+ * Thus it is only when we decrement count from some value > 0
+ * that we have actually got the semaphore.
+ */
+void __down(struct semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	tsk->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+	smp_wmb();
+
+	/*
+	 * Try to get the semaphore.  If the count is > 0, then we've
+	 * got the semaphore; we decrement count and exit the loop.
+	 * If the count is 0 or negative, we set it to -1, indicating
+	 * that we are asleep, and then sleep.
+	 */
+	while (__sem_update_count(sem, -1) <= 0) {
+		schedule();
+		tsk->state = TASK_UNINTERRUPTIBLE;
+	}
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	/*
+	 * If there are any more sleepers, wake one of them up so
+	 * that it can either get the semaphore, or set count to -1
+	 * indicating that there are still processes sleeping.
+	 */
+	wake_up(&sem->wait);
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	tsk->state = TASK_INTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+	smp_wmb();
+
+	while (__sem_update_count(sem, -1) <= 0) {
+		if (signal_pending(current)) {
+			/*
+			 * A signal is pending - give up trying.
+			 * Set sem->count to 0 if it is negative,
+			 * since we are no longer sleeping.
+			 */
+			__sem_update_count(sem, 0);
+			retval = -EINTR;
+			break;
+		}
+		schedule();
+		tsk->state = TASK_INTERRUPTIBLE;
+	}
+	tsk->state = TASK_RUNNING;
+	remove_wait_queue(&sem->wait, &wait);
+	wake_up(&sem->wait);
+	return retval;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/setup.c linux-2.4.19-pre5/arch/ppc64/kernel/setup.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/setup.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,731 @@
+/*
+ * 
+ * Common boot and setup code.
+ *
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/ioport.h>
+#include <asm/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/smp.h>
+#include <asm/elf.h>
+#include <asm/machdep.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/Naca.h>
+#include <asm/Paca.h>
+#include <asm/ppcdebug.h>
+#include <asm/time.h>
+
+extern unsigned long klimit;
+/* extern void *stab; */
+extern HTAB htab_data;
+extern unsigned long loops_per_jiffy;
+
+extern unsigned long embedded_sysmap_start;
+extern unsigned long embedded_sysmap_end;
+
+int have_of = 1;
+
+extern void  chrp_init(unsigned long r3,
+		       unsigned long r4,
+		       unsigned long r5,
+		       unsigned long r6,
+		       unsigned long r7);
+
+extern void chrp_init_map_io_space( void );
+extern void iSeries_init( void );
+extern void iSeries_init_early( void );
+extern void pSeries_init_early( void );
+extern void pSeriesLP_init_early(void);
+extern void mm_init_ppc64( void ); 
+
+unsigned long decr_overclock = 1;
+unsigned long decr_overclock_proc0 = 1;
+unsigned long decr_overclock_set = 0;
+unsigned long decr_overclock_proc0_set = 0;
+
+#ifdef CONFIG_XMON
+extern void xmon_map_scc(void);
+#endif
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
+		    unsigned long r6, unsigned long r7);
+int parse_bootinfo(void);
+
+unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
+int _machine = _MACH_unknown;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+struct machdep_calls ppc_md;
+struct Naca *naca;
+
+/*
+ * Perhaps we can put the pmac screen_info[] here
+ * on pmac as well so we don't need the ifdef's.
+ * Until we get multiple-console support in here
+ * that is.  -- Cort
+ * Maybe tie it to serial consoles, since this is really what
+ * these processors use on existing boards.  -- Dan
+ */ 
+struct screen_info screen_info = {
+	0, 25,			/* orig-x, orig-y */
+	0,			/* unused */
+	0,			/* orig-video-page */
+	0,			/* orig-video-mode */
+	80,			/* orig-video-cols */
+	0,0,0,			/* ega_ax, ega_bx, ega_cx */
+	25,			/* orig-video-lines */
+	1,			/* orig-video-isVGA */
+	16			/* orig-video-points */
+};
+
+/*
+ * These are used in binfmt_elf.c to put aux entries on the stack
+ * for each elf executable being started.
+ */
+int dcache_bsize;
+int icache_bsize;
+int ucache_bsize;
+
+/*
+ * Initialize the PPCDBG state.  Called before relocation has been enabled.
+ */
+void ppcdbg_initialize(void) {
+	unsigned long offset = reloc_offset();
+	struct Naca *_naca = RELOC(naca);
+
+	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
+}
+
+/* 
+ * Initialize a set of PACA's, one for each processor.
+ *
+ * At this point, relocation is on, but we have not done any other
+ * setup of the mm subsystem.
+ */
+void paca_init(void) {
+#if 0
+	int processorCount = naca->processorCount, i;
+	struct Paca *paca[];
+
+	/* Put the array of paca's on a page boundary & allocate 1/2 page of */
+	/* storage for each.                                                 */  
+	klimit += (PAGE_SIZE-1) & PAGE_MASK;
+	naca->xPaca = paca[0] = klimit;
+	klimit += ((PAGE_SIZE>>1) * processorCount); 
+
+	for(i=0; i<processorCount; i++) {
+		paca[0]->xPacaIndex = i;
+	}
+#endif
+}
+
+/*
+ * Do some initial setup of the system.  The paramters are those which 
+ * were passed in from the bootloader.
+ */
+void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
+		  unsigned long r6, unsigned long r7)
+{
+	/* This should be fixed properly in kernel/resource.c */
+	iomem_resource.end = MEM_SPACE_LIMIT;
+
+	/* pSeries systems are identified in prom.c via OF. */
+	if ( itLpNaca.xLparInstalled == 1 )
+		_machine = _MACH_iSeries;
+	switch (_machine) {
+	case _MACH_iSeries:
+		iSeries_init_early();
+		break;
+
+#ifdef CONFIG_PPC_PSERIES
+	case _MACH_pSeries:
+		pSeries_init_early();
+#ifdef CONFIG_BLK_DEV_INITRD
+		initrd_start = initrd_end = 0;
+#endif
+		parse_bootinfo();
+		break;
+
+	case _MACH_pSeriesLP:
+		pSeriesLP_init_early();
+#ifdef CONFIG_BLK_DEV_INITRD
+		initrd_start = initrd_end = 0;
+#endif
+		parse_bootinfo();
+		break;
+#endif
+	}
+
+	udbg_puts("\n-----------------------------------------------------\n");
+	udbg_puts("Naca Info...\n\n");
+	udbg_puts("naca                       = 0x");
+	udbg_puthex((unsigned long)naca);
+	udbg_putc('\n');
+
+	udbg_puts("naca->processorCount       = 0x");
+	udbg_puthex(naca->processorCount);
+	udbg_putc('\n');
+
+	udbg_puts("naca->physicalMemorySize   = 0x");
+	udbg_puthex(naca->physicalMemorySize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->dCacheL1LineSize     = 0x");
+	udbg_puthex(naca->dCacheL1LineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->dCacheL1LogLineSize  = 0x");
+	udbg_puthex(naca->dCacheL1LogLineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->dCacheL1LinesPerPage = 0x");
+	udbg_puthex(naca->dCacheL1LinesPerPage);
+	udbg_putc('\n');
+
+	udbg_puts("naca->iCacheL1LineSize     = 0x");
+	udbg_puthex(naca->iCacheL1LineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->iCacheL1LogLineSize  = 0x");
+	udbg_puthex(naca->iCacheL1LogLineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->iCacheL1LinesPerPage = 0x");
+	udbg_puthex(naca->iCacheL1LinesPerPage);
+	udbg_putc('\n');
+
+	udbg_puts("naca->pftSize              = 0x");
+	udbg_puthex(naca->pftSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->serialPortAddr       = 0x");
+	udbg_puthex(naca->serialPortAddr);
+	udbg_putc('\n');
+
+	udbg_puts("naca->interrupt_controller = 0x");
+	udbg_puthex(naca->interrupt_controller);
+	udbg_putc('\n');
+
+	udbg_printf("\nHTAB Info ...\n\n"); 
+	udbg_puts("htab_data.htab             = 0x");
+	udbg_puthex((unsigned long)htab_data.htab);
+	udbg_putc('\n');
+	udbg_puts("htab_data.num_ptegs        = 0x");
+	udbg_puthex(htab_data.htab_num_ptegs);
+	udbg_putc('\n');
+
+	udbg_puts("\n-----------------------------------------------------\n");
+
+
+	if ( _machine & _MACH_pSeries ) {
+		finish_device_tree();
+		chrp_init(r3, r4, r5, r6, r7);
+	}
+
+	mm_init_ppc64();
+
+	switch (_machine) {
+	case _MACH_iSeries:
+		iSeries_init();
+		break;
+	default:
+		/* The following relies on the device tree being */
+		/* fully configured.                             */
+		parse_cmd_line(r3, r4, r5, r6, r7);
+	}
+}
+
+void machine_restart(char *cmd)
+{
+	ppc_md.restart(cmd);
+}
+  
+void machine_power_off(void)
+{
+	ppc_md.power_off();
+}
+  
+void machine_halt(void)
+{
+	ppc_md.halt();
+}
+
+unsigned long ppc_proc_freq;
+unsigned long ppc_tb_freq;
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	unsigned long cpu_id = (unsigned long)v - 1;
+	unsigned int pvr;
+	unsigned short maj;
+	unsigned short min;
+
+#ifdef CONFIG_SMP
+	if (cpu_id == NR_CPUS) {
+
+		if (ppc_md.get_cpuinfo != NULL)
+			ppc_md.get_cpuinfo(m);
+
+		return 0;
+	}
+
+	if (!(cpu_online_map & (1<<cpu_id)))
+		return 0;
+#endif
+
+	pvr = xPaca[cpu_id].pvr;
+	maj = (pvr >> 8) & 0xFF;
+	min = pvr & 0xFF;
+
+	seq_printf(m, "processor\t: %lu\n", cpu_id);
+	seq_printf(m, "cpu\t\t: ");
+
+	pvr = xPaca[cpu_id].pvr;
+
+	switch (PVR_VER(pvr)) {
+	case PV_PULSAR:
+		seq_printf(m, "RS64-III (pulsar)\n");
+		break;
+	case PV_POWER4:
+		seq_printf(m, "POWER4 (gp)\n");
+		break;
+	case PV_ICESTAR:
+		seq_printf(m, "RS64-III (icestar)\n");
+		break;
+	case PV_SSTAR:
+		seq_printf(m, "RS64-IV (sstar)\n");
+		break;
+	case PV_630:
+		seq_printf(m, "POWER3 (630)\n");
+		break;
+	case PV_630p:
+		seq_printf(m, "POWER3 (630+)\n");
+		break;
+	default:
+		seq_printf(m, "Unknown (%08x)\n", pvr);
+		break;
+	}
+
+	/*
+	 * Assume here that all clock rates are the same in a
+	 * smp system.  -- Cort
+	 */
+	if (_machine != _MACH_iSeries) {
+		struct device_node *cpu_node;
+		int *fp;
+
+		cpu_node = find_type_devices("cpu");
+		if (cpu_node) {
+			fp = (int *) get_property(cpu_node, "clock-frequency",
+						  NULL);
+			if (fp)
+				seq_printf(m, "clock\t\t: %dMHz\n",
+					   *fp / 1000000);
+		}
+	}
+
+	if (ppc_md.setup_residual != NULL)
+		ppc_md.setup_residual(m, cpu_id);
+
+	seq_printf(m, "revision\t: %hd.%hd\n", maj, min);
+	
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
+
+/*
+ * Fetch the cmd_line from open firmware. */
+void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
+		  unsigned long r6, unsigned long r7)
+{
+	struct device_node *chosen;
+	char *p;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if ((initrd_start == 0) && r3 && r4 && r4 != 0xdeadbeef) {
+		initrd_start = (r3 >= KERNELBASE) ? r3 : (unsigned long)__va(r3);
+		initrd_end = initrd_start + r4;
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+		initrd_below_start_ok = 1;
+	}
+#endif
+
+	cmd_line[0] = 0;
+	chosen = find_devices("chosen");
+	if (chosen != NULL) {
+		p = get_property(chosen, "bootargs", NULL);
+		if (p != NULL)
+			strncpy(cmd_line, p, sizeof(cmd_line));
+	}
+	cmd_line[sizeof(cmd_line) - 1] = 0;
+
+	/* Look for mem= option on command line */
+	if (strstr(cmd_line, "mem=")) {
+		char *p, *q;
+		unsigned long maxmem = 0;
+		extern unsigned long __max_memory;
+
+		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
+			q = p + 4;
+			if (p > cmd_line && p[-1] != ' ')
+				continue;
+			maxmem = simple_strtoul(q, &q, 0);
+			if (*q == 'k' || *q == 'K') {
+				maxmem <<= 10;
+				++q;
+			} else if (*q == 'm' || *q == 'M') {
+				maxmem <<= 20;
+				++q;
+			}
+		}
+		__max_memory = maxmem;
+	}
+	ppc_md.progress("id mach: done", 0x200);
+}
+
+
+char *bi_tag2str(unsigned long tag)
+{
+	switch (tag) {
+	case BI_FIRST:
+		return "BI_FIRST";
+	case BI_LAST:
+		return "BI_LAST";
+	case BI_CMD_LINE:
+		return "BI_CMD_LINE";
+	case BI_BOOTLOADER_ID:
+		return "BI_BOOTLOADER_ID";
+	case BI_INITRD:
+		return "BI_INITRD";
+	case BI_SYSMAP:
+		return "BI_SYSMAP";
+	case BI_MACHTYPE:
+		return "BI_MACHTYPE";
+	default:
+		return "BI_UNKNOWN";
+	}
+}
+
+int parse_bootinfo(void)
+{
+	struct bi_record *rec;
+	extern char *sysmap;
+	extern unsigned long sysmap_size;
+
+	rec = prom.bi_recs;
+
+	if ( rec == NULL || rec->tag != BI_FIRST )
+		return -1;
+
+	for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) {
+		switch (rec->tag) {
+		case BI_CMD_LINE:
+			memcpy(cmd_line, (void *)rec->data, rec->size);
+			break;
+		case BI_SYSMAP:
+			sysmap = (char *)((rec->data[0] >= (KERNELBASE))
+					? rec->data[0] : (unsigned long)__va(rec->data[0]));
+			sysmap_size = rec->data[1];
+			break;
+#ifdef CONFIG_BLK_DEV_INITRD
+		case BI_INITRD:
+			initrd_start = (unsigned long)__va(rec->data[0]);
+			initrd_end = initrd_start + rec->data[1];
+			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+			initrd_below_start_ok = 1;
+			break;
+#endif /* CONFIG_BLK_DEV_INITRD */
+		}
+	}
+
+	return 0;
+}
+
+void __init ppc_init(void)
+{
+	/* clear the progress line */
+	ppc_md.progress(" ", 0xffff);
+
+	if (ppc_md.init != NULL) {
+		ppc_md.init();
+	}
+}
+
+void __init ppc64_calibrate_delay(void)
+{
+	loops_per_jiffy = tb_ticks_per_jiffy;
+
+	printk("Calibrating delay loop... %lu.%02lu BogoMips\n",
+			       loops_per_jiffy/(500000/HZ),
+			       loops_per_jiffy/(5000/HZ) % 100);
+
+}	
+
+extern void (*calibrate_delay)(void);
+
+/*
+ * Called into from start_kernel, after lock_kernel has been called.
+ * Initializes bootmem, which is unsed to manage page allocation until
+ * mem_init is called.
+ */
+void __init setup_arch(char **cmdline_p)
+{
+	extern int panic_timeout;
+	extern char _etext[], _edata[];
+	extern void do_init_bootmem(void);
+
+	calibrate_delay = ppc64_calibrate_delay;
+
+#ifdef CONFIG_XMON
+	xmon_map_scc();
+	if (strstr(cmd_line, "xmon"))
+		xmon(0);
+#endif /* CONFIG_XMON */
+#ifdef CONFIG_KDB
+	xmon_map_scc();	/* in kdb/start.c --need to rename TAI */
+#endif
+	ppc_md.progress("setup_arch:enter", 0x3eab);
+
+#if defined(CONFIG_KGDB)
+	kgdb_map_scc();
+	set_debug_traps();
+	breakpoint();
+#endif
+	/*
+	 * Set cache line size based on type of cpu as a default.
+	 * Systems with OF can look in the properties on the cpu node(s)
+	 * for a possibly more accurate value.
+	 */
+	dcache_bsize = naca->dCacheL1LineSize; 
+	icache_bsize = naca->iCacheL1LineSize; 
+
+	/* reboot on panic */
+	panic_timeout = 180;
+
+	init_mm.start_code = PAGE_OFFSET;
+	init_mm.end_code = (unsigned long) _etext;
+	init_mm.end_data = (unsigned long) _edata;
+	init_mm.brk = (unsigned long) klimit;
+	
+	/* Save unparsed command line copy for /proc/cmdline */
+	strcpy(saved_command_line, cmd_line);
+	*cmdline_p = cmd_line;
+
+	/* set up the bootmem stuff with available memory */
+	do_init_bootmem();
+	ppc_md.progress("setup_arch:bootmem", 0x3eab);
+
+	ppc_md.setup_arch();
+
+	paging_init();
+	ppc_md.progress("setup_arch: exit", 0x3eab);
+}
+
+/* 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 ppc64_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);
+	for (i = 0; i < 2; i++)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+        for (i = 0; i < 4; i++)
+                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; i++)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	for (i = 0; i < 32; i++)
+		id->words94_125[i]  = __le16_to_cpu(id->words94_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	for (i = 0; i < 96; i++)
+		id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
+}
+
+
+void exception_trace(unsigned long trap)
+{
+	unsigned long x, srr0, srr1, reg20, reg1, reg21;
+
+	asm("mflr %0" : "=r" (x) :);
+	asm("mfspr %0,0x1a" : "=r" (srr0) :);
+	asm("mfspr %0,0x1b" : "=r" (srr1) :);
+	asm("mr %0,1" : "=r" (reg1) :);
+	asm("mr %0,20" : "=r" (reg20) :);
+	asm("mr %0,21" : "=r" (reg21) :);
+
+	udbg_puts("\n");
+	udbg_puts("Took an exception : "); udbg_puthex(x); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(reg1); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(reg20); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(reg21); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(srr0); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(srr1); udbg_puts("\n");
+}
+
+int set_spread_lpevents( char * str )
+{
+	/* The parameter is the number of processors to share in processing lp events */
+	unsigned long i;
+	unsigned long val = simple_strtoul( str, NULL, 0 );
+	if ( ( val > 0 ) && ( val <= maxPacas ) ) {
+		for ( i=1; i<val; ++i )
+			xPaca[i].lpQueuePtr = xPaca[0].lpQueuePtr;
+		printk("lpevent processing spread over %ld processors\n", val);
+	}
+	else
+		printk("invalid spreaqd_lpevents %ld\n", val);
+	return 1;
+}	
+
+/* This should only be called on processor 0 during calibrate decr */
+void setup_default_decr(void)
+{
+	struct Paca * paca = (struct Paca *)mfspr(SPRG3);
+
+	if ( decr_overclock_set && !decr_overclock_proc0_set )
+		decr_overclock_proc0 = decr_overclock;
+
+	paca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;	
+	paca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
+}
+
+int set_decr_overclock_proc0( char * str )
+{
+	unsigned long val = simple_strtoul( str, NULL, 0 );
+	if ( ( val >= 1 ) && ( val <= 48 ) ) {
+		decr_overclock_proc0_set = 1;
+		decr_overclock_proc0 = val;
+		printk("proc 0 decrementer overclock factor of %ld\n", val);
+	}
+	else
+		printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
+	return 1;
+}
+
+int set_decr_overclock( char * str )
+{
+	unsigned long val = simple_strtoul( str, NULL, 0 );
+	if ( ( val >= 1 ) && ( val <= 48 ) ) {
+		decr_overclock_set = 1;
+		decr_overclock = val;
+		printk("decrementer overclock factor of %ld\n", val);
+	}
+	else
+		printk("invalid decrementer overclock factor of %ld\n", val);
+	return 1;
+
+}
+
+__setup("spread_lpevents=", set_spread_lpevents );
+__setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
+__setup("decr_overclock=", set_decr_overclock );
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/signal.c linux-2.4.19-pre5/arch/ppc64/kernel/signal.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/signal.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/signal.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,794 @@
+/*
+ *  linux/arch/ppc64/kernel/signal.c
+ *
+ *  
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/kernel/signal.c"
+ *    Copyright (C) 1991, 1992 Linus Torvalds
+ *    1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *
+ *  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/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/elf.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/ppcdebug.h>
+#include <asm/unistd.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+
+/* 
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack.  SE and BE
+ * should not be in this list since gdb may want to change these.  I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
+extern long sys_wait4(pid_t pid, unsigned int *stat_addr,
+		     int options, /*unsigned long*/ struct rusage *ru);
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+		return -EFAULT;
+	if (from->si_code < 0)
+		return __copy_to_user(to, from, sizeof(siginfo_t));
+	else {
+		int err;
+
+		/* If you change siginfo_t structure, please be sure
+		   this code is fixed accordingly.
+		   It should never copy any pad contained in the structure
+		   to avoid security leaks, but must copy the generic
+		   3 ints plus the relevant union member.  */
+		err = __put_user(from->si_signo, &to->si_signo);
+		err |= __put_user(from->si_errno, &to->si_errno);
+		err |= __put_user((short)from->si_code, &to->si_code);
+		/* First 32bits of unions are always present.  */
+		err |= __put_user(from->si_pid, &to->si_pid);
+		switch (from->si_code >> 16) {
+		case __SI_FAULT >> 16:
+			break;
+		case __SI_CHLD >> 16:
+			err |= __put_user(from->si_utime, &to->si_utime);
+			err |= __put_user(from->si_stime, &to->si_stime);
+			err |= __put_user(from->si_status, &to->si_status);
+		default:
+			err |= __put_user(from->si_uid, &to->si_uid);
+			break;
+		/* case __SI_RT: This is not generated by the kernel as of now.  */
+		}
+		return err;
+	}
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
+	       struct pt_regs *regs)
+{
+	sigset_t saveset;
+  
+        PPCDBG(PPCDBG_SYS64X, "sys_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
+                current->pid, current, current->comm);
+
+
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	regs->gpr[3] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, regs))
+			/*
+			 * If a signal handler needs to be called,
+			 * do_signal() has set R3 to the signal number (the
+			 * first argument of the signal handler), so don't
+			 * overwrite that with EINTR !
+			 * In the other cases, do_signal() doesn't touch 
+			 * R3, so it's still set to -EINTR (see above).
+			 */
+			return regs->gpr[3];
+	}
+}
+
+long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
+		  int p7, struct pt_regs *regs)
+{
+	sigset_t saveset, newset;
+
+  
+        PPCDBG(PPCDBG_SYS64X, "sys_rt_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
+                current->pid, current, current->comm);
+	
+  /* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	regs->gpr[3] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, regs))
+			return regs->gpr[3];
+	}
+}
+
+
+
+asmlinkage long sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+  struct pt_regs *regs = (struct pt_regs *) &uss;
+  
+  PPCDBG(PPCDBG_SYS64X, "sys_sigaltstack - running - pid=%ld current=%lx comm=%s \n",
+          current->pid, current, current->comm);
+
+  return do_sigaltstack(uss, uoss, regs->gpr[1]);
+}
+
+long sys_sigaction(int sig, const struct old_sigaction *act,
+	      struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+        PPCDBG(PPCDBG_SYS64X, "sys_sigaction - running - pid=%ld current=%lx comm=%s \n",
+                current->pid, current, current->comm);
+
+ 
+
+	if (act) {
+		old_sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+
+ 
+
+	return ret;
+}
+
+/*
+ * When we have signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ *	a sigregs struct
+ *	one or more sigcontext structs
+ *	a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+ * XXX ultimately we will have to stack up a siginfo and ucontext
+ * for each rt signal.
+ */
+struct sigregs {
+	elf_gregset_t	gp_regs;
+	double		fp_regs[ELF_NFPREG];
+	unsigned int	tramp[2];
+	/* 64 bit API allows for 288 bytes below sp before 
+	   decrementing it. */
+	int		abigap[72];
+};
+
+
+
+struct rt_sigframe
+{
+	unsigned long	_unused[2];
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+};
+
+
+/*
+ *  When we have rt signals to deliver, we set up on the
+ *  user stack, going down from the original stack pointer:
+ *	   a sigregs struct
+ *	   one rt_sigframe struct (siginfo + ucontext)
+ *	   a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ *  Each of these things must be a multiple of 16 bytes in size.
+ *
+ */
+
+int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		     unsigned long r6, unsigned long r7, unsigned long r8,
+		     struct pt_regs *regs)
+{
+	struct rt_sigframe *rt_sf;
+	struct sigcontext_struct sigctx;
+	struct sigregs *sr;
+	int ret;
+	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+	sigset_t set;
+	stack_t st;
+	unsigned long prevsp;
+
+	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
+	    || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
+	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	rt_sf++;			/* Look at next rt_sigframe */
+	if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
+		/* Last stacked signal - restore registers -
+		 * sigctx is initialized to point to the 
+		 * preamble frame (where registers are stored) 
+		 * see handle_signal()
+		 */
+		sr = (struct sigregs *) sigctx.regs;
+		if (regs->msr & MSR_FP )
+			giveup_fpu(current);
+		if (copy_from_user(saved_regs, &sr->gp_regs,
+				   sizeof(sr->gp_regs)))
+			goto badframe;
+		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+		saved_regs[PT_SOFTE] = regs->softe;
+		memcpy(regs, saved_regs, GP_REGS_SIZE);
+		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+				   sizeof(sr->fp_regs)))
+			goto badframe;
+		/* This function sets back the stack flags into
+		   the current task structure.  */
+		sys_sigaltstack(&st, NULL);
+
+		ret = regs->result;
+	} else {
+		/* More signals to go */
+		/* Set up registers for next signal handler */
+		regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
+		if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
+			goto badframe;
+		sr = (struct sigregs *) sigctx.regs;
+		regs->gpr[3] = ret = sigctx.signal;
+		/* Get the siginfo   */
+		get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
+		/* Get the ucontext */
+		get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
+		regs->gpr[6] = (unsigned long) rt_sf;
+
+		regs->link = (unsigned long) &sr->tramp;
+		regs->nip = sigctx.handler;
+		if (get_user(prevsp, &sr->gp_regs[PT_R1])
+		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+			goto badframe;
+	}
+	return ret;
+
+badframe:
+	do_exit(SIGSEGV);
+}
+
+static void
+setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
+	       signed long newsp)
+{
+	struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
+	/* Handler is *really* a pointer to the function descriptor for
+	 * the signal routine.  The first entry in the function
+	 * descriptor is the entry address of signal and the second
+	 * entry is the TOC value we need to use.
+	 */
+        struct funct_descr_entry {
+                     unsigned long entry;
+                     unsigned long toc;
+	};
+  
+	struct funct_descr_entry * funct_desc_ptr;
+	unsigned long temp_ptr;
+
+	/* Set up preamble frame */
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto badframe;
+	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->thread.fpr,
+			      ELF_NFPREG * sizeof(double))
+	    || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])	/* li r0, __NR_rt_sigreturn */
+	    || __put_user(0x44000002UL, &frame->tramp[1]))	/* sc */
+		goto badframe;
+	flush_icache_range((unsigned long) &frame->tramp[0],
+			   (unsigned long) &frame->tramp[2]);
+
+	/* Retrieve rt_sigframe from stack and
+	   set up registers for signal handler
+	*/
+	newsp -= __SIGNAL_FRAMESIZE;
+
+        if ( get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) {
+		goto badframe;
+	}
+
+        funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
+        
+	if (put_user(regs->gpr[1], (unsigned long *)newsp)
+	    || get_user(regs->nip, &funct_desc_ptr->entry)
+            || get_user(regs->gpr[2], &funct_desc_ptr->toc)
+	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
+	    || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
+	    || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
+		goto badframe;
+
+	regs->gpr[1] = newsp;
+	regs->gpr[6] = (unsigned long) rt_sf;
+	regs->link = (unsigned long) frame->tramp;
+
+	
+	return;
+
+badframe:
+#if DEBUG_SIG
+	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
+	       regs, frame, newsp);
+#endif
+	do_exit(SIGSEGV);
+}
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7, unsigned long r8,
+		   struct pt_regs *regs)
+{
+	struct sigcontext_struct *sc, sigctx;
+	struct sigregs *sr;
+	long ret;
+	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+	sigset_t set;
+	unsigned long prevsp;
+
+        sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+		goto badframe;
+
+	set.sig[0] = sigctx.oldmask;
+#if _NSIG_WORDS > 1
+	set.sig[1] = sigctx._unused[3];
+#endif
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	sc++;			/* Look at next sigcontext */
+	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+		/* Last stacked signal - restore registers */
+		sr = (struct sigregs *) sigctx.regs;
+		if (regs->msr & MSR_FP )
+			giveup_fpu(current);
+		if (copy_from_user(saved_regs, &sr->gp_regs,
+				   sizeof(sr->gp_regs)))
+			goto badframe;
+		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+		saved_regs[PT_SOFTE] = regs->softe;
+		memcpy(regs, saved_regs, GP_REGS_SIZE);
+
+		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+				   sizeof(sr->fp_regs)))
+			goto badframe;
+
+		ret = regs->result;
+
+	} else {
+		/* More signals to go */
+		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+			goto badframe;
+		sr = (struct sigregs *) sigctx.regs;
+		regs->gpr[3] = ret = sigctx.signal;
+		regs->gpr[4] = (unsigned long) sc;
+		regs->link = (unsigned long) &sr->tramp;
+		regs->nip = sigctx.handler;
+
+		if (get_user(prevsp, &sr->gp_regs[PT_R1])
+		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+			goto badframe;
+	}
+	return ret;
+
+badframe:
+	do_exit(SIGSEGV);
+}	
+
+/*
+ * Set up a signal frame.
+ */
+static void
+setup_frame(struct pt_regs *regs, struct sigregs *frame,
+            unsigned long newsp)
+{
+
+	/* Handler is *really* a pointer to the function descriptor for
+	 * the signal routine.  The first entry in the function
+	 * descriptor is the entry address of signal and the second
+	 * entry is the TOC value we need to use.
+	 */
+	struct funct_descr_entry {
+		unsigned long entry;
+		unsigned long toc;
+	};
+  
+	struct funct_descr_entry * funct_desc_ptr;
+	unsigned long temp_ptr;
+
+	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
+  
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto badframe;
+	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->thread.fpr,
+			      ELF_NFPREG * sizeof(double))
+	    || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
+	    || __put_user(0x44000002UL, &frame->tramp[1]))   /* sc */
+		goto badframe;
+	flush_icache_range((unsigned long) &frame->tramp[0],
+			   (unsigned long) &frame->tramp[2]);
+
+	newsp -= __SIGNAL_FRAMESIZE;
+	if ( get_user(temp_ptr, &sc->handler))
+		goto badframe;
+  
+	funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
+
+	if (put_user(regs->gpr[1], (unsigned long *)newsp)
+	    || get_user(regs->nip, & funct_desc_ptr ->entry)
+	    || get_user(regs->gpr[2],& funct_desc_ptr->toc)
+	    || get_user(regs->gpr[3], &sc->signal))
+		goto badframe;
+	regs->gpr[1] = newsp;
+	regs->gpr[4] = (unsigned long) sc;
+	regs->link = (unsigned long) frame->tramp;
+
+
+	PPCDBG(PPCDBG_SIGNAL, "setup_frame - returning - regs->gpr[1]=%lx, regs->gpr[4]=%lx, regs->link=%lx \n",
+	       regs->gpr[1], regs->gpr[4], regs->link);
+
+	return;
+
+ badframe:
+	PPCDBG(PPCDBG_SIGNAL, "setup_frame - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
+#if DEBUG_SIG
+	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
+	       regs, frame, newsp);
+#endif
+	do_exit(SIGSEGV);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
+	      unsigned long *newspp, unsigned long frame)
+{
+	struct sigcontext_struct *sc;
+        struct rt_sigframe *rt_sf;
+
+	if (regs->trap == 0x0C00 /* System Call! */
+	    && ((int)regs->result == -ERESTARTNOHAND ||
+		((int)regs->result == -ERESTARTSYS &&
+		 !(ka->sa.sa_flags & SA_RESTART))))
+		regs->result = -EINTR;
+        /* Set up Signal Frame */
+     
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+		/* Put a Real Time Context onto stack */
+		*newspp -= sizeof(*rt_sf);
+		rt_sf = (struct rt_sigframe *) *newspp;
+		if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
+			goto badframe;
+                
+
+		if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
+		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
+		    || __put_user(&rt_sf->uc, &rt_sf->puc)
+		    /* Put the siginfo */
+		    || __copy_to_user(&rt_sf->info, info, sizeof(*info))
+		    /* Create the ucontext */
+		    || __put_user(0, &rt_sf->uc.uc_flags)
+		    || __put_user(0, &rt_sf->uc.uc_link)
+		    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
+		    || __put_user(sas_ss_flags(regs->gpr[1]), 
+				  &rt_sf->uc.uc_stack.ss_flags)
+		    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+		    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
+		    /* mcontext.regs points to preamble register frame */
+		    || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
+		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
+			goto badframe;
+               
+	} else {
+	        /* Put another sigcontext on the stack */
+                *newspp -= sizeof(*sc);
+        	sc = (struct sigcontext_struct *) *newspp;
+        	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+	        	goto badframe;
+
+        	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+	           || __put_user(oldset->sig[0], &sc->oldmask)
+#if _NSIG_WORDS > 1
+	           || __put_user(oldset->sig[1], &sc->_unused[3])
+#endif
+	           || __put_user((struct pt_regs *)frame, &sc->regs)
+	           || __put_user(sig, &sc->signal))
+	        	goto badframe;
+	}
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+	return;
+
+badframe:
+#if DEBUG_SIG
+	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
+	       regs, frame, *newspp);
+	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
+#endif
+	do_exit(SIGSEGV);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+int do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+	unsigned long frame, newsp;
+
+	/*
+	 * If the current thread is 32 bit - invoke the
+	 * 32 bit signal handling code
+	 */
+	if (current->thread.flags & PPC_FLAG_32BIT)
+		return do_signal32(oldset, regs);
+  
+        PPCDBG(PPCDBG_SIGNAL, "do_signal - running - pid=%ld current=%lx comm=%s \n", 
+               current->pid, current, current->comm);
+
+  
+
+        if (!oldset)
+		oldset = &current->blocked;
+
+	newsp = frame = 0;
+
+	for (;;) {
+		unsigned long signr;
+
+                PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+                PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm);
+
+		if (!signr)
+			break;
+
+		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current, SIGCHLD);
+			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
+			if (signr == SIGSTOP)
+				continue;
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
+				continue;
+			}
+		}
+
+		ka = &current->sig->action[signr-1];
+
+  
+                PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler);
+
+		if (ka->sa.sa_handler == SIG_IGN) {
+                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n");
+			if (signr != SIGCHLD)
+				continue;
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				/* nothing */;
+			continue;
+		}
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n");
+
+			/* Init gets no signals it doesn't want.  */
+			if (current->pid == 1)
+				continue;
+
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+				/* FALLTHRU */
+
+			case SIGSTOP:
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+					notify_parent(current, SIGCHLD);
+				schedule();
+				continue;
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
+				/* FALLTHRU */
+
+			default:
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
+				/* NOTREACHED */
+			}
+		}
+
+		if ( (ka->sa.sa_flags & SA_ONSTACK)
+		     && (! on_sig_stack(regs->gpr[1])))
+			newsp = (current->sas_ss_sp + current->sas_ss_size);
+		else
+			newsp = regs->gpr[1];
+		newsp = frame = newsp - sizeof(struct sigregs);
+
+		/* Whee!  Actually deliver the signal.  */
+  
+                PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
+                PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+                break;
+	}
+
+	if (regs->trap == 0x0C00 /* System Call! */ &&
+	    ((int)regs->result == -ERESTARTNOHAND ||
+	     (int)regs->result == -ERESTARTSYS ||
+	     (int)regs->result == -ERESTARTNOINTR)) {
+                PPCDBG(PPCDBG_SIGNAL, "do_signal - going to back up & retry system call \n");
+		regs->gpr[3] = regs->orig_gpr3;
+		regs->nip -= 4;		/* Back up & retry system call */
+		regs->result = 0;
+	}
+
+	if (newsp == frame)
+          {
+             PPCDBG(PPCDBG_SIGNAL, "do_signal - returning w/ no signal delivered \n");
+             return 0;		/* no signals delivered */
+           }
+  
+     
+
+        if (ka->sa.sa_flags & SA_SIGINFO)
+             setup_rt_frame(regs, (struct sigregs *) frame, newsp);
+        else        
+	    setup_frame(regs, (struct sigregs *) frame, newsp);
+        PPCDBG(PPCDBG_SIGNAL, "do_signal - returning a signal was delivered \n");
+	return 1;
+}
+
+
+
+
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/signal32.c linux-2.4.19-pre5/arch/ppc64/kernel/signal32.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/signal32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/signal32.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,1512 @@
+/*
+ * signal32.c: Support 32bit signal syscalls.
+ *
+ * Copyright (C) 2001 IBM
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment.
+ *
+ *      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 <asm/ptrace.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h> 
+#include <linux/mm.h> 
+#include <linux/file.h> 
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
+#include <linux/ncp_fs.h>
+#include <linux/quota.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/personality.h>
+#include <linux/stat.h>
+#include <linux/filter.h>
+#include <asm/types.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+#include <linux/elf.h>
+/* #include <asm/ppc32.h> */
+#include <asm/ppcdebug.h>
+#include <asm/unistd.h>
+#include <asm/ucontext.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+/* 
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack.  SE and BE
+ * should not be in this list since gdb may want to change these.  I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+
+
+
+
+/* Use this to get at 32-bit user passed pointers. */
+/* Things to consider: the low-level assembly stub does
+   srl x, 0, x for first four arguments, so if you have
+   pointer to something in the first four arguments, just
+   declare it as a pointer, not u32. On the other side, 
+   arguments from 5th onwards should be declared as u32
+   for pointers, and need AA() around each usage.
+   A() macro should be used for places where you e.g.
+   have some internal variable u32 and just want to get
+   rid of a compiler warning. AA() has to be used in
+   places where you want to convert a function argument
+   to 32bit pointer or when you e.g. access pt_regs
+   structure and want to consider 32bit registers only.
+   -
+ */
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x)				\
+({	unsigned long __ret;		\
+	__asm__ ("clrldi	%0, %0, 32"	\
+		 : "=r" (__ret)		\
+		 : "0" (__x));		\
+	__ret;				\
+})
+
+
+
+struct timespec32 {
+	s32    tv_sec;
+	s32    tv_nsec;
+};
+
+struct sigregs32 {
+    /***********************************************************************/
+    /* the gp_regs array is 32 bit representation of the pt_regs structure */
+    /*  that was stored on the kernle stack during the system call that    */
+    /*  was interrupted for the signal.                                    */
+    /*                                                                     */
+    /* Note that the entire pt_regs regs structure will fit in the gp_regs */
+    /*   structure because the ELF_NREG value is 48 for PPC and the pt_regs*/
+    /*   structure contains 44 registers                                   */
+    /*                                                                     */ 
+    /***********************************************************************/ 
+	elf_gregset_t32	gp_regs;
+	double		fp_regs[ELF_NFPREG];
+	unsigned int	tramp[2];
+	/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
+	   and 18 fp regs below sp before decrementing it. */
+	int		abigap[56];
+};
+
+
+struct rt_sigframe_32 {
+	/* Unused space at start of frame to allow for storing of stack pointers */
+	unsigned long _unused;
+	/* This is a 32 bit pointer in user address space 
+	 *     it is a pointer to the siginfo stucture in the rt stack frame 
+	 */
+	u32 pinfo;
+	/* This is a 32 bit pointer in user address space */
+	/*     it is a pointer to the user context in the rt stack frame  */
+	u32 puc;
+	struct siginfo32  info;
+	struct ucontext32 uc;
+};
+
+
+
+
+
+extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
+
+
+/****************************************************************************/
+/*  Start of nonRT signal support                                           */
+/*                                                                          */
+/*     sigset_t is 32 bits for non-rt signals                               */
+/*                                                                          */
+/*  System Calls                                                            */
+/*       sigaction                sys32_sigaction                           */
+/*       sigpending               sys32_sigpending                          */
+/*       sigprocmask              sys32_sigprocmask                         */
+/*       sigreturn                sys32_sigreturn                           */
+/*                                                                          */
+/*  Note sigsuspend has no special 32 bit routine - uses the 64 bit routine */ 
+/*                                                                          */
+/*  Other routines                                                          */
+/*        setup_frame32                                                     */
+/*                                                                          */
+/****************************************************************************/
+
+
+asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	if (sig < 0)
+	{
+		sig = -sig;
+	}
+
+	if (act)
+	{
+		old_sigset_t32 mask;
+
+		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		ret |= __get_user(mask, &act->sa_mask);
+		if (ret)
+			return ret;
+		PPCDBG(PPCDBG_SIGNAL, "sys32_sigaction flags =%lx  \n", new_ka.sa.sa_flags);
+
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact)
+	{
+		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
+		ret |= __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer);
+		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return ret;
+}
+
+
+
+
+extern asmlinkage long sys_sigpending(old_sigset_t *set);
+
+asmlinkage long sys32_sigpending(old_sigset_t32 *set)
+{
+	old_sigset_t s;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sigpending - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+		
+	set_fs (KERNEL_DS);
+	ret = sys_sigpending(&s);
+	set_fs (old_fs);
+	if (put_user (s, set)) return -EFAULT;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sigpending - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return ret;
+}
+
+
+
+
+extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset);
+
+/* Note: it is necessary to treat how as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sigprocmask(u32 how, old_sigset_t32 *set, old_sigset_t32 *oset)
+{
+	old_sigset_t s;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+	
+	if (set && get_user (s, set)) return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL);
+	set_fs (old_fs);
+	if (ret) return ret;
+	if (oset && put_user (s, oset)) return -EFAULT;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return 0;
+}
+
+
+
+/*
+ * When we have signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ *	a sigregs struct
+ *	one or more sigcontext structs
+ *	a gap of __SIGNAL_FRAMESIZE32 bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+*/
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+long sys32_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		     unsigned long r6, unsigned long r7, unsigned long r8,
+		     struct pt_regs *regs)
+{
+	struct sigcontext32_struct *sc, sigctx;
+	struct sigregs32 *sr;
+	int ret;
+	elf_gregset_t32 saved_regs;  /* an array of ELF_NGREG unsigned ints (32 bits) */
+	sigset_t set;
+	unsigned int prevsp;
+
+	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	sc = (struct sigcontext32_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
+	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+		goto badframe;
+
+	/* Note that PPC32 puts the upper 32 bits of the sigmask in the  */
+	/*   unused part of the signal stackframe                        */
+	set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3])<< 32);
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	sc++;			/* Look at next sigcontext */
+	/* If the next sigcontext is actually the sigregs (frame)  */
+	/*   - then no more sigcontexts on the user stack          */  
+	if (sc == (struct sigcontext32_struct*)(u64)sigctx.regs)
+	{
+		/* Last stacked signal - restore registers */
+		sr = (struct sigregs32*)(u64)sigctx.regs;
+		if (regs->msr & MSR_FP )
+			giveup_fpu(current);
+		/* copy the 32 bit register values off the user stack */
+		/*   into the 32 bit register area                    */
+		if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs)))
+			goto badframe;
+		/**********************************************************************/
+		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
+		/*   a 32 bit register save of the registers in the pt_regs structure */
+		/*   that was stored on the kernel stack during the system call       */
+		/*   when the system call was interrupted for the signal. Only 32 bits*/
+		/*   are saved because the sigcontext contains a pointer to the regs  */
+		/*   and the sig context address is passed as a pointer to the signal */
+		/*   handler.                                                         */
+		/*                                                                    */
+		/* The entries in the elf_grepset have the same index as the elements */
+		/*   in the pt_regs structure.                                        */
+		/*                                                                    */
+		/**********************************************************************/
+
+		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
+		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
+		/**********************************************************************/
+		/* Register 2 is the kernel toc - should be reset on any calls into   */
+		/*  the kernel                                                        */
+		/**********************************************************************/
+		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
+
+		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
+		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
+		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
+		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
+		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
+		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
+		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
+		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
+		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
+		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
+		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
+		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
+		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
+		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
+		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
+		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
+		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
+		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
+		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
+		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
+		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
+		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
+		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
+		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
+		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
+		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
+		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
+		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
+		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
+		/****************************************************/
+		/*  restore the non gpr registers                   */
+		/****************************************************/
+		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
+		/* Insure that the interrupt mode is 64 bit, during 32 bit execution.
+		 * (This is necessary because we only saved lower 32 bits of msr.)
+		 */
+		regs->msr = regs->msr | MSR_ISF;  /* When this thread is interrupted it should run in 64 bit mode. */
+
+		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
+		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
+		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
+		regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
+		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
+		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
+		/* regs->softe is left unchanged (like the MSR.EE bit) */
+		/******************************************************/
+		/* the DAR and the DSISR are only relevant during a   */
+		/*   data or instruction storage interrupt. The value */
+		/*   will be set to zero.                             */
+		/******************************************************/
+		regs->dar = 0; 
+		regs->dsisr = 0;
+		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+		if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs)))
+			goto badframe;
+
+		ret = regs->result;
+	} else {
+		/* More signals to go */
+		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE32;
+		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+			goto badframe;
+		sr = (struct sigregs32*)(u64)sigctx.regs;
+		regs->gpr[3] = ret = sigctx.signal;
+		regs->gpr[4] = (unsigned long) sc;
+		regs->link = (unsigned long) &sr->tramp;
+		regs->nip = sigctx.handler;
+
+		if (get_user(prevsp, &sr->gp_regs[PT_R1])
+		    || put_user(prevsp, (unsigned int*) regs->gpr[1]))
+			goto badframe;
+	}
+  
+	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - normal exit returning %ld - pid=%ld current=%lx comm=%s \n", ret, current->pid, current, current->comm);
+	return ret;
+
+badframe:
+	PPCDBG(PPCDBG_SYS32NI, "sys32_sigreturn - badframe - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	do_exit(SIGSEGV);
+}	
+
+/*
+ * Set up a signal frame.
+ */
+static void
+setup_frame32(struct pt_regs *regs, struct sigregs32 *frame,
+            unsigned int newsp)
+{
+	struct sigcontext32_struct *sc = (struct sigcontext32_struct *)(u64)newsp;
+
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto badframe;
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	/***************************************************************/
+	/*                                                             */ 
+	/* Copy the register contents for the pt_regs structure on the */
+	/*   kernel stack to the elf_gregset_t32 structure on the user */
+	/*   stack. This is a copy of 64 bit register values to 32 bit */
+	/*   register values. The high order 32 bits of the 64 bit     */
+	/*   registers are not needed since a 32 bit application is    */
+	/*   running and the saved registers are the contents of the   */
+	/*   user registers at the time of a system call.              */
+	/*                                                             */
+	/* The values saved on the user stack will be restored into    */
+	/*  the registers during the signal return processing          */
+	/*                                                             */
+	/* Note the +1 is needed in order to get the lower 32 bits     */
+	/*  of 64 bit register                                         */
+	/***************************************************************/
+	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
+		goto badframe;
+
+  /*****************************************************************************/
+  /* Copy the non gpr registers to the user stack                              */
+  /*****************************************************************************/
+
+	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
+			      sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(&regs->gpr[PT_CTR])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(&regs->gpr[PT_LNK])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(&regs->gpr[PT_XER])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(&regs->gpr[PT_CCR])+1, sizeof(u32))
+# if 0
+	    || __copy_to_user(&frame->gp_regs[PT_MQ], (u32*)(&regs->gpr[PT_MQ])+1, sizeof(u32))
+#endif
+	    || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(&regs->gpr[PT_RESULT])+1,
+			      sizeof(u32)))
+		goto badframe;
+
+
+	/*****************************************************************************/
+	/* Now copy the floating point registers onto the user stack                 */
+	/*                                                                           */
+	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
+	/*   will get control to reset the stack                                     */
+	/*****************************************************************************/
+	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
+			   ELF_NFPREG * sizeof(double))
+	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
+	    || __put_user(0x44000002U, &frame->tramp[1]))   /* sc */
+		goto badframe;
+
+	flush_icache_range((unsigned long) &frame->tramp[0],
+			   (unsigned long) &frame->tramp[2]);
+
+	newsp -= __SIGNAL_FRAMESIZE32;
+	if (put_user(regs->gpr[1], (u32*)(u64)newsp)
+	    || get_user(regs->nip, &sc->handler)
+	    || get_user(regs->gpr[3], &sc->signal))
+		goto badframe;
+
+	regs->gpr[1] = newsp & 0xFFFFFFFF;
+	/**************************************************************/
+	/* first parameter to the signal handler is the signal number */
+	/*  - the value is in gpr3                                    */  
+	/* second parameter to the signal handler is the sigcontext   */
+	/*   - set the value into gpr4                                */ 
+	/**************************************************************/
+	regs->gpr[4] = (unsigned long) sc;
+	regs->link = (unsigned long) frame->tramp;
+	return;
+
+ badframe:
+	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
+#if DEBUG_SIG
+	printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n",
+	       regs, frame, newsp);
+#endif
+	do_exit(SIGSEGV);
+}
+
+
+/****************************************************************************/
+/*  Start of RT signal support                                              */
+/*                                                                          */
+/*     sigset_t is 64 bits for rt signals                                   */
+/*                                                                          */
+/*  System Calls                                                            */
+/*       sigaction                sys32_rt_sigaction                        */
+/*       sigpending               sys32_rt_sigpending                       */
+/*       sigprocmask              sys32_rt_sigprocmask                      */
+/*       sigreturn                sys32_rt_sigreturn                        */
+/*       sigtimedwait             sys32_rt_sigtimedwait                     */
+/*       sigqueueinfo             sys32_rt_sigqueueinfo                     */
+/*       sigsuspend               sys32_rt_sigsuspend                       */ 
+/*                                                                          */
+/*  Other routines                                                          */
+/*        setup_rt_frame32                                                  */
+/*        siginfo64to32                                                     */
+/*        siginfo32to64                                                     */
+/*                                                                          */
+/*                                                                          */
+/****************************************************************************/
+
+
+// This code executes after the rt signal handler in 32 bit mode has completed and 
+//  returned  
+long sys32_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+			unsigned long r6, unsigned long r7, unsigned long r8,
+			struct pt_regs * regs)
+{
+	struct rt_sigframe_32 *rt_stack_frame;
+	struct sigcontext32_struct sigctx;
+	struct sigregs32 *signalregs;
+ 
+	int ret;
+	elf_gregset_t32 saved_regs;   /* an array of 32 bit register values */
+	sigset_t signal_set; 
+	stack_t stack;
+	unsigned int previous_stack;
+
+	ret = 0;
+	/* Adjust the inputted reg1 to point to the first rt signal frame */
+	rt_stack_frame = (struct rt_sigframe_32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
+	/* Copy the information from the user stack  */
+	if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))
+	    || copy_from_user(&signal_set, &rt_stack_frame->uc.uc_sigmask,sizeof(signal_set))
+	    || copy_from_user(&stack,&rt_stack_frame->uc.uc_stack,sizeof(stack)))
+	{
+		/* unable to copy from user storage */
+		goto badframe;
+	}
+
+	/* Unblock the signal that was processed 
+	 *   After a signal handler runs - 
+	 *     if the signal is blockable - the signal will be unblocked  
+	 *       ( sigkill and sigstop are not blockable)
+	 */
+	sigdelsetmask(&signal_set, ~_BLOCKABLE); 
+	/* update the current based on the sigmask found in the rt_stackframe */
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = signal_set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	/* Set to point to the next rt_sigframe - this is used to determine whether this 
+	 *   is the last signal to process
+	 */
+	rt_stack_frame ++;
+
+	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs))
+	{
+		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
+		/* If currently owning the floating point - give them up */
+		if (regs->msr & MSR_FP)
+		{
+			giveup_fpu(current);
+		}
+		if (copy_from_user(saved_regs,&signalregs->gp_regs,sizeof(signalregs->gp_regs))) 
+		{
+			goto badframe;
+		}
+		/**********************************************************************/
+		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
+		/*   a 32 bit register save of the registers in the pt_regs structure */
+		/*   that was stored on the kernel stack during the system call       */
+		/*   when the system call was interrupted for the signal. Only 32 bits*/
+		/*   are saved because the sigcontext contains a pointer to the regs  */
+		/*   and the sig context address is passed as a pointer to the signal */
+		/*   handler.                                                         */
+		/*                                                                    */
+		/* The entries in the elf_grepset have the same index as the elements */
+		/*   in the pt_regs structure.                                        */
+		/*                                                                    */
+		/**********************************************************************/
+
+		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
+		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
+		/**********************************************************************/
+		/* Register 2 is the kernel toc - should be reset on any calls into   */
+		/*  the kernel                                                        */
+		/**********************************************************************/
+		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
+ 
+		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
+		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
+		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
+		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
+		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
+		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
+		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
+		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
+		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
+		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
+		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
+		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
+		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
+		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
+		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
+		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
+		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
+		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
+		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
+		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
+		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
+		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
+		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
+		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
+		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
+		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
+		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
+		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
+		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
+		/****************************************************/
+		/*  restore the non gpr registers                   */
+		/****************************************************/
+		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
+
+		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
+		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
+		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
+		regs->link = (u64)(saved_regs[PT_LNK]) & 0xFFFFFFFF; 
+		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
+		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
+		/* regs->softe is left unchanged (like MSR.EE) */
+		/******************************************************/
+		/* the DAR and the DSISR are only relevant during a   */
+		/*   data or instruction storage interrupt. The value */
+		/*   will be set to zero.                             */
+		/******************************************************/
+		regs->dar = 0; 
+		regs->dsisr = 0;
+		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+		ret = regs->result;
+	}
+	else  /* more signals to go  */
+	{
+		regs->gpr[1] = (u64)rt_stack_frame - __SIGNAL_FRAMESIZE32;
+		if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx)))
+		{
+			goto badframe;
+		}
+		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
+		/* first parm to signal handler is the signal number */
+		regs->gpr[3] = ret = sigctx.signal;
+		/* second parm is a pointer to sig info */
+		get_user(regs->gpr[4], &rt_stack_frame->pinfo);
+		/* third parm is a pointer to the ucontext */
+		get_user(regs->gpr[5], &rt_stack_frame->puc);
+		/* fourth parm is the stack frame */
+		regs->gpr[6] = (u64)rt_stack_frame;
+		/* Set up link register to return to sigreturn when the */
+		/*  signal handler completes */
+		regs->link = (u64)&signalregs->tramp;
+		/* Set next instruction to the start fo the signal handler */
+		regs->nip = sigctx.handler;
+		/* Set the reg1 to look like a call to the signal handler */
+		if (get_user(previous_stack,&signalregs->gp_regs[PT_R1])
+		    || put_user(previous_stack, (unsigned long *)regs->gpr[1]))
+		{
+			goto badframe;
+		}
+
+	}
+
+	return ret;
+
+ badframe:
+	do_exit(SIGSEGV);     
+}
+
+
+
+asmlinkage long sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact, size_t sigsetsize)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+	sigset32_t set32;
+
+	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - entered - sig=%x \n", sig);
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset32_t))
+		return -EINVAL;
+
+	if (act) {
+		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret |= __copy_from_user(&set32, &act->sa_mask,
+					sizeof(sigset32_t));
+		switch (_NSIG_WORDS) {
+		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
+				| (((long)set32.sig[7]) << 32);
+		case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
+				| (((long)set32.sig[5]) << 32);
+		case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
+				| (((long)set32.sig[3]) << 32);
+		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
+				| (((long)set32.sig[1]) << 32);
+		}
+
+		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		
+		if (ret)
+			return -EFAULT;
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		switch (_NSIG_WORDS) {
+		case 4:
+			set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
+			set32.sig[6] = old_ka.sa.sa_mask.sig[3];
+		case 3:
+			set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
+			set32.sig[4] = old_ka.sa.sa_mask.sig[2];
+		case 2:
+			set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
+			set32.sig[2] = old_ka.sa.sa_mask.sig[1];
+		case 1:
+			set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
+			set32.sig[0] = old_ka.sa.sa_mask.sig[0];
+		}
+		ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
+		ret |= __copy_to_user(&oact->sa_mask, &set32,
+				      sizeof(sigset32_t));
+		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+	}
+
+  
+	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigaction - exiting - sig=%x \n", sig);
+	return ret;
+}
+
+
+extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
+					  size_t sigsetsize);
+
+/* Note: it is necessary to treat how as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_rt_sigprocmask(u32 how, sigset32_t *set, sigset32_t *oset, size_t sigsetsize)
+{
+	sigset_t s;
+	sigset32_t s32;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	PPCDBG(PPCDBG_SIGNAL, "sys32_rt_sigprocmask - entered how=%x \n", (int)how);
+	
+	if (set) {
+		if (copy_from_user (&s32, set, sizeof(sigset32_t)))
+			return -EFAULT;
+    
+		switch (_NSIG_WORDS) {
+		case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+		case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+		case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+		case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+		}
+	}
+	
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL,
+				 sigsetsize); 
+	set_fs (old_fs);
+	if (ret) return ret;
+	if (oset) {
+		switch (_NSIG_WORDS) {
+		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+		}
+		if (copy_to_user (oset, &s32, sizeof(sigset32_t)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+
+extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
+
+
+
+asmlinkage long sys32_rt_sigpending(sigset32_t *set,   __kernel_size_t32 sigsetsize)
+{
+
+	sigset_t s;
+	sigset32_t s32;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+		
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigpending(&s, sigsetsize);
+	set_fs (old_fs);
+	if (!ret) {
+		switch (_NSIG_WORDS) {
+		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+		}
+		if (copy_to_user (set, &s32, sizeof(sigset32_t)))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+
+
+siginfo_t32 *
+siginfo64to32(siginfo_t32 *d, siginfo_t *s)
+{
+	memset (d, 0, sizeof(siginfo_t32));
+	d->si_signo = s->si_signo;
+	d->si_errno = s->si_errno;
+	d->si_code = s->si_code;
+	if (s->si_signo >= SIGRTMIN) {
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		
+		d->si_int = s->si_int;
+	} else switch (s->si_signo) {
+	/* XXX: What about POSIX1.b timers */
+	case SIGCHLD:
+		d->si_pid = s->si_pid;
+		d->si_status = s->si_status;
+		d->si_utime = s->si_utime;
+		d->si_stime = s->si_stime;
+		break;
+	case SIGSEGV:
+	case SIGBUS:
+	case SIGFPE:
+	case SIGILL:
+		d->si_addr = (long)(s->si_addr);
+        break;
+	case SIGPOLL:
+		d->si_band = s->si_band;
+		d->si_fd = s->si_fd;
+		break;
+	default:
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		break;
+	}
+	return d;
+}
+
+extern asmlinkage long
+sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
+		    const struct timespec *uts, size_t sigsetsize);
+
+asmlinkage long
+sys32_rt_sigtimedwait(sigset32_t *uthese, siginfo_t32 *uinfo,
+		      struct timespec32 *uts, __kernel_size_t32 sigsetsize)
+{
+	sigset_t s;
+	sigset32_t s32;
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	siginfo_t info;
+	siginfo_t32 info32;
+		
+	if (copy_from_user (&s32, uthese, sizeof(sigset32_t)))
+		return -EFAULT;
+	switch (_NSIG_WORDS) {
+	case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+	case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+	case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+	case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+	}
+	if (uts) {
+		ret = get_user (t.tv_sec, &uts->tv_sec);
+		ret |= __get_user (t.tv_nsec, &uts->tv_nsec);
+		if (ret)
+			return -EFAULT;
+	}
+	set_fs (KERNEL_DS);
+	if (uts) 
+	{
+		ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
+	} else {
+		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts, sigsetsize);
+	}
+	
+	set_fs (old_fs);
+	if (ret >= 0 && uinfo) {
+		if (copy_to_user (uinfo, siginfo64to32(&info32, &info),
+				  sizeof(siginfo_t32)))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+
+
+siginfo_t *
+siginfo32to64(siginfo_t *d, siginfo_t32 *s)
+{
+	d->si_signo = s->si_signo;
+	d->si_errno = s->si_errno;
+	d->si_code = s->si_code;
+	if (s->si_signo >= SIGRTMIN) {
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		d->si_int = s->si_int;
+        
+	} else switch (s->si_signo) {
+	/* XXX: What about POSIX1.b timers */
+	case SIGCHLD:
+		d->si_pid = s->si_pid;
+		d->si_status = s->si_status;
+		d->si_utime = s->si_utime;
+		d->si_stime = s->si_stime;
+		break;
+	case SIGSEGV:
+	case SIGBUS:
+	case SIGFPE:
+	case SIGILL:
+		d->si_addr = (void *)A(s->si_addr);
+  		break;
+	case SIGPOLL:
+		d->si_band = s->si_band;
+		d->si_fd = s->si_fd;
+		break;
+	default:
+		d->si_pid = s->si_pid;
+		d->si_uid = s->si_uid;
+		break;
+	}
+	return d;
+}
+
+
+extern asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
+
+/* Note: it is necessary to treat pid and sig as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_rt_sigqueueinfo(u32 pid, u32 sig, siginfo_t32 *uinfo)
+{
+	siginfo_t info;
+	siginfo_t32 info32;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
+		return -EFAULT;
+    	/* XXX: Is this correct? */
+	siginfo32to64(&info, &info32);
+
+	set_fs (KERNEL_DS);
+	ret = sys_rt_sigqueueinfo((int)pid, (int)sig, &info);
+	set_fs (old_fs);
+	return ret;
+}
+
+
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
+int sys32_rt_sigsuspend(sigset32_t* unewset, size_t sigsetsize, int p3, int p4, int p6, int p7, struct pt_regs *regs)
+{
+	sigset_t saveset, newset;
+	
+	sigset32_t s32;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&s32, unewset, sizeof(s32)))
+		return -EFAULT;
+
+	/* Swap the 2 words of the 64-bit sigset_t (they are stored in the "wrong" endian in 32-bit user storage). */
+	switch (_NSIG_WORDS) 
+	{
+		case 4: newset.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+		case 3: newset.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+		case 2: newset.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+		case 1: newset.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+	}
+
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	regs->gpr[3] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, regs))
+			return regs->gpr[3];
+	}
+}
+
+
+
+
+
+
+
+
+/*
+ * Set up a rt signal frame.
+ */
+static void
+setup_rt_frame32(struct pt_regs *regs, struct sigregs32 *frame,
+            unsigned int newsp)
+{
+	unsigned int copyreg4,copyreg5;
+	struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp;
+
+  
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto badframe;
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+	/***************************************************************/
+	/*                                                             */ 
+	/* Copy the register contents for the pt_regs structure on the */
+	/*   kernel stack to the elf_gregset_t32 structure on the user */
+	/*   stack. This is a copy of 64 bit register values to 32 bit */
+	/*   register values. The high order 32 bits of the 64 bit     */
+	/*   registers are not needed since a 32 bit application is    */
+	/*   running and the saved registers are the contents of the   */
+	/*   user registers at the time of a system call.              */
+	/*                                                             */
+	/* The values saved on the user stack will be restored into    */
+	/*  the registers during the signal return processing          */
+	/*                                                             */
+	/* Note the +1 is needed in order to get the lower 32 bits     */
+	/*  of 64 bit register                                         */
+	/***************************************************************/
+	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
+		goto badframe;
+
+	/*****************************************************************************/
+	/* Copy the non gpr registers to the user stack                              */
+	/*****************************************************************************/
+
+	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
+			      sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(&regs->gpr[PT_CTR])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(&regs->gpr[PT_LNK])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(&regs->gpr[PT_XER])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(&regs->gpr[PT_CCR])+1, sizeof(u32))
+	    || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(&regs->gpr[PT_RESULT])+1,
+			      sizeof(u32)))
+		goto badframe;
+
+
+	/*****************************************************************************/
+	/* Now copy the floating point registers onto the user stack                 */
+	/*                                                                           */
+	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
+	/*   will get control to reset the stack                                     */
+	/*****************************************************************************/
+
+
+	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
+			   ELF_NFPREG * sizeof(double))
+	    || __put_user(0x38000000U + __NR_rt_sigreturn, &frame->tramp[0])    /* li r0, __NR_rt_sigreturn */
+	    || __put_user(0x44000002U, &frame->tramp[1]))   /* sc */
+		goto badframe;
+
+	flush_icache_range((unsigned long) &frame->tramp[0],
+			   (unsigned long) &frame->tramp[2]);
+
+  
+	/* Retrieve rt_sigframe from stack and
+	   set up registers for signal handler
+	*/
+	newsp -= __SIGNAL_FRAMESIZE32;
+      
+
+	if (put_user((u32)(regs->gpr[1]), (unsigned int *)(u64)newsp)
+	    || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
+	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
+	    || get_user(copyreg4, &rt_sf->pinfo)
+	    || get_user(copyreg5, &rt_sf->puc))
+		goto badframe;
+
+	regs->gpr[4] = copyreg4;
+	regs->gpr[5] = copyreg5;
+
+   
+	regs->gpr[1] = newsp;
+	regs->gpr[6] = (unsigned long) rt_sf;
+
+
+	regs->link = (unsigned long) frame->tramp;
+
+	return;
+
+
+ badframe:
+	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
+#if DEBUG_SIG
+	printk("badframe in setup_frame32, regs=%p frame=%p newsp=%lx\n",
+	       regs, frame, newsp);
+#endif
+	do_exit(SIGSEGV);
+}
+
+
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal32(unsigned long sig, struct k_sigaction *ka,
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
+	      unsigned int *newspp, unsigned int frame)
+{
+	struct sigcontext32_struct *sc;
+	struct rt_sigframe_32 *rt_stack_frame;
+	siginfo_t32 siginfo32bit;
+
+	if (regs->trap == 0x0C00 /* System Call! */
+	    && ((int)regs->result == -ERESTARTNOHAND ||
+		((int)regs->result == -ERESTARTSYS &&
+		 !(ka->sa.sa_flags & SA_RESTART))))
+		regs->result = -EINTR;
+
+	/* Set up the signal frame             */
+	/*   Determine if an real time frame - siginfo required   */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+	{
+		siginfo64to32(&siginfo32bit,info);
+		*newspp -= sizeof(*rt_stack_frame);
+		rt_stack_frame = (struct rt_sigframe_32 *) (u64)(*newspp) ;
+    
+		if (verify_area(VERIFY_WRITE, rt_stack_frame, sizeof(*rt_stack_frame)))
+		{
+			goto badframe;
+		}
+		if (__put_user((u32)(u64)ka->sa.sa_handler, &rt_stack_frame->uc.uc_mcontext.handler)
+		    || __put_user((u32)(u64)&rt_stack_frame->info, &rt_stack_frame->pinfo)
+		    || __put_user((u32)(u64)&rt_stack_frame->uc, &rt_stack_frame->puc)
+		    /*  put the siginfo on the user stack                    */
+		    || __copy_to_user(&rt_stack_frame->info,&siginfo32bit,sizeof(siginfo32bit))
+		    /*  set the ucontext on the user stack                   */ 
+		    || __put_user(0,&rt_stack_frame->uc.uc_flags)
+		    || __put_user(0,&rt_stack_frame->uc.uc_link)
+		    || __put_user(current->sas_ss_sp, &rt_stack_frame->uc.uc_stack.ss_sp)
+		    || __put_user(sas_ss_flags(regs->gpr[1]),
+				  &rt_stack_frame->uc.uc_stack.ss_flags)
+		    || __put_user(current->sas_ss_size, &rt_stack_frame->uc.uc_stack.ss_size)
+		    || __copy_to_user(&rt_stack_frame->uc.uc_sigmask, oldset,sizeof(*oldset))
+		    /* point the mcontext.regs to the pramble register frame  */
+		    || __put_user(frame, &rt_stack_frame->uc.uc_mcontext.regs)
+		    || __put_user(sig,&rt_stack_frame->uc.uc_mcontext.signal))
+		{
+			goto badframe; 
+		}
+	} else {
+		/* Put another sigcontext on the stack */
+		*newspp -= sizeof(*sc);
+		sc = (struct sigcontext32_struct *)(u64)*newspp;
+		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+			goto badframe;
+
+		/* Note the upper 32 bits of the signal mask are stored in the */
+		/*   unused part of the signal stack frame                     */  
+		if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler)
+		    || __put_user(oldset->sig[0], &sc->oldmask)
+		    || __put_user((oldset->sig[0] >> 32), &sc->_unused[3])
+		    || __put_user((unsigned int)frame, &sc->regs)
+		    || __put_user(sig, &sc->signal))
+			goto badframe;
+	}
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+	
+	return;
+
+badframe:
+#if DEBUG_SIG
+	printk("badframe in handle_signal32, regs=%p frame=%lx newsp=%lx\n",
+	       regs, frame, *newspp);
+	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
+#endif
+	do_exit(SIGSEGV);
+}
+
+
+/****************************************************************************/
+/*  Start Alternate signal stack support                                    */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/*  System Calls                                                            */
+/*       sigaltatck               sys32_sigaltstack                         */
+/*                                                                          */
+/****************************************************************************/
+
+
+asmlinkage int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3, int p4, int p6,
+				 int p7, struct pt_regs *regs)
+{
+	stack_t uss, uoss;
+	int ret;
+	mm_segment_t old_fs;
+	unsigned long sp;
+
+	/* set sp to the user stack on entry to the system call                  */
+	/*   the system call router sets R9 to the saved registers               */
+	sp = regs->gpr[1];
+
+	/*  Put new stack info in local 64 bit stack struct                      */ 
+	if (newstack && (get_user((long)uss.ss_sp, &((stack_32_t *)(long)newstack)->ss_sp) ||
+			 __get_user(uss.ss_flags, &((stack_32_t *)(long)newstack)->ss_flags) ||
+			 __get_user(uss.ss_size, &((stack_32_t *)(long)newstack)->ss_size)))
+		return -EFAULT; 
+
+   
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = do_sigaltstack(newstack ? &uss : NULL, oldstack ? &uoss : NULL, sp);
+	set_fs(old_fs);
+	/* Copy the stack information to the user output buffer                  */
+	if (!ret && oldstack  && (put_user((long)uoss.ss_sp, &((stack_32_t *)(long)oldstack)->ss_sp) ||
+				  __put_user(uoss.ss_flags, &((stack_32_t *)(long)oldstack)->ss_flags) ||
+				  __put_user(uoss.ss_size, &((stack_32_t *)(long)oldstack)->ss_size)))
+		return -EFAULT;
+	return ret;
+}
+
+
+
+/****************************************************************************/
+/*  Start of do_signal32 routine                                            */
+/*                                                                          */
+/*   This routine gets control when a pemding signal needs to be processed  */
+/*     in the 32 bit target thread -                                        */
+/*                                                                          */
+/*   It handles both rt and non-rt signals                                  */
+/*                                                                          */
+/****************************************************************************/
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+
+int do_signal32(sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+	unsigned int frame, newsp;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	newsp = frame = 0;
+
+	for (;;) {
+		unsigned long signr;
+		
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+		ifppcdebug(PPCDBG_SYS32) {
+			if (signr)
+				udbg_printf("do_signal32 - processing signal=%2lx - pid=%ld, comm=%s \n", signr, current->pid, current->comm);
+		}
+
+		if (!signr)
+			break;
+
+		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current, SIGCHLD);
+			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
+			if (signr == SIGSTOP)
+				continue;
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
+				continue;
+			}
+		}
+
+		ka = &current->sig->action[signr-1];
+
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
+				continue;
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				/* nothing */;
+			continue;
+		}
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
+			/* Init gets no signals it doesn't want.  */
+			if (current->pid == 1)
+				continue;
+
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+				/* FALLTHRU */
+
+			case SIGSTOP:
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+					notify_parent(current, SIGCHLD);
+				schedule();
+				continue;
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
+				/* FALLTHRU */
+
+			default:
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
+				/* NOTREACHED */
+			}
+		}
+
+		PPCDBG(PPCDBG_SIGNAL, " do signal :sigaction flags = %lx \n" ,ka->sa.sa_flags);
+		PPCDBG(PPCDBG_SIGNAL, " do signal :on sig stack  = %lx \n" ,on_sig_stack(regs->gpr[1]));
+		PPCDBG(PPCDBG_SIGNAL, " do signal :reg1  = %lx \n" ,regs->gpr[1]);
+		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack  = %lx \n" ,current->sas_ss_sp);
+		PPCDBG(PPCDBG_SIGNAL, " do signal :alt stack size  = %lx \n" ,current->sas_ss_size);
+
+
+
+		if ( (ka->sa.sa_flags & SA_ONSTACK)
+		     && (! on_sig_stack(regs->gpr[1])))
+		{
+			newsp = (current->sas_ss_sp + current->sas_ss_size);
+		} else
+			newsp = regs->gpr[1];
+		newsp = frame = newsp - sizeof(struct sigregs32);
+
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal32(signr, ka, &info, oldset, regs, &newsp, frame);
+		break;
+	}
+
+	if (regs->trap == 0x0C00 /* System Call! */ &&
+	    ((int)regs->result == -ERESTARTNOHAND ||
+	     (int)regs->result == -ERESTARTSYS ||
+	     (int)regs->result == -ERESTARTNOINTR)) {
+		regs->gpr[3] = regs->orig_gpr3;
+		regs->nip -= 4;		/* Back up & retry system call */
+		regs->result = 0;
+	}
+
+	if (newsp == frame)
+	{
+		return 0;		/* no signals delivered */
+	}
+	// Invoke correct stack setup routine 
+	if (ka->sa.sa_flags & SA_SIGINFO) 
+		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
+	else
+		setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
+
+	return 1;
+
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/smp.c linux-2.4.19-pre5/arch/ppc64/kernel/smp.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/smp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/smp.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,765 @@
+/*
+ * 
+ *
+ * SMP support for ppc.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
+ * deal of code from the sparc and intel versions.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
+ * PowerPC-64 Support added by Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/init.h>
+/* #include <linux/openpic.h> */
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/Naca.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/iSeries/HvCallCfg.h>
+#include <asm/time.h>
+#include <asm/ppcdebug.h>
+#include "open_pic.h"
+#include <asm/machdep.h>
+
+int smp_threads_ready = 0;
+volatile int smp_commenced = 0;
+int smp_num_cpus = 1;
+int smp_tb_synchronized = 0;
+extern atomic_t ipi_recv;
+extern atomic_t ipi_sent;
+spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+cycles_t cacheflush_time;
+static int max_cpus __initdata = NR_CPUS;
+
+unsigned long cpu_online_map;
+
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+
+#define TB_SYNC_PASSES 4
+volatile unsigned long __initdata tb_sync_flag = 0;
+volatile unsigned long __initdata tb_offset = 0;
+
+extern unsigned char stab_array[];
+
+int start_secondary(void *);
+extern int cpu_idle(void *unused);
+void smp_call_function_interrupt(void);
+void smp_message_pass(int target, int msg, unsigned long data, int wait);
+static unsigned long iSeries_smp_message[NR_CPUS];
+extern struct Naca *naca;
+extern struct Paca xPaca[];
+
+void xics_setup_cpu(void);
+void xics_cause_IPI(int cpu);
+
+/*
+ * XICS only has a single IPI, so encode the messages per CPU
+ */
+volatile unsigned long xics_ipi_message[NR_CPUS] = {0};
+
+#define smp_message_pass(t,m,d,w) \
+    do {     atomic_inc(&ipi_sent); \
+	     ppc_md.smp_message_pass((t),(m),(d),(w)); \
+       } while(0)
+
+#ifdef CONFIG_KDB
+void smp_kdb_stop(void)
+{
+}
+#endif
+
+static inline void set_tb(unsigned int upper, unsigned int lower)
+{
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, upper);
+	mtspr(SPRN_TBWL, lower);
+}
+
+void iSeries_smp_message_recv( struct pt_regs * regs )
+{
+	int cpu = smp_processor_id();
+	int msg;
+
+	if ( smp_num_cpus < 2 )
+		return;
+
+	for ( msg = 0; msg < 4; ++msg )
+		if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) )
+			smp_message_recv( msg, regs );
+
+}
+
+static void smp_iSeries_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	int i;
+	for (i = 0; i < smp_num_cpus; ++i) {
+		if ( (target == MSG_ALL) || 
+                    (target == i) || 
+                    ((target == MSG_ALL_BUT_SELF) && (i != smp_processor_id())) ) {
+			set_bit( msg, &iSeries_smp_message[i] );
+			HvCall_sendIPI(&(xPaca[i]));
+		}
+	}
+}
+
+static int smp_iSeries_numProcs(void)
+{
+	unsigned np, i;
+	struct ItLpPaca * lpPaca;
+
+	np = 0;
+        for (i=0; i < maxPacas; ++i) {
+                lpPaca = xPaca[i].xLpPacaPtr;
+                if ( lpPaca->xDynProcStatus < 2 ) {
+                        ++np;
+                }
+        }
+	return np;
+}
+
+static int smp_iSeries_probe(void)
+{
+	unsigned i;
+	unsigned np;
+	struct ItLpPaca * lpPaca;
+
+	np = 0;
+	for (i=0; i < maxPacas; ++i) {
+		lpPaca = xPaca[i].xLpPacaPtr;
+		if ( lpPaca->xDynProcStatus < 2 ) {
+			++np;
+			xPaca[i].next_jiffy_update_tb = xPaca[0].next_jiffy_update_tb;
+		}
+	}
+	
+	smp_tb_synchronized = 1;
+	return np;
+}
+
+static void smp_iSeries_kick_cpu(int nr)
+{
+	struct ItLpPaca * lpPaca;
+	/* Verify we have a Paca for processor nr */
+	if ( ( nr <= 0 ) ||
+	     ( nr >= maxPacas ) )
+		return;
+	/* Verify that our partition has a processor nr */
+	lpPaca = xPaca[nr].xLpPacaPtr;
+	if ( lpPaca->xDynProcStatus >= 2 )
+		return;
+	/* The processor is currently spinning, waiting
+	 * for the xProcStart field to become non-zero
+	 * After we set xProcStart, the processor will
+	 * continue on to secondary_start in iSeries_head.S
+	 */
+	xPaca[nr].xProcStart = 1;
+}
+
+static void smp_iSeries_setup_cpu(int nr)
+{
+}
+
+/* This is called very early. */
+void smp_init_iSeries(void)
+{
+	ppc_md.smp_message_pass = smp_iSeries_message_pass;
+	ppc_md.smp_probe        = smp_iSeries_probe;
+	ppc_md.smp_kick_cpu     = smp_iSeries_kick_cpu;
+	ppc_md.smp_setup_cpu    = smp_iSeries_setup_cpu;
+
+	naca->processorCount	= smp_iSeries_numProcs();
+}
+
+
+static void
+smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	/* make sure we're sending something that translates to an IPI */
+	if ( msg > 0x3 ){
+		printk("SMP %d: smp_message_pass: unknown msg %d\n",
+		       smp_processor_id(), msg);
+		return;
+	}
+	switch ( target )
+	{
+	case MSG_ALL:
+		openpic_cause_IPI(msg, 0xffffffff);
+		break;
+	case MSG_ALL_BUT_SELF:
+		openpic_cause_IPI(msg,
+				  0xffffffff & ~(1 << smp_processor_id()));
+		break;
+	default:
+		openpic_cause_IPI(msg, 1<<target);
+		break;
+	}
+}
+
+static int
+smp_chrp_probe(void)
+{
+	if (naca->processorCount > 1)
+		openpic_request_IPIs();
+
+	return naca->processorCount;
+}
+
+static void
+smp_kick_cpu(int nr)
+{
+	/* Verify we have a Paca for processor nr */
+	if ( ( nr <= 0 ) ||
+	     ( nr >= maxPacas ) )
+		return;
+
+	/* The processor is currently spinning, waiting
+	 * for the xProcStart field to become non-zero
+	 * After we set xProcStart, the processor will
+	 * continue on to secondary_start in iSeries_head.S
+	 */
+	xPaca[nr].xProcStart = 1;
+}
+
+extern struct gettimeofday_struct do_gtod;
+
+static void
+smp_chrp_setup_cpu(int cpu_nr)
+{
+	static atomic_t ready = ATOMIC_INIT(1);
+	static volatile int frozen = 0;
+
+	if (_machine == _MACH_pSeriesLP) {
+		/* timebases already synced under the hypervisor. */
+		xPaca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
+		if (cpu_nr == 0) {
+			do_gtod.tb_orig_stamp = tb_last_stamp;
+			/* Should update do_gtod.stamp_xsec.
+			 * For now we leave it which means the time can be some
+			 * number of msecs off until someone does a settimeofday()
+			 */
+		}
+		smp_tb_synchronized = 1;
+	} else {
+		if (cpu_nr == 0) {
+			/* wait for all the others */
+			while (atomic_read(&ready) < smp_num_cpus)
+				barrier();
+			atomic_set(&ready, 1);
+			/* freeze the timebase */
+			rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
+			mb();
+			frozen = 1;
+			set_tb(0, 0);
+			xPaca[0].next_jiffy_update_tb = 0;
+			smp_space_timers(smp_num_cpus);
+			while (atomic_read(&ready) < smp_num_cpus)
+				barrier();
+			/* thaw the timebase again */
+			rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
+			mb();
+			frozen = 0;
+			tb_last_stamp = get_tb();
+			do_gtod.tb_orig_stamp = tb_last_stamp;
+			smp_tb_synchronized = 1;
+		} else {
+			atomic_inc(&ready);
+			while (!frozen)
+				barrier();
+			set_tb(0, 0);
+			mb();
+			atomic_inc(&ready);
+			while (frozen)
+				barrier();
+		}
+	}
+
+	if (OpenPIC_Addr) {
+		do_openpic_setup_cpu();
+	} else {
+	  if (cpu_nr > 0)
+	    xics_setup_cpu();
+	}
+}
+
+static void
+smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	int i;
+
+	for (i = 0; i < smp_num_cpus; ++i) {
+		if (target == MSG_ALL || target == i
+		    || (target == MSG_ALL_BUT_SELF
+			&& i != smp_processor_id())) {
+			set_bit(msg, &xics_ipi_message[i]);
+			mb();
+			xics_cause_IPI(i);
+			}
+	}
+}
+
+static int
+smp_xics_probe(void)
+{
+	return naca->processorCount;
+}
+
+/* This is called very early */
+void smp_init_pSeries(void)
+{
+	if(naca->interrupt_controller == IC_OPEN_PIC) {
+		ppc_md.smp_message_pass = smp_openpic_message_pass;
+		ppc_md.smp_probe        = smp_chrp_probe;
+		ppc_md.smp_kick_cpu     = smp_kick_cpu;
+		ppc_md.smp_setup_cpu    = smp_chrp_setup_cpu;
+	} else {
+		ppc_md.smp_message_pass = smp_xics_message_pass;
+		ppc_md.smp_probe        = smp_xics_probe;
+		ppc_md.smp_kick_cpu     = smp_kick_cpu;
+		ppc_md.smp_setup_cpu    = smp_chrp_setup_cpu;
+	}
+}
+
+
+void smp_local_timer_interrupt(struct pt_regs * regs)
+{
+	if (!--(get_paca()->prof_counter)) {
+		update_process_times(user_mode(regs));
+		(get_paca()->prof_counter)=get_paca()->prof_multiplier;
+	}
+}
+
+void smp_message_recv(int msg, struct pt_regs *regs)
+{
+	atomic_inc(&ipi_recv);
+	
+	switch( msg ) {
+	case PPC_MSG_CALL_FUNCTION:
+		smp_call_function_interrupt();
+		break;
+	case PPC_MSG_RESCHEDULE: 
+		current->need_resched = 1;
+		break;
+#ifdef CONFIG_XMON
+	case PPC_MSG_XMON_BREAK:
+		xmon(regs);
+		break;
+#endif /* CONFIG_XMON */
+#ifdef CONFIG_KDB
+	case PPC_MSG_XMON_BREAK:
+	        /* This isn't finished yet, obviously -TAI */
+		kdb(KDB_REASON_KEYBOARD,0, (kdb_eframe_t) regs);
+		break;
+#endif
+	default:
+		printk("SMP %d: smp_message_recv(): unknown msg %d\n",
+		       smp_processor_id(), msg);
+		break;
+	}
+}
+
+void smp_send_reschedule(int cpu)
+{
+	/*
+	 * This is only used if `cpu' is running an idle task,
+	 * so it will reschedule itself anyway...
+	 *
+	 * This isn't the case anymore since the other CPU could be
+	 * sleeping and won't reschedule until the next interrupt (such
+	 * as the timer).
+	 *  -- Cort
+	 */
+	/* This is only used if `cpu' is running an idle task,
+	   so it will reschedule itself anyway... */
+	smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0);
+}
+
+#ifdef CONFIG_XMON
+void smp_send_xmon_break(int cpu)
+{
+	smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0);
+}
+#endif /* CONFIG_XMON */
+
+static void stop_this_cpu(void *dummy)
+{
+	__cli();
+	while (1)
+		;
+}
+
+void smp_send_stop(void)
+{
+	smp_call_function(stop_this_cpu, NULL, 1, 0);
+	smp_num_cpus = 1;
+}
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ * Stolen from the i386 version.
+ */
+static spinlock_t call_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+static struct call_data_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t started;
+	atomic_t finished;
+	int wait;
+} *call_data;
+
+/*
+ * This function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ *
+ * [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.
+ * <nonatomic> currently unused.
+ * <wait> If true, wait (atomically) 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.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+			int wait)
+
+{ 
+	struct call_data_struct data;
+	int ret = -1, cpus = smp_num_cpus-1;
+	int timeout;
+
+	if (!cpus)
+		return 0;
+
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+
+	spin_lock_bh(&call_lock);
+	call_data = &data;
+	/* Send a message to all other CPUs and wait for them to respond */
+	smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0);
+
+	/* Wait for response */
+	timeout = 8000000;
+	while (atomic_read(&data.started) != cpus) {
+		HMT_low();
+		if (--timeout == 0) {
+			printk("smp_call_function on cpu %d: other cpus not responding (%d)\n",
+			       smp_processor_id(), atomic_read(&data.started));
+#ifdef CONFIG_XMON
+                        xmon(0);
+#endif
+#ifdef CONFIG_PPC_ISERIES
+			HvCall_terminateMachineSrc();
+#endif
+			goto out;
+		}
+		barrier();
+		udelay(1);
+	}
+
+	if (wait) {
+		timeout = 1000000;
+		while (atomic_read(&data.finished) != cpus) {
+			HMT_low();
+			if (--timeout == 0) {
+				printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n",
+				       smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started));
+#ifdef CONFIG_PPC_ISERIES
+				HvCall_terminateMachineSrc();
+#endif
+				goto out;
+			}
+			barrier();
+			udelay(1);
+		}
+	}
+	ret = 0;
+
+ out:
+	HMT_medium();
+	spin_unlock_bh(&call_lock);
+	return ret;
+}
+
+void smp_call_function_interrupt(void)
+{
+	void (*func) (void *info) = call_data->func;
+	void *info = call_data->info;
+	int wait = call_data->wait;
+
+	/*
+	 * Notify initiating CPU that I've grabbed the data and am
+	 * about to execute the function
+	 */
+	atomic_inc(&call_data->started);
+	/*
+	 * At this point the info structure may be out of scope unless wait==1
+	 */
+	(*func)(info);
+	if (wait)
+		atomic_inc(&call_data->finished);
+}
+
+static void smp_space_timers( unsigned nr )
+{
+	unsigned long offset, i;
+	
+	offset = tb_ticks_per_jiffy / nr;
+	for ( i=1; i<nr; ++i ) {
+		xPaca[i].next_jiffy_update_tb = xPaca[i-1].next_jiffy_update_tb + offset;
+	}
+}
+
+extern unsigned long decr_overclock;
+
+void __init smp_boot_cpus(void)
+{
+	extern struct current_set_struct current_set[];
+	struct Paca *paca;
+	extern void __secondary_start_chrp(void);
+	int i, cpu_nr;
+	struct task_struct *p;
+	unsigned long sp;
+
+	printk("Entering SMP Mode...\n");
+	PPCDBG(PPCDBG_SMP, "smp_boot_cpus: start.  NR_CPUS = 0x%lx\n", NR_CPUS);
+
+	smp_num_cpus = 1;
+        smp_store_cpu_info(0);
+	cpu_online_map = 1UL;
+
+	/*
+	 * assume for now that the first cpu booted is
+	 * cpu 0, the master -- Cort
+	 */
+	cpu_callin_map[0] = 1;
+	current->processor = 0;
+
+	init_idle();
+
+	for (i = 0; i < NR_CPUS; i++) {
+		paca = &xPaca[i];
+		paca->prof_counter=1;
+		paca->prof_multiplier = 1;
+		if(i != 0) {
+		        /*
+			 * Processor 0's segment table is statically 
+			 * initialized to real address 0x5000.  The
+			 * Other processor's tables are created and
+			 * initialized here.
+			 */
+			paca->xStab_data.virt = (unsigned long)&stab_array[PAGE_SIZE * (i-1)];
+			memset((void *)paca->xStab_data.virt, 0, PAGE_SIZE); 
+			paca->xStab_data.real = __v2a(paca->xStab_data.virt);
+			paca->default_decr = tb_ticks_per_jiffy / decr_overclock;
+		}
+	}
+
+	/*
+	 * XXX very rough, assumes 20 bus cycles to read a cache line,
+	 * timebase increments every 4 bus cycles, 32kB L1 data cache.
+	 */
+	cacheflush_time = 5 * 1024;
+
+	/* Probe arch for CPUs */
+	cpu_nr = ppc_md.smp_probe();
+
+	printk("Probe found %d CPUs\n", cpu_nr);
+
+	/*
+	 * only check for cpus we know exist.  We keep the callin map
+	 * with cpus at the bottom -- Cort
+	 */
+	if (cpu_nr > max_cpus)
+		cpu_nr = max_cpus;
+
+#ifdef CONFIG_ISERIES
+	smp_space_timers( cpu_nr );
+#endif
+
+	printk("Waiting for %d CPUs\n", cpu_nr-1);
+
+	for ( i = 1 ; i < cpu_nr; i++ ) {
+		int c;
+		struct pt_regs regs;
+		
+		/* create a process for the processor */
+		/* we don't care about the values in regs since we'll
+		   never reschedule the forked task. */
+		/* We DO care about one bit in the pt_regs we
+		   pass to do_fork.  That is the MSR_FP bit in
+		   regs.msr.  If that bit is on, then do_fork
+		   (via copy_thread) will call giveup_fpu.
+		   giveup_fpu will get a pointer to our (current's)
+		   last register savearea via current->thread.regs
+		   and using that pointer will turn off the MSR_FP,
+		   MSR_FE0 and MSR_FE1 bits.  At this point, this
+		   pointer is pointing to some arbitrary point within
+		   our stack */
+
+		memset(&regs, 0, sizeof(struct pt_regs));
+
+		if (do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0) < 0)
+			panic("failed fork for CPU %d", i);
+		p = init_task.prev_task;
+		if (!p)
+			panic("No idle task for CPU %d", i);
+
+		PPCDBG(PPCDBG_SMP,"\tProcessor %d, task = 0x%lx\n", i, p);
+
+		del_from_runqueue(p);
+		unhash_process(p);
+		init_tasks[i] = p;
+
+		p->processor = i;
+		p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+		current_set[i].task = p;
+		sp = ((unsigned long)p) + sizeof(union task_union)
+			- STACK_FRAME_OVERHEAD;
+		current_set[i].sp_real = (void *)__v2a(sp);
+
+		/* wake up cpus */
+		ppc_md.smp_kick_cpu(i);
+
+		/*
+		 * wait to see if the cpu made a callin (is actually up).
+		 * use this value that I found through experimentation.
+		 * -- Cort
+		 */
+		for ( c = 5000; c && !cpu_callin_map[i] ; c-- ) {
+			udelay(100);
+		}
+		
+		if ( cpu_callin_map[i] )
+		{
+			printk("Processor %d found.\n", i);
+			PPCDBG(PPCDBG_SMP, "\tProcessor %d found.\n", i);
+			/* this sync's the decr's -- Cort */
+			smp_num_cpus++;
+		} else {
+			printk("Processor %d is stuck.\n", i);
+			PPCDBG(PPCDBG_SMP, "\tProcessor %d is stuck.\n", i);
+		}
+	}
+
+	/* Setup CPU 0 last (important) */
+	ppc_md.smp_setup_cpu(0);
+	
+	if (smp_num_cpus < 2) {
+	        tb_last_stamp = get_tb();
+		smp_tb_synchronized = 1;
+	}
+}
+
+void __init smp_commence(void)
+{
+	/*
+	 *	Lets the callin's below out of their loop.
+	 */
+	PPCDBG(PPCDBG_SMP, "smp_commence: start\n"); 
+	wmb();
+	smp_commenced = 1;
+}
+
+void __init smp_callin(void)
+{
+	int cpu = current->processor;
+	
+        smp_store_cpu_info(cpu);
+	set_dec(xPaca[cpu].default_decr);
+	cpu_callin_map[cpu] = 1;
+
+	ppc_md.smp_setup_cpu(cpu);
+
+	init_idle();
+
+	set_bit(smp_processor_id(), &cpu_online_map);
+	
+	while(!smp_commenced) {
+		barrier();
+	}
+	__sti();
+}
+
+/* intel needs this */
+void __init initialize_secondary(void)
+{
+}
+
+/* Activate a secondary processor. */
+int start_secondary(void *unused)
+{
+	int cpu; 
+
+	cpu = current->processor;
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	smp_callin();
+
+	/* Go into the idle loop. */
+	return cpu_idle(NULL);
+}
+
+void __init smp_setup(char *str, int *ints)
+{
+}
+
+int __init setup_profiling_timer(unsigned int multiplier)
+{
+	return 0;
+}
+
+/* this function is called for each processor
+ */
+void __init smp_store_cpu_info(int id)
+{
+        xPaca[id].pvr = _get_PVR();
+}
+
+static int __init maxcpus(char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus=", maxcpus);
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/stab.c linux-2.4.19-pre5/arch/ppc64/kernel/stab.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/stab.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/stab.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,360 @@
+/*
+ * PowerPC64 Segment Translation Support.
+ *
+ * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
+ *    Copyright (c) 2001 Dave Engebretsen
+ * 
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/Paca.h>
+#include <asm/Naca.h>
+#include <asm/pmc.h>
+
+inline int make_ste(unsigned long stab, 
+		    unsigned long esid, unsigned long vsid);
+inline void make_slbe(unsigned long esid, unsigned long vsid,
+		      int large);
+extern struct Naca *naca;
+
+/*
+ * Build an entry for the base kernel segment and put it into
+ * the segment table or SLB.  All other segment table or SLB
+ * entries are faulted in.
+ */
+void stab_initialize(unsigned long stab)
+{
+	unsigned long esid, vsid; 
+
+	esid = GET_ESID(KERNELBASE);
+	vsid = get_kernel_vsid(esid << SID_SHIFT); 
+
+	if (!__is_processor(PV_POWER4)) {
+                __asm__ __volatile__("isync; slbia; isync":::"memory");
+		make_ste(stab, esid, vsid);
+	} else {
+                /* Invalidate the entire SLB & all the ERATS */
+                __asm__ __volatile__("isync" : : : "memory");
+#ifndef CONFIG_PPC_ISERIES
+                __asm__ __volatile__("slbmte  %0,%0"
+                                      : : "r" (0) : "memory");
+                __asm__ __volatile__("isync; slbia; isync":::"memory");
+		make_slbe(esid, vsid, 0);
+#else
+                __asm__ __volatile__("isync; slbia; isync":::"memory");
+#endif
+        }
+}
+
+/*
+ * Create a segment table entry for the given esid/vsid pair.
+ */ 
+inline int
+make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
+{
+	unsigned long entry, group, old_esid, castout_entry, i;
+	unsigned int global_entry;
+	STE *ste, *castout_ste;
+
+	/* Search the primary group first. */
+	global_entry = (esid & 0x1f) << 3;
+	ste = (STE *)(stab | ((esid & 0x1f) << 7)); 
+
+	/*
+	 * Find an empty entry, if one exists.
+	 */
+	for(group = 0; group < 2; group++) {
+		for(entry = 0; entry < 8; entry++, ste++) {
+			if(!(ste->dw0.dw0.v)) {
+				ste->dw1.dw1.vsid = vsid;
+				/* Order VSID updte */
+				__asm__ __volatile__ ("eieio" : : : "memory");
+				ste->dw0.dw0.esid = esid;
+				ste->dw0.dw0.v  = 1;
+				ste->dw0.dw0.kp = 1;
+				/* Order update     */
+				__asm__ __volatile__ ("sync" : : : "memory"); 
+
+				return(global_entry | entry);
+			}
+		}
+		/* Now search the secondary group. */
+		global_entry = ((~esid) & 0x1f) << 3;
+		ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); 
+	}
+
+	/*
+	 * Could not find empty entry, pick one with a round robin selection.
+	 * Search all entries in the two groups.  Note that the first time
+	 * we get here, we start with entry 1 so the initializer
+	 * can be common with the SLB castout code.
+	 */
+
+	/* This assumes we never castout when initializing the stab. */
+	PMC_SW_PROCESSOR(stab_capacity_castouts); 
+
+	castout_entry = get_paca()->xStab_data.next_round_robin;
+	for(i = 0; i < 16; i++) {
+		if(castout_entry < 8) {
+			global_entry = (esid & 0x1f) << 3;
+			ste = (STE *)(stab | ((esid & 0x1f) << 7)); 
+			castout_ste = ste + castout_entry;
+		} else {
+			global_entry = ((~esid) & 0x1f) << 3;
+			ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); 
+			castout_ste = ste + (castout_entry - 8);
+		}
+
+		if((((castout_ste->dw0.dw0.esid) >> 32) == 0) ||
+		   (((castout_ste->dw0.dw0.esid) & 0xffffffff) > 0)) {
+			/* Found an entry to castout.  It is either a user */
+			/* region, or a secondary kernel segment.          */
+			break;
+		}
+
+		castout_entry = (castout_entry + 1) & 0xf;
+	}
+
+	get_paca()->xStab_data.next_round_robin = (castout_entry + 1) & 0xf;
+
+	/* Modify the old entry to the new value. */
+
+	/* Force previous translations to complete. DRENG */
+	__asm__ __volatile__ ("isync" : : : "memory" );
+
+	castout_ste->dw0.dw0.v = 0;
+	__asm__ __volatile__ ("sync" : : : "memory" );    /* Order update */
+	castout_ste->dw1.dw1.vsid = vsid;
+	__asm__ __volatile__ ("eieio" : : : "memory" );   /* Order update */
+	old_esid = castout_ste->dw0.dw0.esid;
+	castout_ste->dw0.dw0.esid = esid;
+	castout_ste->dw0.dw0.v  = 1;
+	castout_ste->dw0.dw0.kp = 1;
+	__asm__ __volatile__ ("slbie  %0" : : "r" (old_esid << SID_SHIFT)); 
+	/* Ensure completion of slbie */
+	__asm__ __volatile__ ("sync" : : : "memory" );  
+
+	return(global_entry | (castout_entry & 0x7));
+}
+
+/*
+ * Create a segment buffer entry for the given esid/vsid pair.
+ */ 
+inline void make_slbe(unsigned long esid, unsigned long vsid, int large)
+{
+	unsigned long entry, castout_entry;
+	slb_dword0 castout_esid_data;
+	union {
+		unsigned long word0;
+		slb_dword0    data;
+	} esid_data;
+	union {
+		unsigned long word0;
+		slb_dword1    data;
+	} vsid_data;
+	
+	/*
+	 * Find an empty entry, if one exists.
+	 */
+	for(entry = 0; entry < naca->slb_size; entry++) {
+		__asm__ __volatile__("slbmfee  %0,%1" 
+				     : "=r" (esid_data) : "r" (entry)); 
+		if(!esid_data.data.v) {
+			/* 
+			 * Write the new SLB entry.
+			 */
+			vsid_data.word0 = 0;
+			vsid_data.data.vsid = vsid;
+			vsid_data.data.kp = 1;
+			if (large)
+				vsid_data.data.l = 1;
+
+			esid_data.word0 = 0;
+			esid_data.data.esid = esid;
+			esid_data.data.v = 1;
+			esid_data.data.index = entry;
+
+			/* slbie not needed as no previous mapping existed. */
+			/* Order update  */
+			__asm__ __volatile__ ("isync" : : : "memory");
+			__asm__ __volatile__ ("slbmte  %0,%1" 
+					      : : "r" (vsid_data), 
+					      "r" (esid_data)); 
+			/* Order update  */
+			__asm__ __volatile__ ("isync" : : : "memory");
+			return;
+		}
+	}
+	
+	/*
+	 * Could not find empty entry, pick one with a round robin selection.
+	 */
+
+	PMC_SW_PROCESSOR(stab_capacity_castouts); 
+
+	castout_entry = get_paca()->xStab_data.next_round_robin;
+	__asm__ __volatile__("slbmfee  %0,%1" 
+			     : "=r" (castout_esid_data) 
+			     : "r" (castout_entry)); 
+
+	entry = castout_entry; 
+	castout_entry++; 
+	if(castout_entry >= naca->slb_size) {
+		castout_entry = 1; 
+	}
+	get_paca()->xStab_data.next_round_robin = castout_entry;
+
+	/* Invalidate the old entry. */
+	castout_esid_data.v = 0; /* Set the class to 0 */
+	/* slbie not needed as the previous mapping is still valid. */
+	__asm__ __volatile__("slbie  %0" : : "r" (castout_esid_data)); 
+	
+	/* 
+	 * Write the new SLB entry.
+	 */
+	vsid_data.word0 = 0;
+	vsid_data.data.vsid = vsid;
+	vsid_data.data.kp = 1;
+	if (large)
+		vsid_data.data.l = 1;
+	
+	esid_data.word0 = 0;
+	esid_data.data.esid = esid;
+	esid_data.data.v = 1;
+	esid_data.data.index = entry;
+	
+	__asm__ __volatile__ ("isync" : : : "memory");   /* Order update */
+	__asm__ __volatile__ ("slbmte  %0,%1" 
+			      : : "r" (vsid_data), "r" (esid_data)); 
+	__asm__ __volatile__ ("isync" : : : "memory" );   /* Order update */
+}
+
+/*
+ * Allocate a segment table entry for the given ea.
+ */
+int ste_allocate ( unsigned long ea, 
+		   unsigned long trap) 
+{
+	unsigned long vsid, esid;
+	int kernel_segment = 0;
+
+	PMC_SW_PROCESSOR(stab_faults); 
+
+	/* Check for invalid effective addresses. */
+	if (!IS_VALID_EA(ea)) {
+		return 1;
+	}
+	
+	/* Kernel or user address? */
+	if (REGION_ID(ea) >= KERNEL_REGION_ID) {
+		kernel_segment = 1;
+		vsid = get_kernel_vsid( ea );
+	} else {
+		struct mm_struct *mm = current->mm;
+		if ( mm ) {
+			vsid = get_vsid(mm->context, ea );
+		} else {
+			return 1;
+		}
+	}
+
+	esid = GET_ESID(ea);
+	if (trap == 0x380 || trap == 0x480) {
+#ifndef CONFIG_PPC_ISERIES
+		if (REGION_ID(ea) == KERNEL_REGION_ID)
+			make_slbe(esid, vsid, 1); 
+		else
+#endif
+			make_slbe(esid, vsid, 0); 
+	} else {
+		unsigned char top_entry, stab_entry, *segments; 
+
+		stab_entry = make_ste(get_paca()->xStab_data.virt, esid, vsid);
+		PMC_SW_PROCESSOR_A(stab_entry_use, stab_entry & 0xf); 
+
+		segments = get_paca()->xSegments;		
+		top_entry = segments[0];
+		if(!kernel_segment && top_entry < (STAB_CACHE_SIZE - 1)) {
+			top_entry++;
+			segments[top_entry] = stab_entry;
+			if(top_entry == STAB_CACHE_SIZE - 1) top_entry = 0xff;
+			segments[0] = top_entry;
+		}
+	}
+	
+	return(0); 
+}
+ 
+/* 
+ * Flush all entries from the segment table of the current processor.
+ * Kernel and Bolted entries are not removed as we cannot tolerate 
+ * faults on those addresses.
+ */
+
+#define STAB_PRESSURE 0
+
+void flush_stab(void)
+{
+	STE *stab = (STE *) get_paca()->xStab_data.virt;
+	unsigned char *segments = get_paca()->xSegments;
+	unsigned long flags, i;
+
+	if(!__is_processor(PV_POWER4)) {
+		unsigned long entry;
+		STE *ste;
+
+		/* Force previous translations to complete. DRENG */
+		__asm__ __volatile__ ("isync" : : : "memory");
+
+		__save_and_cli(flags);
+		if(segments[0] != 0xff && !STAB_PRESSURE) {
+			for(i = 1; i <= segments[0]; i++) {
+				ste = stab + segments[i]; 
+				ste->dw0.dw0.v = 0;
+				PMC_SW_PROCESSOR(stab_invalidations); 
+			}
+		} else {
+			/* Invalidate all entries. */
+                        ste = stab;
+
+		        /* Never flush the first entry. */ 
+		        ste += 1;
+			for(entry = 1;
+			    entry < (PAGE_SIZE / sizeof(STE)); 
+			    entry++, ste++) {
+				unsigned long ea;
+				ea = ste->dw0.dw0.esid << SID_SHIFT;
+				if (STAB_PRESSURE || ea < KERNELBASE) {
+					ste->dw0.dw0.v = 0;
+					PMC_SW_PROCESSOR(stab_invalidations); 
+				}
+			}
+		}
+
+		*((unsigned long *)segments) = 0;
+		__restore_flags(flags);
+
+		/* Invalidate the SLB. */
+		/* Force invals to complete. */
+		__asm__ __volatile__ ("sync" : : : "memory");  
+		/* Flush the SLB.            */
+		__asm__ __volatile__ ("slbia" : : : "memory"); 
+		/* Force flush to complete.  */
+		__asm__ __volatile__ ("sync" : : : "memory");  
+	} else {
+		unsigned long flags;
+
+		PMC_SW_PROCESSOR(stab_invalidations); 
+
+		__save_and_cli(flags);
+		__asm__ __volatile__("isync; slbia; isync":::"memory");
+		__restore_flags(flags);
+	}
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/sys32.S linux-2.4.19-pre5/arch/ppc64/kernel/sys32.S
--- linux-2.4.19-pre4/arch/ppc64/kernel/sys32.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/sys32.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,243 @@
+/* 
+ * sys32.S: I-cache tricks for 32-bit compatability layer simple
+ *          conversions.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
+ * Copyright (C) 2000 Ken Aaker (kdaaker@rchland.vnet.ibm.com)
+ * For PPC ABI convention is parms in Regs 3-10.
+ * The router in entry.S clears the high 32 bits in the first
+ * 4 arguments (R3-R6).
+ *
+ *      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 "ppc_asm.h"
+#include <asm/errno.h>
+#include <asm/processor.h>
+
+/* NOTE: call as jump breaks return stack, we have to avoid that */
+
+	.text
+
+_GLOBAL(sys32_mmap)
+	clrldi		r7, r7, 32	/* int fd parm */
+	clrldi		r8, r8, 32	/* off_t offset parm */
+	b		.sys_mmap
+
+_GLOBAL(sys32_lseek)
+	extsw		r4,r4		/* sign extend off_t offset parm */
+	b		.sys_lseek
+
+_GLOBAL(sys32_chmod)
+/* Ken Aaker.. hmmm maybe I don't need to do anything here */
+	b		.sys_chmod
+
+_GLOBAL(sys32_mknod)
+/* Ken Aaker.. hmmm maybe I don't need to do anything here */
+	b		.sys_mknod
+
+_GLOBAL(sys32_sendto)
+	clrldi		r7, r7, 32	/* struct sockaddr *addr parm */
+	clrldi		r8, r8, 32	/* int addr_len parm */
+	b		.sys_sendto
+
+_GLOBAL(sys32_recvfrom)
+	clrldi		r7, r7, 32	/* struct sockaddr *addr parm */
+	clrldi		r8, r8, 32	/* int *addr_len parm */
+	b		.sys_recvfrom
+
+_GLOBAL(sys32_getsockopt)
+	clrldi		r7, r7, 32	/* int *optlen parm */
+	b		.sys_getsockopt
+
+_GLOBAL(sys32_bdflush)
+	extsw		r4,r4		/* sign extend long data parm */
+	b		.sys_bdflush
+
+_GLOBAL(sys32_mmap2)
+	clrldi		r7, r7, 32	/* unsigned long fd parm */
+	extsw		r8, r8		/* off_t offset */
+	b		.sys_mmap
+
+_GLOBAL(sys32_socketcall)	/* r3=call, r4=args */
+	cmpwi		r3, 1
+	blt-		.do_einval
+	cmpwi		r3, 17
+	bgt-		.do_einval
+	subi		r3, r3, 1	/* index into socketcall_table vectors and jmp */
+	sldi		r3, r3, 3	/* each entry is 8 bytes */
+	LOADADDR(r10,.socketcall_table_begin)
+	ldx		r10, r10, r3
+	mtctr		r10
+	bctr
+
+/* Socket function vectored fix ups for 32 bit */
+_STATIC(do_sys_socket) /* sys_socket(int, int, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwa		r4,4(r10)
+	lwa		r5,8(r10)
+	b		.sys_socket
+
+_STATIC(do_sys_bind) /* sys_bind(int fd, struct sockaddr *, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwa		r5,8(r10)
+	b		.sys_bind
+
+_STATIC(do_sys_connect) /* sys_connect(int, struct sockaddr *, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwa		r5,8(r10)
+	b		.sys_connect
+
+_STATIC(do_sys_listen) /* sys_listen(int, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwa		r4,4(r10)
+	b		.sys_listen
+
+_STATIC(do_sys_accept) /* sys_accept(int, struct sockaddr *, int *) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	b		.sys_accept
+
+_STATIC(do_sys_getsockname) /* sys_getsockname(int, struct sockaddr *, int *) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	b		.sys_getsockname
+
+_STATIC(do_sys_getpeername) /* sys_getpeername(int, struct sockaddr *, int *) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	b		.sys_getpeername
+
+_STATIC(do_sys_socketpair) /* sys_socketpair(int, int, int, int *) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwa		r4,4(r10)
+	lwa		r5,8(r10)
+	lwz		r6,12(r10)
+	b		.sys_socketpair
+
+_STATIC(do_sys_send) /* sys_send(int, void *, size_t, unsigned int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	lwz		r6,12(r10)
+	b		.sys_send
+
+_STATIC(do_sys_recv) /* sys_recv(int, void *, size_t, unsigned int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	lwz		r6,12(r10)
+	b		.sys_recv
+
+_STATIC(do_sys_sendto) /* sys32_sendto(int, u32, __kernel_size_t32, unsigned int, u32, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	lwz		r6,12(r10)
+	lwz		r7,16(r10)
+	lwa		r8,20(r10)
+	b		.sys32_sendto
+
+_STATIC(do_sys_recvfrom) /* sys32_recvfrom(int, u32, __kernel_size_t32, unsigned int, u32, u32) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwz		r5,8(r10)
+	lwz		r6,12(r10)
+	lwz		r7,16(r10)
+	lwz		r8,20(r10)
+	b		.sys32_recvfrom
+
+_STATIC(do_sys_shutdown) /* sys_shutdown(int, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwa		r4,4(r10)
+	b		.sys_shutdown
+
+_STATIC(do_sys_setsockopt) /* sys32_setsockopt(int, int, int, char *, int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwa		r4,4(r10)
+	lwa		r5,8(r10)
+	lwz		r6,12(r10)
+	lwa		r7,16(r10)
+	b		.sys32_setsockopt
+
+_STATIC(do_sys_getsockopt) /* sys32_getsockopt(int, int, int, u32, u32) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwa		r4,4(r10)
+	lwa		r5,8(r10)
+	lwz		r6,12(r10)
+	lwz		r7,16(r10)
+	b		.sys32_getsockopt
+
+_STATIC(do_sys_sendmsg) /* sys32_sendmsg(int, struct msghdr32 *, unsigned int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwa		r5,8(r10)
+	b		.sys32_sendmsg
+
+_STATIC(do_sys_recvmsg) /* sys32_recvmsg(int, struct msghdr32 *, unsigned int) */
+	mr		r10,r4
+	lwa		r3,0(r10)
+	lwz		r4,4(r10)
+	lwa		r5,8(r10)
+	b		.sys32_recvmsg
+
+_STATIC(do_einval)
+	li	r3,-EINVAL
+	b	.ret_from_syscall_1
+_STATIC(do_efault)
+	li	r3,-EFAULT
+	b	.ret_from_syscall_1
+
+	.data
+	.align	8
+_GLOBAL(socketcall_table_begin)
+	.llong		.do_sys_socket
+	.llong		.do_sys_bind
+	.llong		.do_sys_connect
+	.llong		.do_sys_listen
+	.llong		.do_sys_accept
+	.llong		.do_sys_getsockname
+	.llong		.do_sys_getpeername
+	.llong		.do_sys_socketpair
+	.llong		.do_sys_send
+	.llong		.do_sys_recv
+	.llong		.do_sys_sendto
+	.llong		.do_sys_recvfrom
+	.llong		.do_sys_shutdown
+	.llong		.do_sys_setsockopt
+	.llong		.do_sys_getsockopt
+	.llong		.do_sys_sendmsg
+	.llong		.do_sys_recvmsg
+_GLOBAL(socketcall_table_end)
+	.section	__ex_table,"a"
+	.align		3
+	.llong		.socketcall_table_begin
+	.llong		0
+	.llong		.socketcall_table_end
+	.llong		.do_efault
+	.previous
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/sys_ppc32.c linux-2.4.19-pre5/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/sys_ppc32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/sys_ppc32.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,4831 @@
+/*
+ * sys_ppc32.c: Conversion between 32bit and 64bit native syscalls.
+ *
+ * Copyright (C) 2001 IBM
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment.
+ *
+ *      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 <asm/ptrace.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h> 
+#include <linux/mm.h> 
+#include <linux/file.h> 
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
+#include <linux/ncp_fs.h>
+#include <linux/quota.h>
+#include <linux/module.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfsd/xdr.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/poll.h>
+#include <linux/personality.h>
+#include <linux/stat.h>
+#include <linux/filter.h>
+#include <linux/highmem.h>
+#include <linux/highuid.h>
+#include <linux/mman.h>
+#include <linux/sysctl.h>
+
+#include <asm/types.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+
+#include <asm/semaphore.h>
+
+#include <net/scm.h>
+#include <linux/elf.h>
+#include <asm/ppcdebug.h>
+#include <asm/time.h>
+
+extern unsigned long wall_jiffies;
+#define USEC_PER_SEC (1000000)
+
+/* 
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack.  SE and BE
+ * should not be in this list since gdb may want to change these.  I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+
+/* Use this to get at 32-bit user passed pointers. */
+/* Things to consider: the low-level assembly stub does
+   srl x, 0, x for first four arguments, so if you have
+   pointer to something in the first four arguments, just
+   declare it as a pointer, not u32. On the other side, 
+   arguments from 5th onwards should be declared as u32
+   for pointers, and need AA() around each usage.
+   A() macro should be used for places where you e.g.
+   have some internal variable u32 and just want to get
+   rid of a compiler warning. AA() has to be used in
+   places where you want to convert a function argument
+   to 32bit pointer or when you e.g. access pt_regs
+   structure and want to consider 32bit registers only.
+   -
+ */
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x)				\
+({	unsigned long __ret;		\
+	__asm__ ("clrldi	%0, %0, 32"	\
+		 : "=r" (__ret)		\
+		 : "0" (__x));		\
+	__ret;				\
+})
+
+
+
+/* In order to reduce some races, while at the same time doing additional
+ * checking and hopefully speeding things up, we copy filenames to the
+ * kernel data space before using them..
+ *
+ * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
+ */
+static inline int do_getname32(const char *filename, char *page)
+{
+	int retval;
+
+	/* 32bit pointer will be always far below TASK_SIZE :)) */
+	retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE);
+	if (retval > 0) {
+		if (retval < PAGE_SIZE)
+			return 0;
+		return -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -ENOENT;
+	return retval;
+}
+
+char * getname32(const char *filename)
+{
+	char *tmp, *result;
+
+	result = ERR_PTR(-ENOMEM);
+  tmp =  __getname();
+	if (tmp)  {
+		int retval = do_getname32(filename, tmp);
+
+		result = tmp;
+		if (retval < 0) {
+			putname(tmp);
+			result = ERR_PTR(retval);
+		}
+	}
+	return result;
+}
+
+
+
+extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
+
+struct utimbuf32 {
+	__kernel_time_t32 actime, modtime;
+};
+
+asmlinkage long sys32_utime(char * filename, struct utimbuf32 *times)
+{
+	struct utimbuf t;
+	mm_segment_t old_fs;
+	int ret;
+	char *filenam;
+	
+	PPCDBG(PPCDBG_SYS32NI, "sys32_utime - running - filename=%s, times=%p - pid=%ld, comm=%s \n", filename, times, current->pid, current->comm);
+
+	if (!times)
+		return sys_utime(filename, NULL);
+	if (get_user(t.actime, &times->actime) || __get_user(t.modtime, &times->modtime))
+		return -EFAULT;
+	filenam = getname32(filename);
+
+	ret = PTR_ERR(filenam);
+	if (!IS_ERR(filenam)) {
+		old_fs = get_fs();
+		set_fs (KERNEL_DS); 
+		ret = sys_utime(filenam, &t);
+		set_fs (old_fs);
+		putname (filenam);
+	}
+
+	return ret;
+}
+
+
+
+struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
+
+typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
+
+static long do_readv_writev32(int type, struct file *file,
+			      const struct iovec32 *vector, u32 count)
+{
+	unsigned long tot_len;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov=iovstack, *ivp;
+	struct inode *inode;
+	long retval, i;
+	IO_fn_t fn;
+
+	/* First get the "struct iovec" from user memory and
+	 * verify all the pointers
+	 */
+	if (!count)
+		return 0;
+	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+		return -EFAULT;
+	if (count > UIO_MAXIOV)
+		return -EINVAL;
+	if (count > UIO_FASTIOV) {
+		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+		if (!iov)
+			return -ENOMEM;
+	}
+
+	tot_len = 0;
+	i = count;
+	ivp = iov;
+	while(i > 0) {
+		u32 len;
+		u32 buf;
+
+		__get_user(len, &vector->iov_len);
+		__get_user(buf, &vector->iov_base);
+		tot_len += len;
+		ivp->iov_base = (void *)A(buf);
+		ivp->iov_len = (__kernel_size_t) len;
+		vector++;
+		ivp++;
+		i--;
+	}
+
+	inode = file->f_dentry->d_inode;
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	retval = locks_verify_area((type == VERIFY_WRITE
+				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+				   inode, file, file->f_pos, tot_len);
+	if (retval) {
+		if (iov != iovstack)
+			kfree(iov);
+		return retval;
+	}
+
+	/* Then do the actual IO.  Note that sockets need to be handled
+	 * specially as they have atomicity guarantees and can handle
+	 * iovec's natively
+	 */
+	if (inode->i_sock) {
+		int err;
+		err = sock_readv_writev(type, inode, file, iov, count, tot_len);
+		if (iov != iovstack)
+			kfree(iov);
+		return err;
+	}
+
+	if (!file->f_op) {
+		if (iov != iovstack)
+			kfree(iov);
+		return -EINVAL;
+	}
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	fn = file->f_op->read;
+	if (type == VERIFY_READ)
+		fn = (IO_fn_t) file->f_op->write;		
+	ivp = iov;
+	while (count > 0) {
+		void * base;
+		int len, nr;
+
+		base = ivp->iov_base;
+		len = ivp->iov_len;
+		ivp++;
+		count--;
+		nr = fn(file, base, len, &file->f_pos);
+		if (nr < 0) {
+			if (retval)
+				break;
+			retval = nr;
+			break;
+		}
+		retval += nr;
+		if (nr != len)
+			break;
+	}
+	if (iov != iovstack)
+		kfree(iov);
+	return retval;
+}
+
+asmlinkage long sys32_readv(u32 fd, struct iovec32 *vector, u32 count)
+{
+	struct file *file;
+	long ret = -EBADF;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_readv - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	file = fget(fd);
+	if(!file)
+		goto bad_file;
+
+	if (file->f_op && (file->f_mode & FMODE_READ) &&
+     (file->f_op->readv || file->f_op->read))
+		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
+	fput(file);
+
+bad_file:
+	PPCDBG(PPCDBG_SYS32, "sys32_readv - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return ret;
+}
+
+asmlinkage long sys32_writev(u32 fd, struct iovec32 *vector, u32 count)
+{
+	struct file *file;
+	int ret = -EBADF;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_writev - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	file = fget(fd);
+	if(!file)
+		goto bad_file;
+	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
+	   (file->f_op->writev || file->f_op->write))
+		ret = do_readv_writev32(VERIFY_READ, file, vector, count);
+	fput(file);
+
+bad_file:
+	PPCDBG(PPCDBG_SYS32, "sys32_writev - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return ret;
+}
+
+
+
+static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = get_user(kfl->l_type, &ufl->l_type);
+	err |= __get_user(kfl->l_whence, &ufl->l_whence);
+	err |= __get_user(kfl->l_start, &ufl->l_start);
+	err |= __get_user(kfl->l_len, &ufl->l_len);
+	err |= __get_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	int err;
+	
+	err = __put_user(kfl->l_type, &ufl->l_type);
+	err |= __put_user(kfl->l_whence, &ufl->l_whence);
+	err |= __put_user(kfl->l_start, &ufl->l_start);
+	err |= __put_user(kfl->l_len, &ufl->l_len);
+	err |= __put_user(kfl->l_pid, &ufl->l_pid);
+	return err;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+	{
+		struct flock f;
+		mm_segment_t old_fs;
+		long ret;
+
+		if(get_flock(&f, (struct flock32 *)arg))
+			return -EFAULT;
+		old_fs = get_fs(); set_fs (KERNEL_DS);
+		ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+		set_fs (old_fs);
+		if(put_flock(&f, (struct flock32 *)arg))
+			return -EFAULT;
+		return ret;
+	}
+	default:
+		return sys_fcntl(fd, cmd, (unsigned long)arg);
+	}
+}
+
+struct ncp_mount_data32 {
+        int version;
+        unsigned int ncp_fd;
+        __kernel_uid_t32 mounted_uid;
+        __kernel_pid_t32 wdog_pid;
+        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+        unsigned int time_out;
+        unsigned int retry_count;
+        unsigned int flags;
+        __kernel_uid_t32 uid;
+        __kernel_gid_t32 gid;
+        __kernel_mode_t32 file_mode;
+        __kernel_mode_t32 dir_mode;
+};
+
+static void *do_ncp_super_data_conv(void *raw_data)
+{
+	struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
+	struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
+
+	n->dir_mode = n32->dir_mode;
+	n->file_mode = n32->file_mode;
+	n->gid = n32->gid;
+	n->uid = n32->uid;
+	memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
+	n->wdog_pid = n32->wdog_pid;
+	n->mounted_uid = n32->mounted_uid;
+	return raw_data;
+}
+
+struct smb_mount_data32 {
+        int version;
+        __kernel_uid_t32 mounted_uid;
+        __kernel_uid_t32 uid;
+        __kernel_gid_t32 gid;
+        __kernel_mode_t32 file_mode;
+        __kernel_mode_t32 dir_mode;
+};
+
+static void *do_smb_super_data_conv(void *raw_data)
+{
+	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
+	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
+
+	s->version = s32->version;
+	s->mounted_uid = s32->mounted_uid;
+	s->uid = s32->uid;
+	s->gid = s32->gid;
+	s->file_mode = s32->file_mode;
+	s->dir_mode = s32->dir_mode;
+	return raw_data;
+}
+
+static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
+{
+	int i;
+	unsigned long page;
+	struct vm_area_struct *vma;
+
+	*kernel = 0;
+	if(!user)
+		return 0;
+	vma = find_vma(current->mm, (unsigned long)user);
+	if(!vma || (unsigned long)user < vma->vm_start)
+		return -EFAULT;
+	if(!(vma->vm_flags & VM_READ))
+		return -EFAULT;
+	i = vma->vm_end - (unsigned long) user;
+	if(PAGE_SIZE <= (unsigned long) i)
+		i = PAGE_SIZE - 1;
+	if(!(page = __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	if(copy_from_user((void *) page, user, i)) {
+		free_page(page);
+		return -EFAULT;
+	}
+	*kernel = page;
+	return 0;
+}
+
+#define SMBFS_NAME	"smbfs"
+#define NCPFS_NAME	"ncpfs"
+
+asmlinkage long sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
+{
+	unsigned long type_page = 0;
+	unsigned long data_page = 0;
+	unsigned long dev_page = 0;
+	unsigned long dir_page = 0;
+	int err, is_smb, is_ncp;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_mount - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	is_smb = is_ncp = 0;
+
+	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
+	if (err)
+		goto out;
+
+	if (!type_page) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	is_smb = !strcmp((char *)type_page, SMBFS_NAME);
+	is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
+
+	err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
+	if (err)
+		goto type_out;
+
+	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
+	if (err)
+		goto data_out;
+
+	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
+	if (err)
+		goto dev_out;
+
+	if (!is_smb && !is_ncp) {
+		lock_kernel();
+		err = do_mount((char*)dev_page, (char*)dir_page,
+				(char*)type_page, new_flags, (char*)data_page);
+		unlock_kernel();
+	} else {
+		if (is_ncp)
+			do_ncp_super_data_conv((void *)data_page);
+		else
+			do_smb_super_data_conv((void *)data_page);
+
+		lock_kernel();
+		err = do_mount((char*)dev_page, (char*)dir_page,
+				(char*)type_page, new_flags, (char*)data_page);
+		unlock_kernel();
+	}
+	free_page(dir_page);
+
+dev_out:
+	free_page(dev_page);
+
+data_out:
+	free_page(data_page);
+
+type_out:
+	free_page(type_page);
+
+out:
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_mount - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return err;
+}
+
+struct dqblk32 {
+    __u32 dqb_bhardlimit;
+    __u32 dqb_bsoftlimit;
+    __u32 dqb_curblocks;
+    __u32 dqb_ihardlimit;
+    __u32 dqb_isoftlimit;
+    __u32 dqb_curinodes;
+    __kernel_time_t32 dqb_btime;
+    __kernel_time_t32 dqb_itime;
+};
+                                
+
+extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+
+/* Note: it is necessary to treat cmd and id as unsigned ints, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_quotactl(u32 cmd_parm, const char *special, u32 id_parm, unsigned long addr)
+{
+  int cmd = (int)cmd_parm;
+  int id  = (int)id_parm;
+	int cmds = cmd >> SUBCMDSHIFT;
+	int err;
+	struct dqblk d;
+	mm_segment_t old_fs;
+	char *spec;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_quotactl - entered - pid=%ld current=%lx comm=%s \n",
+		    current->pid, current, current->comm);
+
+	switch (cmds) {
+	case Q_GETQUOTA:
+		break;
+	case Q_SETQUOTA:
+	case Q_SETUSE:
+	case Q_SETQLIM:
+		if (copy_from_user (&d, (struct dqblk32 *)addr,
+				    sizeof (struct dqblk32)))
+			return -EFAULT;
+		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		break;
+	default:
+		return sys_quotactl(cmd, special,
+				    id, (caddr_t)addr);
+	}
+	spec = getname32 (special);
+	err = PTR_ERR(spec);
+	if (IS_ERR(spec)) return err;
+	old_fs = get_fs ();
+	set_fs (KERNEL_DS);
+	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
+	set_fs (old_fs);
+	putname (spec);
+	if (cmds == Q_GETQUOTA) {
+		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+		((struct dqblk32 *)&d)->dqb_itime = i;
+		((struct dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct dqblk32 *)addr, &d,
+				  sizeof (struct dqblk32)))
+			return -EFAULT;
+	}
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_quotactl - exited - pid=%ld current=%lx comm=%s \n",
+		    current->pid, current, current->comm);
+
+	return err;
+}
+
+
+
+/* readdir & getdents */
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
+
+struct old_linux_dirent32 {
+	u32		d_ino;
+	u32		d_offset;
+	unsigned short	d_namlen;
+  /* unsigned char	d_type; */
+	char		d_name[1];
+};
+
+struct readdir_callback32 {
+	struct old_linux_dirent32 * dirent;
+	int count;
+};
+
+static int fillonedir(void * __buf, const char * name, int namlen,
+		                  off_t offset, ino_t ino, unsigned int d_type)
+{
+	struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
+	struct old_linux_dirent32 * dirent;
+
+	if (buf->count)
+		return -EINVAL;
+	buf->count++;
+	dirent = buf->dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(offset, &dirent->d_offset);
+	put_user(namlen, &dirent->d_namlen);
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	return 0;
+}
+
+asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
+{
+	int error = -EBADF;
+	struct file * file;
+	struct readdir_callback32 buf;
+
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.count = 0;
+	buf.dirent = dirent;
+
+	error = vfs_readdir(file, (filldir_t)fillonedir, &buf);
+	if (error < 0)
+		goto out_putf;
+	error = buf.count;
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+
+#if 0
+struct linux_dirent32 {
+	u32		d_ino;
+	u32		d_off;
+	unsigned short	d_reclen;
+	char		d_name[1];
+};
+#else
+struct linux_dirent32 {
+	u32		d_ino;
+	u32		d_off;
+	unsigned short	d_reclen;
+  /* unsigned char	d_type; */
+	char		d_name[256];
+};
+#endif
+
+struct getdents_callback32 {
+	struct linux_dirent32 * current_dir;
+	struct linux_dirent32 * previous;
+	int count;
+	int error;
+};
+
+static int
+filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino,
+		               unsigned int d_type)
+{
+	struct linux_dirent32 * dirent;
+	struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent)
+		put_user(offset, &dirent->d_off);
+	dirent = buf->current_dir;
+	buf->previous = dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(reclen, &dirent->d_reclen);
+	/* put_user(d_type, &dirent->d_type); */
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	((char *) dirent) += reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+	return 0;
+}
+
+asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
+{
+	struct file * file;
+	struct linux_dirent32 * lastdirent;
+	struct getdents_callback32 buf;
+	int error = -EBADF;
+
+	PPCDBG(PPCDBG_SYS32NI, "sys32_getdents - running - fd=%x, pid=%ld, comm=%s \n", fd, current->pid, current->comm);
+
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, (filldir_t)filldir, &buf);
+	if (error < 0)
+		goto out_putf;
+	lastdirent = buf.previous;
+	error = buf.error;
+	if(lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+ out_putf:
+	fput(file);
+
+ out:
+	return error;
+}
+/* end of readdir & getdents */
+
+
+
+/* 32-bit timeval and related flotsam.  */
+
+struct timeval32
+{
+	int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+	struct timeval32 it_interval;
+	struct timeval32 it_value;
+};
+
+
+
+
+/*
+ * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
+ * 64-bit unsigned longs.
+ */
+static inline int
+get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
+{
+	if (ufdset) {
+		unsigned long odd;
+
+		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
+			return -EFAULT;
+
+		odd = n & 1UL;
+		n &= ~1UL;
+		while (n) {
+			unsigned long h, l;
+			__get_user(l, ufdset);
+			__get_user(h, ufdset+1);
+			ufdset += 2;
+			*fdset++ = h << 32 | l;
+			n -= 2;
+		}
+		if (odd)
+			__get_user(*fdset, ufdset);
+	} else {
+		/* Tricky, must clear full unsigned long in the
+		 * kernel fdset at the end, this makes sure that
+		 * actually happens.
+		 */
+		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
+	}
+	return 0;
+}
+
+static inline void
+set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
+{
+	unsigned long odd;
+
+	if (!ufdset)
+		return;
+
+	odd = n & 1UL;
+	n &= ~1UL;
+	while (n) {
+		unsigned long h, l;
+		l = *fdset++;
+		h = l >> 32;
+		__put_user(l, ufdset);
+		__put_user(h, ufdset+1);
+		ufdset += 2;
+		n -= 2;
+	}
+	if (odd)
+		__put_user(*fdset, ufdset);
+}
+
+
+
+#define MAX_SELECT_SECONDS ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+
+asmlinkage long sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
+{
+	fd_set_bits fds;
+	struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x);
+	char *bits;
+	unsigned long nn;
+	long timeout;
+	int ret, size;
+	
+  PPCDBG(PPCDBG_SYS32X, "sys32_select - entered - n=%x, inp=%p, outp=%p - pid=%ld comm=%s \n", n, inp, outp, current->pid, current->comm);
+
+	timeout = MAX_SCHEDULE_TIMEOUT;
+	if (tvp) {
+		time_t sec, usec;
+		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
+		    || (ret = __get_user(sec, &tvp->tv_sec))
+		    || (ret = __get_user(usec, &tvp->tv_usec)))
+			goto out_nofds;
+
+		ret = -EINVAL;
+		if(sec < 0 || usec < 0)
+			goto out_nofds;
+
+		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+			timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
+			timeout += sec * (unsigned long) HZ;
+		}
+	}
+
+	ret = -EINVAL;
+	if (n < 0)
+		goto out_nofds;
+	if (n > current->files->max_fdset)
+		n = current->files->max_fdset;
+
+	/*
+	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+	 * since we used fdset we need to allocate memory in units of
+	 * long-words. 
+	 */
+	ret = -ENOMEM;
+	size = FDS_BYTES(n);
+	bits = kmalloc(6 * size, GFP_KERNEL);
+	if (!bits)
+		goto out_nofds;
+	fds.in      = (unsigned long *)  bits;
+	fds.out     = (unsigned long *) (bits +   size);
+	fds.ex      = (unsigned long *) (bits + 2*size);
+	fds.res_in  = (unsigned long *) (bits + 3*size);
+	fds.res_out = (unsigned long *) (bits + 4*size);
+	fds.res_ex  = (unsigned long *) (bits + 5*size);
+
+	nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
+	if ((ret = get_fd_set32(nn, fds.in, inp)) ||
+	    (ret = get_fd_set32(nn, fds.out, outp)) ||
+	    (ret = get_fd_set32(nn, fds.ex, exp)))
+		goto out;
+	zero_fd_set(n, fds.res_in);
+	zero_fd_set(n, fds.res_out);
+	zero_fd_set(n, fds.res_ex);
+
+	ret = do_select(n, &fds, &timeout);
+
+	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
+		time_t sec = 0, usec = 0;
+		if (timeout) {
+			sec = timeout / HZ;
+			usec = timeout % HZ;
+			usec *= (1000000/HZ);
+		}
+		put_user(sec, &tvp->tv_sec);
+		put_user(usec, &tvp->tv_usec);
+	}
+
+  if (ret < 0)
+		goto out;
+	if (!ret) {
+		ret = -ERESTARTNOHAND;
+		if (signal_pending(current))
+			goto out;
+		ret = 0;
+	}
+
+	set_fd_set32(nn, inp, fds.res_in);
+	set_fd_set32(nn, outp, fds.res_out);
+	set_fd_set32(nn, exp, fds.res_ex);
+  
+out:
+	kfree(bits);
+
+out_nofds:
+	PPCDBG(PPCDBG_SYS32X, "sys32_select - exited - pid=%ld, comm=%s \n", current->pid, current->comm);
+	return ret;
+}
+
+
+
+
+/*
+ * Due to some executables calling the wrong select we sometimes
+ * get wrong args.  This determines how the args are being passed
+ * (a single ptr to them all args passed) then calls
+ * sys_select() with the appropriate args. -- Cort
+ */
+/* Note: it is necessary to treat n as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int ppc32_select(u32 n, u32* inp, u32* outp, u32* exp, u32 tvp_x)
+{
+	if ((unsigned int)n >= 4096)
+		panic("ppc32_select - wrong arguments were passed in \n");
+
+	return sys32_select((int)n, inp, outp, exp, tvp_x);
+}
+
+
+
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+{
+	unsigned long ino, blksize, blocks;
+	kdev_t dev, rdev;
+	umode_t mode;
+	nlink_t nlink;
+	uid_t uid;
+	gid_t gid;
+	off_t size;
+	time_t atime, mtime, ctime;
+	int err;
+
+	/* Stream the loads of inode data into the load buffer,
+	 * then we push it all into the store buffer below.  This
+	 * should give optimal cache performance.
+	 */
+	ino = inode->i_ino;
+	dev = inode->i_dev;
+	mode = inode->i_mode;
+	nlink = inode->i_nlink;
+	uid = inode->i_uid;
+	gid = inode->i_gid;
+	rdev = inode->i_rdev;
+	size = inode->i_size;
+	atime = inode->i_atime;
+	mtime = inode->i_mtime;
+	ctime = inode->i_ctime;
+	blksize = inode->i_blksize;
+	blocks = inode->i_blocks;
+
+	err  = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
+	err |= put_user(ino, &statbuf->st_ino);
+	err |= put_user(mode, &statbuf->st_mode);
+	err |= put_user(nlink, &statbuf->st_nlink);
+	err |= put_user(uid, &statbuf->st_uid);
+	err |= put_user(gid, &statbuf->st_gid);
+	err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
+	err |= put_user(size, &statbuf->st_size);
+	err |= put_user(atime, &statbuf->st_atime);
+	err |= put_user(0, &statbuf->__unused1);
+	err |= put_user(mtime, &statbuf->st_mtime);
+	err |= put_user(0, &statbuf->__unused2);
+	err |= put_user(ctime, &statbuf->st_ctime);
+	err |= put_user(0, &statbuf->__unused3);
+	if (blksize) {
+		err |= put_user(blksize, &statbuf->st_blksize);
+		err |= put_user(blocks, &statbuf->st_blocks);
+	} else {
+		unsigned int tmp_blocks;
+
+#define D_B   7
+#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
+		tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+		if (tmp_blocks > D_B) {
+			unsigned int indirect;
+
+			indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
+			tmp_blocks += indirect;
+			if (indirect > 1) {
+				indirect = (indirect - 1 + I_B - 1) / I_B;
+				tmp_blocks += indirect;
+				if (indirect > 1)
+					tmp_blocks++;
+			}
+		}
+		err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
+		err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
+#undef D_B
+#undef I_B
+	}
+	err |= put_user(0, &statbuf->__unused4[0]);
+	err |= put_user(0, &statbuf->__unused4[1]);
+
+	return err;
+}
+
+static __inline__ int
+do_revalidate(struct dentry *dentry)
+{
+	struct inode * inode = dentry->d_inode;
+	if (inode->i_op && inode->i_op->revalidate)
+		return inode->i_op->revalidate(dentry);
+	return 0;
+}
+
+asmlinkage long sys32_newstat(char* filename, struct stat32* statbuf)
+{
+	struct nameidata nd;
+	int error;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_newstat - running - filename=%s, statbuf=%p, pid=%ld, comm=%s\n", filename, statbuf, current->pid, current->comm);
+
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
+		if (!error)
+			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage long sys32_newlstat(char * filename, struct stat32 *statbuf)
+{
+	struct nameidata nd;
+	int error;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_newlstat - running - fn=%s, pid=%ld, comm=%s\n", filename, current->pid, current->comm);
+
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
+		if (!error)
+			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
+{
+	struct file *f;
+	int err = -EBADF;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_newfstat - running - fd=%x, pid=%ld, comm=%s\n", fd, current->pid, current->comm);
+
+	f = fget(fd);
+	if (f) {
+		struct dentry * dentry = f->f_dentry;
+
+		err = do_revalidate(dentry);
+		if (!err)
+			err = cp_new_stat32(dentry->d_inode, statbuf);
+		fput(f);
+	}
+	return err;
+}
+
+static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
+{
+	int err;
+	
+	err = put_user (kbuf->f_type, &ubuf->f_type);
+	err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
+	err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
+	err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree);
+	err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail);
+	err |= __put_user (kbuf->f_files, &ubuf->f_files);
+	err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree);
+	err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen);
+	err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);
+	err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);
+	return err;
+}
+
+extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
+
+asmlinkage long sys32_statfs(const char * path, struct statfs32 *buf)
+{
+	int ret;
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	char *pth;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_statfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+	
+	pth = getname32 (path);
+	ret = PTR_ERR(pth);
+	if (!IS_ERR(pth)) {
+		set_fs (KERNEL_DS);
+		ret = sys_statfs((const char *)pth, &s);
+		set_fs (old_fs);
+		putname (pth);
+		if (put_statfs(buf, &s))
+			return -EFAULT;
+	}
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_statfs - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return ret;
+}
+
+extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf);
+
+asmlinkage long sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
+{
+	int ret;
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_fstatfs - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+	
+	set_fs (KERNEL_DS);
+	ret = sys_fstatfs(fd, &s);
+	set_fs (old_fs);
+	if (put_statfs(buf, &s))
+		return -EFAULT;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_fstatfs - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return ret;
+}
+
+
+
+extern asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
+
+/* Note: it is necessary to treat option as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sysfs(u32 option, u32 arg1, u32 arg2)
+{
+	PPCDBG(PPCDBG_SYS32, "sys32_sysfs - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+	return sys_sysfs((int)option, arg1, arg2);
+}
+
+
+
+
+extern unsigned long do_mremap(unsigned long addr,
+	unsigned long old_len, unsigned long new_len,
+	unsigned long flags, unsigned long new_addr);
+                
+asmlinkage unsigned long sys32_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len,
+                                    	unsigned long flags, u32 __new_addr)
+{
+	unsigned long ret = -EINVAL;
+	unsigned long new_addr = AA(__new_addr);
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_mremap - entered - pid=%ld current=%lx comm=%s\n",
+		    current->pid, current, current->comm);
+
+
+	if (old_len > 0xf0000000UL || new_len > 0xf0000000UL)
+		goto out;
+	if (addr > 0xf0000000UL - old_len)
+		goto out;
+	down_write(&current->mm->mmap_sem);
+	if (flags & MREMAP_FIXED) {
+		if (new_addr > 0xf0000000UL - new_len)
+			goto out_sem;
+	} else if (addr > 0xf0000000UL - new_len) {
+		ret = -ENOMEM;
+		if (!(flags & MREMAP_MAYMOVE))
+			goto out_sem;
+		new_addr = get_unmapped_area (NULL, addr, new_len, 0, 0);
+		if (!new_addr)
+			goto out_sem;
+		flags |= MREMAP_FIXED;
+	}
+	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+out_sem:
+	up_write(&current->mm->mmap_sem);
+out:
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_mremap - exited - pid=%ld current=%lx comm=%s\n",
+		    current->pid, current, current->comm);
+
+	return ret;       
+}
+
+
+
+/* Handle adjtimex compatability. */
+struct timex32 {
+	u32 modes;
+	s32 offset, freq, maxerror, esterror;
+	s32 status, constant, precision, tolerance;
+	struct timeval32 time;
+	s32 tick;
+	s32 ppsfreq, jitter, shift, stabil;
+	s32 jitcnt, calcnt, errcnt, stbcnt;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+	s32  :32; s32  :32; s32  :32; s32  :32;
+};
+
+extern int do_adjtimex(struct timex *);
+extern void ppc_adjtimex(void);
+
+asmlinkage long sys32_adjtimex(struct timex32 *utp)
+{
+	struct timex txc;
+	int ret;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_adjtimex - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	memset(&txc, 0, sizeof(struct timex));
+
+	if(get_user(txc.modes, &utp->modes) ||
+	   __get_user(txc.offset, &utp->offset) ||
+	   __get_user(txc.freq, &utp->freq) ||
+	   __get_user(txc.maxerror, &utp->maxerror) ||
+	   __get_user(txc.esterror, &utp->esterror) ||
+	   __get_user(txc.status, &utp->status) ||
+	   __get_user(txc.constant, &utp->constant) ||
+	   __get_user(txc.precision, &utp->precision) ||
+	   __get_user(txc.tolerance, &utp->tolerance) ||
+	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+	   __get_user(txc.tick, &utp->tick) ||
+	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||
+	   __get_user(txc.jitter, &utp->jitter) ||
+	   __get_user(txc.shift, &utp->shift) ||
+	   __get_user(txc.stabil, &utp->stabil) ||
+	   __get_user(txc.jitcnt, &utp->jitcnt) ||
+	   __get_user(txc.calcnt, &utp->calcnt) ||
+	   __get_user(txc.errcnt, &utp->errcnt) ||
+	   __get_user(txc.stbcnt, &utp->stbcnt))
+		return -EFAULT;
+
+	ret = do_adjtimex(&txc);
+
+	/* adjust the conversion of TB to time of day to track adjtimex */
+	ppc_adjtimex();
+
+	if(put_user(txc.modes, &utp->modes) ||
+	   __put_user(txc.offset, &utp->offset) ||
+	   __put_user(txc.freq, &utp->freq) ||
+	   __put_user(txc.maxerror, &utp->maxerror) ||
+	   __put_user(txc.esterror, &utp->esterror) ||
+	   __put_user(txc.status, &utp->status) ||
+	   __put_user(txc.constant, &utp->constant) ||
+	   __put_user(txc.precision, &utp->precision) ||
+	   __put_user(txc.tolerance, &utp->tolerance) ||
+	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+	   __put_user(txc.tick, &utp->tick) ||
+	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||
+	   __put_user(txc.jitter, &utp->jitter) ||
+	   __put_user(txc.shift, &utp->shift) ||
+	   __put_user(txc.stabil, &utp->stabil) ||
+	   __put_user(txc.jitcnt, &utp->jitcnt) ||
+	   __put_user(txc.calcnt, &utp->calcnt) ||
+	   __put_user(txc.errcnt, &utp->errcnt) ||
+	   __put_user(txc.stbcnt, &utp->stbcnt))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+
+
+#ifdef CONFIG_MODULES
+
+extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size);
+
+asmlinkage unsigned long sys32_create_module(const char *name_user, __kernel_size_t32 size)
+{
+	
+	PPCDBG(PPCDBG_SYS32M, "sys32_create_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return sys_create_module(name_user, (size_t)size);
+}
+
+
+
+extern asmlinkage long sys_init_module(const char *name_user, struct module *mod_user);
+
+asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user)
+{
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_init_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return sys_init_module(name_user, mod_user);
+}
+
+
+
+extern asmlinkage long sys_delete_module(const char *name_user);
+
+asmlinkage long sys32_delete_module(const char *name_user)
+{
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_delete_module - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return sys_delete_module(name_user);
+}
+
+
+
+struct module_info32 {
+	u32 addr;
+	u32 size;
+	u32 flags;
+	s32 usecount;
+};
+
+/* Query various bits about modules.  */
+
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+	unsigned long page;
+	long retval;
+
+	if ((unsigned long)user_name >= TASK_SIZE
+	    && !segment_eq(get_fs (), KERNEL_DS))
+		return -EFAULT;
+
+	page = __get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+	if (retval > 0) {
+		if (retval < PAGE_SIZE) {
+			*buf = (char *)page;
+			return retval;
+		}
+		retval = -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -EINVAL;
+
+	free_page(page);
+	return retval;
+}
+
+static inline void
+put_mod_name(char *buf)
+{
+	free_page((unsigned long)buf);
+}
+
+static __inline__ struct module *find_module(const char *name)
+{
+	struct module *mod;
+
+	for (mod = module_list; mod ; mod = mod->next) {
+		if (mod->flags & MOD_DELETED)
+			continue;
+		if (!strcmp(mod->name, name))
+			break;
+	}
+
+	return mod;
+}
+
+static int
+qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	struct module *mod;
+	size_t nmod, space, len;
+
+	nmod = space = 0;
+
+	for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
+		len = strlen(mod->name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, mod->name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	if (put_user(nmod, ret))
+		return -EFAULT;
+	else
+		return 0;
+
+calc_space_needed:
+	space += len;
+	while ((mod = mod->next)->next != NULL)
+		space += strlen(mod->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static int
+qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	size_t i, space, len;
+
+	if (mod->next == NULL)
+		return -EINVAL;
+	if (!MOD_CAN_QUERY(mod))
+		return put_user(0, ret);
+
+	space = 0;
+	for (i = 0; i < mod->ndeps; ++i) {
+		const char *dep_name = mod->deps[i].dep->name;
+
+		len = strlen(dep_name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, dep_name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	return put_user(i, ret);
+
+calc_space_needed:
+	space += len;
+	while (++i < mod->ndeps)
+		space += strlen(mod->deps[i].dep->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static int
+qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	size_t nrefs, space, len;
+	struct module_ref *ref;
+
+	if (mod->next == NULL)
+		return -EINVAL;
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
+
+	space = 0;
+	for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
+		const char *ref_name = ref->ref->name;
+
+		len = strlen(ref_name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+		if (copy_to_user(buf, ref_name, len))
+			return -EFAULT;
+		buf += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	if (put_user(nrefs, ret))
+		return -EFAULT;
+	else
+		return 0;
+
+calc_space_needed:
+	space += len;
+	while ((ref = ref->next_ref) != NULL)
+		space += strlen(ref->ref->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static inline int
+qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	size_t i, space, len;
+	struct module_symbol *s;
+	char *strings;
+	unsigned *vals;
+
+	if (!MOD_CAN_QUERY(mod))
+		if (put_user(0, ret))
+			return -EFAULT;
+		else
+			return 0;
+
+	space = mod->nsyms * 2*sizeof(u32);
+
+	i = len = 0;
+	s = mod->syms;
+
+	if (space > bufsize)
+		goto calc_space_needed;
+
+	if (!access_ok(VERIFY_WRITE, buf, space))
+		return -EFAULT;
+
+	bufsize -= space;
+	vals = (unsigned *)buf;
+	strings = buf+space;
+
+	for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
+		len = strlen(s->name)+1;
+		if (len > bufsize)
+			goto calc_space_needed;
+
+		if (copy_to_user(strings, s->name, len)
+		    || __put_user(s->value, vals+0)
+		    || __put_user(space, vals+1))
+			return -EFAULT;
+
+		strings += len;
+		bufsize -= len;
+		space += len;
+	}
+
+	if (put_user(i, ret))
+		return -EFAULT;
+	else
+		return 0;
+
+calc_space_needed:
+	for (; i < mod->nsyms; ++i, ++s)
+		space += strlen(s->name)+1;
+
+	if (put_user(space, ret))
+		return -EFAULT;
+	else
+		return -ENOSPC;
+}
+
+static inline int
+qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+	int error = 0;
+
+	if (mod->next == NULL)
+		return -EINVAL;
+
+	if (sizeof(struct module_info32) <= bufsize) {
+		struct module_info32 info;
+		info.addr = (unsigned long)mod;
+		info.size = mod->size;
+		info.flags = mod->flags;
+		info.usecount =
+			((mod_member_present(mod, can_unload)
+			  && mod->can_unload)
+			 ? -1 : atomic_read(&mod->uc.usecount));
+
+		if (copy_to_user(buf, &info, sizeof(struct module_info32)))
+			return -EFAULT;
+	} else
+		error = -ENOSPC;
+
+	if (put_user(sizeof(struct module_info32), ret))
+		return -EFAULT;
+
+	return error;
+}
+
+/* Note: it is necessary to treat which as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_query_module(char *name_user, u32 which, char *buf, __kernel_size_t32 bufsize, u32 ret)
+{
+	struct module *mod;
+	int err;
+	
+	PPCDBG(PPCDBG_SYS32M, "sys32_query_module - entered - pid=%ld current=%lx comm=%s\n",
+		    current->pid, current, current->comm);
+
+	lock_kernel();
+	if (name_user == 0) {
+		/* This finds "kernel_module" which is not exported. */
+		for(mod = module_list; mod->next != NULL; mod = mod->next)
+			;
+	} else {
+		long namelen;
+		char *name;
+
+		if ((namelen = get_mod_name(name_user, &name)) < 0) {
+			err = namelen;
+			goto out;
+		}
+		err = -ENOENT;
+		if (namelen == 0) {
+			/* This finds "kernel_module" which is not exported. */
+			for(mod = module_list; mod->next != NULL; mod = mod->next)
+				;
+		} else if ((mod = find_module(name)) == NULL) {
+			put_mod_name(name);
+			goto out;
+		}
+		put_mod_name(name);
+	}
+
+	switch ((int)which)
+	{
+	case 0:
+		err = 0;
+		break;
+	case QM_MODULES:
+		err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret));
+		break;
+	case QM_DEPS:
+		err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+		break;
+	case QM_REFS:
+		err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+		break;
+	case QM_SYMBOLS:
+		err = qm_symbols(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+		break;
+	case QM_INFO:
+		err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+out:
+	unlock_kernel();
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_query_module - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return err;
+}
+
+
+
+struct kernel_sym32 {
+	u32 value;
+	char name[60];
+};
+		 
+extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table);
+
+asmlinkage long sys32_get_kernel_syms(struct kernel_sym32 *table)
+{
+	int len, i;
+	struct kernel_sym *tbl;
+	mm_segment_t old_fs;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	
+	len = sys_get_kernel_syms(NULL);
+	if (!table) return len;
+	tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
+	if (!tbl) return -ENOMEM;
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	sys_get_kernel_syms(tbl);
+	set_fs (old_fs);
+	for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
+		if (put_user (tbl[i].value, &table->value) ||
+		    copy_to_user (table->name, tbl[i].name, 60))
+			break;
+	}
+	kfree (tbl);
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return i;
+}
+
+#else /* CONFIG_MODULES */
+
+asmlinkage unsigned long sys32_create_module(const char *name_user, size_t size)
+{
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_create_module - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+
+	return -ENOSYS;
+}
+
+asmlinkage long sys32_init_module(const char *name_user, struct module *mod_user)
+{
+	PPCDBG(PPCDBG_SYS32, "sys32_init_module - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+
+	return -ENOSYS;
+}
+
+asmlinkage long sys32_delete_module(const char *name_user)
+{
+	PPCDBG(PPCDBG_SYS32, "sys32_delete_module - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+
+	return -ENOSYS;
+}
+
+/* Note: it is necessary to treat which as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_query_module(const char *name_user, u32 which, char *buf, size_t bufsize, size_t *ret)
+{
+	PPCDBG(PPCDBG_SYS32, "sys32_query_module - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	/* Let the program know about the new interface.  Not that it'll do them much good. */
+	if ((int)which == 0)
+		return 0;
+
+	PPCDBG(PPCDBG_SYS32, "sys32_query_module - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+	return -ENOSYS;
+}
+
+asmlinkage long sys32_get_kernel_syms(struct kernel_sym *table)
+{
+	PPCDBG(PPCDBG_SYS32, "sys32_get_kernel_syms - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+
+	return -ENOSYS;
+}
+
+#endif  /* CONFIG_MODULES */
+
+
+
+/* Stuff for NFS server syscalls... */
+struct nfsctl_svc32 {
+	u16			svc32_port;
+	s32			svc32_nthreads;
+};
+
+struct nfsctl_client32 {
+	s8			cl32_ident[NFSCLNT_IDMAX+1];
+	s32			cl32_naddr;
+	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
+	s32			cl32_fhkeytype;
+	s32			cl32_fhkeylen;
+	u8			cl32_fhkey[NFSCLNT_KEYMAX];
+};
+
+struct nfsctl_export32 {
+	s8			ex32_client[NFSCLNT_IDMAX+1];
+	s8			ex32_path[NFS_MAXPATHLEN+1];
+	__kernel_dev_t32	ex32_dev;
+	__kernel_ino_t32	ex32_ino;
+	s32			ex32_flags;
+	__kernel_uid_t32	ex32_anon_uid;
+	__kernel_gid_t32	ex32_anon_gid;
+};
+
+struct nfsctl_uidmap32 {
+	u32			ug32_ident;   /* char * */
+	__kernel_uid_t32	ug32_uidbase;
+	s32			ug32_uidlen;
+	u32			ug32_udimap;  /* uid_t * */
+	__kernel_uid_t32	ug32_gidbase;
+	s32			ug32_gidlen;
+	u32			ug32_gdimap;  /* gid_t * */
+};
+
+struct nfsctl_fhparm32 {
+	struct sockaddr		gf32_addr;
+	__kernel_dev_t32	gf32_dev;
+	__kernel_ino_t32	gf32_ino;
+	s32			gf32_version;
+};
+
+struct nfsctl_fdparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_version;
+};
+
+struct nfsctl_fsparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_maxlen;
+};
+
+struct nfsctl_arg32 {
+	s32			ca32_version;	/* safeguard */
+	union {
+		struct nfsctl_svc32	u32_svc;
+		struct nfsctl_client32	u32_client;
+		struct nfsctl_export32	u32_export;
+		struct nfsctl_uidmap32	u32_umap;
+		struct nfsctl_fhparm32	u32_getfh;
+		struct nfsctl_fdparm32	u32_getfd;
+		struct nfsctl_fsparm32	u32_getfs;
+	} u;
+#define ca32_svc	u.u32_svc
+#define ca32_client	u.u32_client
+#define ca32_export	u.u32_export
+#define ca32_umap	u.u32_umap
+#define ca32_getfh	u.u32_getfh
+#define ca32_getfd	u.u32_getfd
+#define ca32_getfs	u.u32_getfs
+#define ca32_authd	u.u32_authd
+};
+
+union nfsctl_res32 {
+	__u8			cr32_getfh[NFS_FHSIZE];
+	struct knfsd_fh		cr32_getfs;
+};
+
+static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
+	err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
+	return err;
+}
+
+static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_client.cl_ident[0],
+			  &arg32->ca32_client.cl32_ident[0],
+			  NFSCLNT_IDMAX);
+	err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
+	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
+			  &arg32->ca32_client.cl32_addrlist[0],
+			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
+	err |= __get_user(karg->ca_client.cl_fhkeytype,
+		      &arg32->ca32_client.cl32_fhkeytype);
+	err |= __get_user(karg->ca_client.cl_fhkeylen,
+		      &arg32->ca32_client.cl32_fhkeylen);
+	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
+			  &arg32->ca32_client.cl32_fhkey[0],
+			  NFSCLNT_KEYMAX);
+
+	if(err) return -EFAULT;
+	return 0;
+}
+
+static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_export.ex_client[0],
+			  &arg32->ca32_export.ex32_client[0],
+			  NFSCLNT_IDMAX);
+	err |= copy_from_user(&karg->ca_export.ex_path[0],
+			  &arg32->ca32_export.ex32_path[0],
+			  NFS_MAXPATHLEN);
+	err |= __get_user(karg->ca_export.ex_dev,
+		      &arg32->ca32_export.ex32_dev);
+	err |= __get_user(karg->ca_export.ex_ino,
+		      &arg32->ca32_export.ex32_ino);
+	err |= __get_user(karg->ca_export.ex_flags,
+		      &arg32->ca32_export.ex32_flags);
+	err |= __get_user(karg->ca_export.ex_anon_uid,
+		      &arg32->ca32_export.ex32_anon_uid);
+	err |= __get_user(karg->ca_export.ex_anon_gid,
+		      &arg32->ca32_export.ex32_anon_gid);
+	karg->ca_export.ex_anon_uid = karg->ca_export.ex_anon_uid;
+	karg->ca_export.ex_anon_gid = karg->ca_export.ex_anon_gid;
+
+	if(err) return -EFAULT;
+	return 0;
+}
+
+static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	u32 uaddr;
+	int i;
+	int err;
+
+	memset(karg, 0, sizeof(*karg));
+	if(__get_user(karg->ca_version, &arg32->ca32_version))
+		return -EFAULT;
+	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	if(!karg->ca_umap.ug_ident)
+		return -ENOMEM;
+	err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
+	if(strncpy_from_user(karg->ca_umap.ug_ident,
+			     (char *)A(uaddr), PAGE_SIZE) <= 0)
+		return -EFAULT;
+	err |= __get_user(karg->ca_umap.ug_uidbase,
+		      &arg32->ca32_umap.ug32_uidbase);
+	err |= __get_user(karg->ca_umap.ug_uidlen,
+		      &arg32->ca32_umap.ug32_uidlen);
+	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
+	if (err)
+		return -EFAULT;
+	karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
+					  GFP_USER);
+	if(!karg->ca_umap.ug_udimap)
+		return -ENOMEM;
+	for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
+		err |= __get_user(karg->ca_umap.ug_udimap[i],
+			      &(((__kernel_uid_t32 *)A(uaddr))[i]));
+	err |= __get_user(karg->ca_umap.ug_gidbase,
+		      &arg32->ca32_umap.ug32_gidbase);
+	err |= __get_user(karg->ca_umap.ug_uidlen,
+		      &arg32->ca32_umap.ug32_gidlen);
+	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
+	if (err)
+		return -EFAULT;
+	karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
+					  GFP_USER);
+	if(!karg->ca_umap.ug_gdimap)
+		return -ENOMEM;
+	for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
+		err |= __get_user(karg->ca_umap.ug_gdimap[i],
+			      &(((__kernel_gid_t32 *)A(uaddr))[i]));
+
+	return err;
+}
+
+static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfh.gf_addr,
+			  &arg32->ca32_getfh.gf32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= __get_user(karg->ca_getfh.gf_dev,
+		      &arg32->ca32_getfh.gf32_dev);
+	err |= __get_user(karg->ca_getfh.gf_ino,
+		      &arg32->ca32_getfh.gf32_ino);
+	err |= __get_user(karg->ca_getfh.gf_version,
+		      &arg32->ca32_getfh.gf32_version);
+
+	if(err) return -EFAULT;
+	return 0;
+}
+
+static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfd.gd_addr,
+			  &arg32->ca32_getfd.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfd.gd_path,
+			  &arg32->ca32_getfd.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfd.gd_version,
+		      &arg32->ca32_getfd.gd32_version);
+
+	if(err) return -EFAULT;
+	return 0;
+}
+
+static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfs.gd_addr,
+			  &arg32->ca32_getfs.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfs.gd_path,
+			  &arg32->ca32_getfs.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfs.gd_maxlen,
+		      &arg32->ca32_getfs.gd32_maxlen);
+
+	if(err) return -EFAULT;
+	return 0;
+}
+
+/* This really doesn't need translations, we are only passing
+ * back a union which contains opaque nfs file handle data.
+ */
+static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
+{
+	int err;
+
+	err = copy_to_user(res32, kres, sizeof(*res32));
+
+	if(err) return -EFAULT;
+	return 0;
+}
+
+/* Note: it is necessary to treat cmd_parm as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+int asmlinkage sys32_nfsservctl(u32 cmd_parm, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+{
+  int cmd = (int)cmd_parm;
+	struct nfsctl_arg *karg = NULL;
+	union nfsctl_res *kres = NULL;
+	mm_segment_t oldfs;
+	int err;
+
+	karg = kmalloc(sizeof(*karg), GFP_USER);
+	if(!karg)
+		return -ENOMEM;
+	if(res32) {
+		kres = kmalloc(sizeof(*kres), GFP_USER);
+		if(!kres) {
+			kfree(karg);
+			return -ENOMEM;
+		}
+	}
+	switch(cmd) {
+	case NFSCTL_SVC:
+		err = nfs_svc32_trans(karg, arg32);
+		break;
+	case NFSCTL_ADDCLIENT:
+		err = nfs_clnt32_trans(karg, arg32);
+		break;
+	case NFSCTL_DELCLIENT:
+		err = nfs_clnt32_trans(karg, arg32);
+		break;
+	case NFSCTL_EXPORT:
+	case NFSCTL_UNEXPORT:
+		err = nfs_exp32_trans(karg, arg32);
+		break;
+	/* This one is unimplemented, be we're ready for it. */
+	case NFSCTL_UGIDUPDATE:
+		err = nfs_uud32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFH:
+		err = nfs_getfh32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFD:
+		err = nfs_getfd32_trans(karg, arg32);
+		break;
+	case NFSCTL_GETFS:
+		err = nfs_getfs32_trans(karg, arg32);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	if(err)
+		goto done;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_nfsservctl(cmd, karg, kres);
+	set_fs(oldfs);
+
+	if (err)
+		goto done;
+
+	if((cmd == NFSCTL_GETFH) ||
+	   (cmd == NFSCTL_GETFD) ||
+	   (cmd == NFSCTL_GETFS))
+		err = nfs_getfh32_res_trans(kres, res32);
+
+done:
+	if(karg) {
+		if(cmd == NFSCTL_UGIDUPDATE) {
+			if(karg->ca_umap.ug_ident)
+				kfree(karg->ca_umap.ug_ident);
+			if(karg->ca_umap.ug_udimap)
+				kfree(karg->ca_umap.ug_udimap);
+			if(karg->ca_umap.ug_gdimap)
+				kfree(karg->ca_umap.ug_gdimap);
+		}
+		kfree(karg);
+	}
+	if(kres)
+		kfree(kres);
+	return err;
+}
+
+
+
+struct timespec32 {
+	s32    tv_sec;
+	s32    tv_nsec;
+};
+
+extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+
+asmlinkage long sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
+{
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	PPCDBG(PPCDBG_SYS32NI, "sys32_nanosleep - running - pid=%ld, comm=%s \n", current->pid, current->comm);
+	
+	if (get_user (t.tv_sec, &rqtp->tv_sec) ||
+	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+	set_fs (old_fs);
+	if (rmtp && ret == -EINTR) {
+		if (__put_user (t.tv_sec, &rmtp->tv_sec) ||
+	    	    __put_user (t.tv_nsec, &rmtp->tv_nsec))
+			return -EFAULT;
+	}
+	
+	return ret;
+}
+
+
+
+
+/* These are here just in case some old sparc32 binary calls it. */
+asmlinkage long sys32_pause(void)
+{
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_pause - running - pid=%ld, comm=%s \n", current->pid, current->comm);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	
+	return -ERESTARTNOHAND;
+}
+
+
+
+static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+		(__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+		 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+		 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+		 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
+
+static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+		 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+		 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+		 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
+}
+
+static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+{
+	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+		(__get_user(o->tv_sec, &i->tv_sec) |
+		 __get_user(o->tv_usec, &i->tv_usec)));
+}
+
+static inline long put_tv32(struct timeval32 *o, struct timeval *i)
+{
+	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+		(__put_user(i->tv_sec, &o->tv_sec) |
+		 __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+
+
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+/* Note: it is necessary to treat which as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_getitimer(u32 which, struct itimerval32 *it)
+{
+	struct itimerval kit;
+	int error;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_getitimer - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	error = do_getitimer((int)which, &kit);
+	if (!error && put_it32(it, &kit))
+		error = -EFAULT;
+
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_getitimer - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+	return error;
+}
+
+
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+/* Note: it is necessary to treat which as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_setitimer(u32 which, struct itimerval32 *in, struct itimerval32 *out)
+{
+	struct itimerval kin, kout;
+	int error;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_setitimer - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	if (in) {
+		if (get_it32(&kin, in))
+			return -EFAULT;
+	} else
+		memset(&kin, 0, sizeof(kin));
+
+	error = do_setitimer((int)which, &kin, out ? &kout : NULL);
+	if (error || !out)
+		return error;
+	if (put_it32(out, &kout))
+		return -EFAULT;
+
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_setitimer - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+	return 0;
+}
+
+#define RLIM_INFINITY32	0xffffffff
+#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+
+struct rlimit32 {
+	u32	rlim_cur;
+	u32	rlim_max;
+};
+
+extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+asmlinkage long sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs(old_fs);
+	if (!ret) {
+		ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
+		ret |= __put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max);
+	}
+	
+	return ret;
+}
+
+/* Back compatibility for getrlimit. Needed for some apps. */
+asmlinkage long sys32_old_getrlimit(unsigned int resource, struct rlimit32* rlim)
+{
+	struct rlimit   x;    // 64-bit version of the resource limits.
+	struct rlimit32 x32;  // 32-bit version of the resource limits.
+	long rc = 0;
+	
+	if (resource >= RLIM_NLIMITS) {
+		PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - specified resource is too large (%x) - pid=%ld, comm=%s\n", resource, current->pid, current->comm);
+		return -EINVAL;
+	}
+
+	memcpy(&x, current->rlim+resource, sizeof(struct rlimit));
+
+	if(x.rlim_cur > RLIM_INFINITY32)
+		x32.rlim_cur = RLIM_INFINITY32;
+	else
+		x32.rlim_cur = x.rlim_cur;
+
+	if(x.rlim_max > RLIM_INFINITY32)
+		x32.rlim_max = RLIM_INFINITY32;
+	else
+		x32.rlim_max = x.rlim_max;
+
+	rc = (copy_to_user(rlim, &x32, sizeof(x32))) ? (-EFAULT) : 0;
+	if (rc == 0) {
+		PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - current=%x, maximum=%x - pid=%ld, comm=%s\n", x32.rlim_cur, x32.rlim_max, current->pid, current->comm);
+	} else {
+		PPCDBG(PPCDBG_SYS32, "sys32_old_getrlimit - unable to copy into user's storage - pid=%ld, comm=%s\n", current->pid, current->comm);
+	}
+	return rc;
+}
+
+extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	long ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_setrlimit - entered - resource=%x, rlim=%p - pid=%ld, comm=%s\n", resource, rlim, current->pid, current->comm);
+
+	if (resource >= RLIM_NLIMITS) return -EINVAL;	
+	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user (r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+	if (r.rlim_cur >= RLIM_INFINITY32)
+		r.rlim_cur = RLIM_INFINITY;
+	if (r.rlim_max >= RLIM_INFINITY32)
+		r.rlim_max = RLIM_INFINITY;
+	set_fs (KERNEL_DS);
+	ret = sys_setrlimit(resource, &r);
+	set_fs (old_fs);
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_setrlimit - exited w/ ret=%x - pid=%ld, comm=%s\n", ret, current->pid, current->comm);
+	return ret;
+}
+
+
+struct rusage32 {
+        struct timeval32 ru_utime;
+        struct timeval32 ru_stime;
+        s32    ru_maxrss;
+        s32    ru_ixrss;
+        s32    ru_idrss;
+        s32    ru_isrss;
+        s32    ru_minflt;
+        s32    ru_majflt;
+        s32    ru_nswap;
+        s32    ru_inblock;
+        s32    ru_oublock;
+        s32    ru_msgsnd; 
+        s32    ru_msgrcv; 
+        s32    ru_nsignals;
+        s32    ru_nvcsw;
+        s32    ru_nivcsw;
+};
+
+static int put_rusage (struct rusage32 *ru, struct rusage *r)
+{
+	int err;
+	
+	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
+	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
+	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
+	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
+	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
+	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
+	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
+	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
+	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
+	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
+	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
+	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
+	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
+	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
+	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
+	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
+	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
+	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
+	return err;
+}
+
+
+extern asmlinkage long sys_getrusage(int who, struct rusage *ru);
+
+/* Note: it is necessary to treat who as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_getrusage(u32 who, struct rusage32 *ru)
+{
+	struct rusage r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_getrusage - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+		
+	set_fs (KERNEL_DS);
+	ret = sys_getrusage((int)who, &r);
+	set_fs (old_fs);
+	if (put_rusage (ru, &r)) 
+		return -EFAULT;
+
+	return ret;
+}
+
+
+
+
+struct sysinfo32 {
+        s32 uptime;
+        u32 loads[3];
+        u32 totalram;
+        u32 freeram;
+        u32 sharedram;
+        u32 bufferram;
+        u32 totalswap;
+        u32 freeswap;
+        unsigned short procs;
+        char _f[22];
+};
+
+extern asmlinkage long sys_sysinfo(struct sysinfo *info);
+
+asmlinkage long sys32_sysinfo(struct sysinfo32 *info)
+{
+	struct sysinfo s;
+	int ret, err;
+	mm_segment_t old_fs = get_fs ();
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sysinfo - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sysinfo(&s);
+	set_fs (old_fs);
+	err = put_user (s.uptime, &info->uptime);
+	err |= __put_user (s.loads[0], &info->loads[0]);
+	err |= __put_user (s.loads[1], &info->loads[1]);
+	err |= __put_user (s.loads[2], &info->loads[2]);
+	err |= __put_user (s.totalram, &info->totalram);
+	err |= __put_user (s.freeram, &info->freeram);
+	err |= __put_user (s.sharedram, &info->sharedram);
+	err |= __put_user (s.bufferram, &info->bufferram);
+	err |= __put_user (s.totalswap, &info->totalswap);
+	err |= __put_user (s.freeswap, &info->freeswap);
+	err |= __put_user (s.procs, &info->procs);
+	if (err)
+		return -EFAULT;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sysinfo - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return ret;
+}
+
+
+
+
+/* Translations due to time_t size differences.  Which affects all
+   sorts of things, like timeval and itimerval.  */
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage long sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_gettimeofday - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+
+	if (tv) {
+		struct timeval ktv;
+		do_gettimeofday(&ktv);
+		if (put_tv32(tv, &ktv))
+			return -EFAULT;
+	}
+	if (tz) {
+		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+			return -EFAULT;
+	}
+	
+	return 0;
+}
+
+
+
+asmlinkage long sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+	struct timeval ktv;
+	struct timezone ktz;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_settimeofday - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+ 	if (tv) {
+		if (get_tv32(&ktv, tv))
+			return -EFAULT;
+	}
+	if (tz) {
+		if (copy_from_user(&ktz, tz, sizeof(ktz)))
+			return -EFAULT;
+	}
+
+	return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+
+
+
+struct tms32 {
+	__kernel_clock_t32 tms_utime;
+	__kernel_clock_t32 tms_stime;
+	__kernel_clock_t32 tms_cutime;
+	__kernel_clock_t32 tms_cstime;
+};
+                                
+extern asmlinkage long sys_times(struct tms * tbuf);
+
+asmlinkage long sys32_times(struct tms32 *tbuf)
+{
+	struct tms t;
+	long ret;
+	mm_segment_t old_fs = get_fs ();
+	int err;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_times - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	
+	set_fs (KERNEL_DS);
+	ret = sys_times(tbuf ? &t : NULL);
+	set_fs (old_fs);
+	if (tbuf) {
+		err = put_user (t.tms_utime, &tbuf->tms_utime);
+		err |= __put_user (t.tms_stime, &tbuf->tms_stime);
+		err |= __put_user (t.tms_cutime, &tbuf->tms_cutime);
+		err |= __put_user (t.tms_cstime, &tbuf->tms_cstime);
+		if (err)
+			ret = -EFAULT;
+	}
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_times - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return ret;
+}
+
+struct msgbuf32 { s32 mtype; char mtext[1]; };
+
+struct semid_ds32 {
+	struct ipc_perm sem_perm;
+	__kernel_time_t32 sem_otime;
+	__kernel_time_t32 sem_ctime;
+	u32 sem_base;
+	u32 sem_pending;
+	u32 sem_pending_last;
+	u32 undo;
+	unsigned short sem_nsems;
+};
+
+struct semid64_ds32 {
+	struct ipc64_perm sem_perm;
+	unsigned int __unused1;
+	__kernel_time_t32 sem_otime;
+	unsigned int __unused2;
+	__kernel_time_t32 sem_ctime;
+	u32 sem_nsems;
+	u32 __unused3;
+	u32 __unused4;
+};
+
+struct msqid_ds32
+{
+	struct ipc_perm msg_perm;
+	u32 msg_first;
+	u32 msg_last;
+	__kernel_time_t32 msg_stime;
+	__kernel_time_t32 msg_rtime;
+	__kernel_time_t32 msg_ctime;
+	u32 msg_lcbytes;
+	u32 msg_lqbytes;
+	unsigned short msg_cbytes;
+	unsigned short msg_qnum;
+	unsigned short msg_qbytes;
+	__kernel_ipc_pid_t32 msg_lspid;
+	__kernel_ipc_pid_t32 msg_lrpid;
+};
+
+struct msqid64_ds32 {
+	struct ipc64_perm msg_perm;
+	unsigned int __unused1;
+	__kernel_time_t32 msg_stime;
+	unsigned int __unused2;
+	__kernel_time_t32 msg_rtime;
+	unsigned int __unused3;
+	__kernel_time_t32 msg_ctime;
+	unsigned int msg_cbytes;
+	unsigned int msg_qnum;
+	unsigned int msg_qbytes;
+	__kernel_pid_t32 msg_lspid;
+	__kernel_pid_t32 msg_lrpid;
+	unsigned int __unused4;
+	unsigned int __unused5;
+};
+
+struct shmid_ds32 {
+	struct ipc_perm shm_perm;
+	int shm_segsz;
+	__kernel_time_t32 shm_atime;
+	__kernel_time_t32 shm_dtime;
+	__kernel_time_t32 shm_ctime;
+	__kernel_ipc_pid_t32 shm_cpid;
+	__kernel_ipc_pid_t32 shm_lpid;
+	unsigned short shm_nattch;
+	unsigned short __unused;
+	unsigned int __unused2;
+	unsigned int __unused3;
+};
+
+struct shmid64_ds32 {
+	struct ipc64_perm shm_perm;
+	unsigned int __unused1;
+	__kernel_time_t32 shm_atime;
+	unsigned int __unused2;
+	__kernel_time_t32 shm_dtime;
+	unsigned int __unused3;
+	__kernel_time_t32 shm_ctime;
+	unsigned int __unused4;
+	__kernel_size_t32 shm_segsz;
+	__kernel_pid_t32 shm_cpid;
+	__kernel_pid_t32 shm_lpid;
+	unsigned int shm_nattch;
+	unsigned int __unused5;
+	unsigned int __unused6;
+};
+
+/*
+ * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit
+ * emulation..
+ *
+ * This is really horribly ugly.
+ */
+static long do_sys32_semctl(int first, int second, int third, void *uptr)
+{
+	union semun fourth;
+	u32 pad;
+	int err, err2;
+	mm_segment_t old_fs;
+
+	if (!uptr)
+		return -EINVAL;
+	err = -EFAULT;
+	if (get_user(pad, (u32 *)uptr))
+		return err;
+	if (third == SETVAL)
+		fourth.val = (int)pad;
+	else
+		fourth.__pad = (void *)A(pad);
+	switch (third & (~IPC_64)) {
+
+	case IPC_INFO:
+	case IPC_RMID:
+	case SEM_INFO:
+	case GETVAL:
+	case GETPID:
+	case GETNCNT:
+	case GETZCNT:
+	case GETALL:
+	case SETALL:
+	case SETVAL:
+		err = sys_semctl(first, second, third, fourth);
+		break;
+
+	case IPC_STAT:
+	case SEM_STAT:
+		if (third & IPC_64) {
+			struct semid64_ds s64;
+			struct semid64_ds32 *usp;
+
+			usp = (struct semid64_ds32 *)A(pad);
+			fourth.__pad = &s64;
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_semctl(first, second, third, fourth);
+			set_fs(old_fs);
+			err2 = copy_to_user(&usp->sem_perm, &s64.sem_perm,
+					    sizeof(struct ipc64_perm));
+			err2 |= __put_user(s64.sem_otime, &usp->sem_otime);
+			err2 |= __put_user(s64.sem_ctime, &usp->sem_ctime);
+			err2 |= __put_user(s64.sem_nsems, &usp->sem_nsems);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			struct semid_ds s;
+			struct semid_ds32 *usp;
+
+			usp = (struct semid_ds32 *)A(pad);
+			fourth.__pad = &s;
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_semctl(first, second, third, fourth);
+			set_fs(old_fs);
+			err2 = copy_to_user(&usp->sem_perm, &s.sem_perm,
+					    sizeof(struct ipc_perm));
+			err2 |= __put_user(s.sem_otime, &usp->sem_otime);
+			err2 |= __put_user(s.sem_ctime, &usp->sem_ctime);
+			err2 |= __put_user(s.sem_nsems, &usp->sem_nsems);
+			if (err2)
+				err = -EFAULT;
+		}
+		break;
+ 
+	case IPC_SET:
+		if (third & IPC_64) {
+			struct semid64_ds s64;
+			struct semid64_ds32 *usp;
+
+			usp = (struct semid64_ds32 *)A(pad);
+
+			err = get_user(s64.sem_perm.uid, &usp->sem_perm.uid);
+			err |= __get_user(s64.sem_perm.gid,
+					  &usp->sem_perm.gid);
+			err |= __get_user(s64.sem_perm.mode,
+					  &usp->sem_perm.mode);
+			if (err)
+				goto out;
+			fourth.__pad = &s64;
+
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_semctl(first, second, third, fourth);
+			set_fs(old_fs);
+
+		} else {
+			struct semid_ds s;
+			struct semid_ds32 *usp;
+
+			usp = (struct semid_ds32 *)A(pad);
+
+			err = get_user(s.sem_perm.uid, &usp->sem_perm.uid);
+			err |= __get_user(s.sem_perm.gid,
+					  &usp->sem_perm.gid);
+			err |= __get_user(s.sem_perm.mode,
+					  &usp->sem_perm.mode);
+			if (err)
+				goto out;
+			fourth.__pad = &s;
+
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_semctl(first, second, third, fourth);
+			set_fs(old_fs);
+		}
+		break;
+	}
+out:
+	return err;
+}
+
+static int 
+do_sys32_msgsnd(int first, int second, int third, void *uptr)
+{
+	struct msgbuf *p;
+	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+	mm_segment_t old_fs;
+	int err;
+
+	if (second < 0)
+		return -EINVAL;
+
+	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+	if (!p)
+		return -ENOMEM;
+	err = get_user(p->mtype, &up->mtype);
+	err |= __copy_from_user(p->mtext, &up->mtext, second);
+	if (err) {
+		err = -EFAULT;
+		goto out;
+	}
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgsnd(first, p, second, third);
+	set_fs(old_fs);
+out:
+	kfree(p);
+	return err;
+}
+
+static int
+do_sys32_msgrcv(int first, int second, int msgtyp, int third,
+		int version, void *uptr)
+{
+	struct msgbuf32 *up;
+	struct msgbuf *p;
+	mm_segment_t old_fs;
+	int err;
+
+	if (second < 0)
+		return -EINVAL;
+
+	if (!version) {
+		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
+		struct ipc_kludge ipck;
+
+		err = -EINVAL;
+		if (!uptr)
+			goto out;
+		err = -EFAULT;
+		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
+			goto out;
+		uptr = (void *)A(ipck.msgp);
+		msgtyp = ipck.msgtyp;
+	}
+	err = -ENOMEM;
+	p = kmalloc(second + sizeof (struct msgbuf) + 4, GFP_USER);
+	if (!p)
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgrcv(first, p, second + 4, msgtyp, third);
+	set_fs(old_fs);
+	if (err < 0)
+		goto free_then_out;
+	up = (struct msgbuf32 *)uptr;
+	if (put_user(p->mtype, &up->mtype) ||
+	    __copy_to_user(&up->mtext, p->mtext, err))
+		err = -EFAULT;
+free_then_out:
+	kfree(p);
+out:
+	return err;
+}
+
+static int
+do_sys32_msgctl(int first, int second, void *uptr)
+{
+	int err = -EINVAL, err2;
+	mm_segment_t old_fs;
+
+	switch (second & (~IPC_64)) {
+
+	case IPC_INFO:
+	case IPC_RMID:
+	case MSG_INFO:
+		err = sys_msgctl(first, second, (struct msqid_ds *)uptr);
+		break;
+
+	case IPC_SET:
+		if (second & IPC_64) {
+			struct msqid64_ds m64;
+			struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
+
+			err2 = copy_from_user(&m64.msg_perm, &up->msg_perm,
+					      sizeof(struct ipc64_perm));
+			err2 |= __get_user(m64.msg_qbytes, &up->msg_qbytes);
+			if (err2) {
+				err = -EFAULT;
+				break;
+			}
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_msgctl(first, second,
+					 (struct msqid_ds *)&m64);
+			set_fs(old_fs);
+		} else {
+			struct msqid_ds m;
+			struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+
+			err2 = copy_from_user(&m.msg_perm, &up->msg_perm,
+					      sizeof(struct ipc_perm));
+			err2 |= __get_user(m.msg_qbytes, &up->msg_qbytes);
+			if (err2) {
+				err = -EFAULT;
+				break;
+			}
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_msgctl(first, second, &m);
+			set_fs(old_fs);
+		}
+		break;
+
+	case IPC_STAT:
+	case MSG_STAT:
+		if (second & IPC_64) {
+			struct msqid64_ds m64;
+			struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
+
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_msgctl(first, second,
+					 (struct msqid_ds *)&m64);
+			set_fs(old_fs);
+
+			err2 = copy_to_user(&up->msg_perm, &m64.msg_perm,
+					    sizeof(struct ipc64_perm));
+ 			err2 |= __put_user(m64.msg_stime, &up->msg_stime);
+			err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
+			err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
+			err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes);
+			err2 |= __put_user(m64.msg_qnum, &up->msg_qnum);
+			err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes);
+			err2 |= __put_user(m64.msg_lspid, &up->msg_lspid);
+			err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			struct msqid64_ds m;
+			struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_msgctl(first, second, (struct msqid_ds *)&m);
+			set_fs(old_fs);
+
+			err2 = copy_to_user(&up->msg_perm, &m.msg_perm,
+					    sizeof(struct ipc_perm));
+ 			err2 |= __put_user(m.msg_stime, &up->msg_stime);
+			err2 |= __put_user(m.msg_rtime, &up->msg_rtime);
+			err2 |= __put_user(m.msg_ctime, &up->msg_ctime);
+			err2 |= __put_user(m.msg_cbytes, &up->msg_cbytes);
+			err2 |= __put_user(m.msg_qnum, &up->msg_qnum);
+			err2 |= __put_user(m.msg_qbytes, &up->msg_qbytes);
+			err2 |= __put_user(m.msg_lspid, &up->msg_lspid);
+			err2 |= __put_user(m.msg_lrpid, &up->msg_lrpid);
+			if (err2)
+				err = -EFAULT;
+		}
+		break;
+	}
+#if 0
+	udbg_printf("  err3 = 0x%lx\n", err); 
+#endif
+	return err;
+}
+
+static int
+do_sys32_shmat(int first, int second, int third, int version, void *uptr)
+{
+	unsigned long raddr;
+	u32 *uaddr = (u32 *)A((u32)third);
+	int err = -EINVAL;
+
+	if (version == 1)
+		return err;
+	err = sys_shmat(first, uptr, second, &raddr);
+	if (err)
+		return err;
+	err = put_user(raddr, uaddr);
+	return err;
+}
+
+static int
+do_sys32_shmctl(int first, int second, void *uptr)
+{
+	int err = -EFAULT, err2;
+	mm_segment_t old_fs;
+
+	switch (second & (~IPC_64)) {
+
+	case IPC_INFO:
+	case IPC_RMID:
+	case SHM_LOCK:
+	case SHM_UNLOCK:
+		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
+		break;
+	case IPC_SET:
+		if (second & IPC_64) {
+			struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr;
+			struct shmid64_ds s64;
+
+			err = get_user(s64.shm_perm.uid, &up->shm_perm.uid);
+			err |= __get_user(s64.shm_perm.gid, &up->shm_perm.gid);
+			err |= __get_user(s64.shm_perm.mode,
+					  &up->shm_perm.mode);
+			if (err)
+				break;
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_shmctl(first, second,
+					 (struct shmid_ds *)&s64);
+			set_fs(old_fs);
+		} else {
+			struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+			struct shmid_ds s;
+
+			err = get_user(s.shm_perm.uid, &up->shm_perm.uid);
+			err |= __get_user(s.shm_perm.gid, &up->shm_perm.gid);
+			err |= __get_user(s.shm_perm.mode, &up->shm_perm.mode);
+			if (err)
+				break;
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_shmctl(first, second, &s);
+			set_fs(old_fs);
+		}
+		break;
+
+	case IPC_STAT:
+	case SHM_STAT:
+		if (second & IPC_64) {
+			struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr;
+			struct shmid64_ds s64;
+
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_shmctl(first, second,
+					 (struct shmid_ds *)&s64);
+			set_fs(old_fs);
+			if (err < 0)
+				break;
+
+			err2 = copy_to_user(&up->shm_perm, &s64.shm_perm,
+					    sizeof(struct ipc64_perm));
+			err2 |= __put_user(s64.shm_atime, &up->shm_atime);
+			err2 |= __put_user(s64.shm_dtime, &up->shm_dtime);
+			err2 |= __put_user(s64.shm_ctime, &up->shm_ctime);
+			err2 |= __put_user(s64.shm_segsz, &up->shm_segsz);
+			err2 |= __put_user(s64.shm_nattch, &up->shm_nattch);
+			err2 |= __put_user(s64.shm_cpid, &up->shm_cpid);
+			err2 |= __put_user(s64.shm_lpid, &up->shm_lpid);
+			if (err2)
+				err = -EFAULT;
+		} else {
+			struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+			struct shmid_ds s;
+
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			err = sys_shmctl(first, second, &s);
+			set_fs(old_fs);
+			if (err < 0)
+				break;
+
+			err2 = copy_to_user(&up->shm_perm, &s.shm_perm,
+					    sizeof(struct ipc_perm));
+			err2 |= __put_user (s.shm_atime, &up->shm_atime);
+			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
+			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
+			err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
+			err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
+			err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
+			err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
+			if (err2)
+				err = -EFAULT;
+		}
+		break;
+
+	case SHM_INFO: {
+		struct shm_info si;
+		struct shm_info32 {
+			int used_ids;
+			u32 shm_tot, shm_rss, shm_swp;
+			u32 swap_attempts, swap_successes;
+		} *uip = (struct shm_info32 *)uptr;
+
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_shmctl(first, second, (struct shmid_ds *)&si);
+		set_fs(old_fs);
+		if (err < 0)
+			break;
+		err2 = put_user(si.used_ids, &uip->used_ids);
+		err2 |= __put_user(si.shm_tot, &uip->shm_tot);
+		err2 |= __put_user(si.shm_rss, &uip->shm_rss);
+		err2 |= __put_user(si.shm_swp, &uip->shm_swp);
+		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
+		err2 |= __put_user(si.swap_successes, &uip->swap_successes);
+		if (err2)
+			err = -EFAULT;
+		break;
+	}
+	}
+	return err;
+}
+
+/*
+ * Note: it is necessary to treat first_parm, second_parm, and
+ * third_parm as unsigned ints, with the corresponding cast to a
+ * signed int to insure that the proper conversion (sign extension)
+ * between the register representation of a signed int (msr in 32-bit
+ * mode) and the register representation of a signed int (msr in
+ * 64-bit mode) is performed.
+ */
+asmlinkage long sys32_ipc(u32 call, u32 first_parm, u32 second_parm, u32 third_parm, u32 ptr, u32 fifth)
+{
+	int first  = (int)first_parm;
+	int second = (int)second_parm;
+	int third  = (int)third_parm;
+	int version, err;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_ipc - entered - call=%x, parm1=%x, parm2=%x, parm3=%x, parm4=%x, parm5=%x \n", 
+         call, first_parm, second_parm, third_parm, ptr, fifth);
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+
+	case SEMOP:
+		/* struct sembuf is the same on 32 and 64bit :)) */
+		err = sys_semop(first, (struct sembuf *)AA(ptr),
+				second);
+		break;
+	case SEMGET:
+		err = sys_semget(first, second, third);
+		break;
+	case SEMCTL:
+		err = do_sys32_semctl(first, second, third,
+				      (void *)AA(ptr));
+		break;
+
+	case MSGSND:
+		err = do_sys32_msgsnd(first, second, third,
+				      (void *)AA(ptr));
+		break;
+	case MSGRCV:
+		err = do_sys32_msgrcv(first, second, fifth, third,
+				      version, (void *)AA(ptr));
+		break;
+	case MSGGET:
+		err = sys_msgget((key_t)first, second);
+		break;
+	case MSGCTL:
+		err = do_sys32_msgctl(first, second, (void *)AA(ptr));
+		break;
+
+	case SHMAT:
+		err = do_sys32_shmat(first, second, third,
+				     version, (void *)AA(ptr));
+		break;
+	case SHMDT: 
+		err = sys_shmdt((char *)AA(ptr));
+		break;
+	case SHMGET:
+		err = sys_shmget(first, second, third);
+		break;
+	case SHMCTL:
+		err = do_sys32_shmctl(first, second, (void *)AA(ptr));
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_ipc - exited w/ %d/0x%x \n", err, err);
+	return err;
+}
+
+/* stat syscall methods. */
+extern asmlinkage int sys_stat(char* filename, struct __old_kernel_stat* statbuf);
+
+static int cp_old_stat32(struct inode* inode, struct __old_kernel_stat32* statbuf)
+{
+	static int warncount = 5;
+	struct __old_kernel_stat32 tmp;
+
+	if (warncount) {
+		warncount--;
+		printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
+			current->comm);
+	}
+
+	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
+	tmp.st_ino = inode->i_ino;
+	tmp.st_mode = inode->i_mode;
+	tmp.st_nlink = inode->i_nlink;
+	SET_OLDSTAT_UID(tmp, inode->i_uid);
+	SET_OLDSTAT_GID(tmp, inode->i_gid);
+	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
+	tmp.st_size = inode->i_size;
+	tmp.st_atime = inode->i_atime;
+	tmp.st_mtime = inode->i_mtime;
+	tmp.st_ctime = inode->i_ctime;
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys32_stat(char* filename, struct __old_kernel_stat32* statbuf)
+{
+	struct nameidata nd;
+	int error;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_stat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	error = user_path_walk(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
+		if (!error)
+			error = cp_old_stat32(nd.dentry->d_inode, statbuf);
+		path_release(&nd);
+	}
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_stat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return error;
+}
+
+asmlinkage long sys32_fstat(unsigned int fd, struct __old_kernel_stat32* statbuf)
+{
+	struct file *f;
+	int err = -EBADF;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_fstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	f = fget(fd);
+	if (f) {
+		struct dentry * dentry = f->f_dentry;
+
+		err = do_revalidate(dentry);
+		if (!err)
+			err = cp_old_stat32(dentry->d_inode, statbuf);
+		fput(f);
+	}
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_fstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return err;
+}
+
+asmlinkage long sys32_lstat(char* filename, struct __old_kernel_stat32* statbuf)
+{
+	struct nameidata nd;
+	int error;
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_lstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	error = user_path_walk_link(filename, &nd);
+	if (!error) {
+		error = do_revalidate(nd.dentry);
+		if (!error)
+			error = cp_old_stat32(nd.dentry->d_inode, statbuf);
+
+		path_release(&nd);
+	}
+	
+	PPCDBG(PPCDBG_SYS32X, "sys32_lstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return error;
+}
+
+extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
+
+/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, __kernel_off_t32* offset, u32 count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	off_t of;
+	
+	if (offset && get_user(of, offset))
+		return -EFAULT;
+		
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile((int)out_fd, (int)in_fd, offset ? &of : NULL, count);
+	set_fs(old_fs);
+	
+	if (offset && put_user(of, offset))
+		return -EFAULT;
+		
+	return ret;
+}
+
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
+
+asmlinkage long sys32_setsockopt(int fd, int level, int optname, char* optval, int optlen)
+{
+	
+	PPCDBG(PPCDBG_SYS32,"sys32_setsockopt - running - pid=%ld, comm=%s\n", current->pid, current->comm);
+
+	if (optname == SO_ATTACH_FILTER) {
+		struct sock_fprog32 {
+			__u16 len;
+			__u32 filter;
+		} *fprog32 = (struct sock_fprog32 *)optval;
+		struct sock_fprog kfprog;
+		struct sock_filter *kfilter;
+		unsigned int fsize;
+		mm_segment_t old_fs;
+		__u32 uptr;
+		int ret;
+
+		if (get_user(kfprog.len, &fprog32->len) ||
+		    __get_user(uptr, &fprog32->filter))
+			return -EFAULT;
+		kfprog.filter = (struct sock_filter *)A(uptr);
+		fsize = kfprog.len * sizeof(struct sock_filter);
+		kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+		if (kfilter == NULL)
+			return -ENOMEM;
+		if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+			kfree(kfilter);
+			return -EFAULT;
+		}
+		kfprog.filter = kfilter;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = sys_setsockopt(fd, level, optname,
+				     (char *)&kfprog, sizeof(kfprog));
+		set_fs(old_fs);
+		kfree(kfilter);
+		return ret;
+	}
+	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
+
+
+
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain -  16 for IP, 16 for IPX, 24 for IPv6, about 80 for AX.25 */
+#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+
+#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
+
+#define CMSG32_DATA(cmsg)	((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
+#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
+#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
+#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \
+				    (struct cmsghdr32 *)(ctl) : \
+				    (struct cmsghdr32 *)NULL)
+#define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+struct msghdr32
+{
+	u32               msg_name;
+	int               msg_namelen;
+	u32               msg_iov;
+	__kernel_size_t32 msg_iovlen;
+	u32               msg_control;
+	__kernel_size_t32 msg_controllen;
+	unsigned          msg_flags;
+};
+
+struct cmsghdr32
+{
+	__kernel_size_t32 cmsg_len;
+	int               cmsg_level;
+	int               cmsg_type;
+};
+
+__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
+					     struct cmsghdr32 *__cmsg, int __cmsg_len)
+{
+	struct cmsghdr32 * __ptr;
+
+	__ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +
+				     CMSG32_ALIGN(__cmsg_len));
+	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+		return NULL;
+
+	return __ptr;
+}
+
+__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg,
+					    struct cmsghdr32 *__cmsg,
+					    int __cmsg_len)
+{
+	return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,
+			       __cmsg, __cmsg_len);
+}
+
+extern __inline__ struct socket *socki_lookup(struct inode *inode)
+{
+	return &inode->u.socket_i;
+}
+
+extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
+{
+	struct file *file;
+	struct inode *inode;
+
+	if (!(file = fget(fd)))
+	{
+		*err = -EBADF;
+		return NULL;
+	}
+
+	inode = file->f_dentry->d_inode;
+	if (!inode || !inode->i_sock || !socki_lookup(inode))
+	{
+		*err = -ENOTSOCK;
+		fput(file);
+		return NULL;
+	}
+
+	return socki_lookup(inode);
+}
+
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg)
+{
+	u32 tmp1, tmp2, tmp3;
+	int err;
+
+	err = get_user(tmp1, &umsg->msg_name);
+	err |= __get_user(tmp2, &umsg->msg_iov);
+	err |= __get_user(tmp3, &umsg->msg_control);
+	if (err)
+		return -EFAULT;
+
+	kmsg->msg_name = (void *)A(tmp1);
+	kmsg->msg_iov = (struct iovec *)A(tmp2);
+	kmsg->msg_control = (void *)A(tmp3);
+
+	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
+	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+	
+	return err;
+}
+
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+					  struct iovec32 *uiov32,
+					  int niov)
+{
+	int tot_len = 0;
+
+	while(niov > 0) {
+		u32 len, buf;
+
+		if(get_user(len, &uiov32->iov_len) ||
+		   get_user(buf, &uiov32->iov_base)) {
+			tot_len = -EFAULT;
+			break;
+		}
+		tot_len += len;
+		kiov->iov_base = (void *)A(buf);
+		kiov->iov_len = (__kernel_size_t) len;
+		uiov32++;
+		kiov++;
+		niov--;
+	}
+	return tot_len;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+			  char *kern_address, int mode)
+{
+	int tot_len;
+
+	if(kern_msg->msg_namelen) {
+		if(mode==VERIFY_READ) {
+			int err = move_addr_to_kernel(kern_msg->msg_name,
+						      kern_msg->msg_namelen,
+						      kern_address);
+			if(err < 0)
+				return err;
+		}
+		kern_msg->msg_name = kern_address;
+	} else
+		kern_msg->msg_name = NULL;
+
+	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+				   GFP_KERNEL);
+		if(!kern_iov)
+			return -ENOMEM;
+	}
+
+	tot_len = iov_from_user32_to_kern(kern_iov,
+					  (struct iovec32 *)kern_msg->msg_iov,
+					  kern_msg->msg_iovlen);
+	if(tot_len >= 0)
+		kern_msg->msg_iov = kern_iov;
+	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+		kfree(kern_iov);
+
+	return tot_len;
+}
+
+/* There is a lot of hair here because the alignment rules (and
+ * thus placement) of cmsg headers and length are different for
+ * 32-bit apps.  -DaveM
+ */
+static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
+				       unsigned char *stackbuf, int stackbuf_size)
+{
+	struct cmsghdr32 *ucmsg;
+	struct cmsghdr *kcmsg, *kcmsg_base;
+	__kernel_size_t32 ucmlen;
+	__kernel_size_t kcmlen, tmp;
+
+	kcmlen = 0;
+	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while(ucmsg != NULL) {
+		if(get_user(ucmlen, &ucmsg->cmsg_len))
+			return -EFAULT;
+
+		/* Catch bogons. */
+		if(CMSG32_ALIGN(ucmlen) <
+		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))
+			return -EINVAL;
+		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
+				   + ucmlen) > kmsg->msg_controllen)
+			return -EINVAL;
+
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmlen += tmp;
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+	if (kcmlen == 0)
+		return -EINVAL;
+
+	/* The kcmlen holds the 64-bit version of the control length.
+	 * It may not be modified as we do not stick it into the kmsg
+	 * until we have successfully copied over all of the data
+	 * from the user.
+	 */
+	if (kcmlen > stackbuf_size)
+		kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
+	if (kcmsg == NULL)
+		return -ENOBUFS;
+
+	/* Now copy them over neatly. */
+	memset(kcmsg, 0, kcmlen);
+	ucmsg = CMSG32_FIRSTHDR(kmsg);
+	while (ucmsg != NULL) {
+		__get_user(ucmlen, &ucmsg->cmsg_len);
+		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+		       CMSG_ALIGN(sizeof(struct cmsghdr)));
+		kcmsg->cmsg_len = tmp;
+		__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
+
+		/* Copy over the data. */
+		if(copy_from_user(CMSG_DATA(kcmsg),
+				  CMSG32_DATA(ucmsg),
+				  (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+			goto out_free_efault;
+
+		/* Advance. */
+		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+	}
+
+	/* Ok, looks like we made it.  Hook it up and return success. */
+	kmsg->msg_control = kcmsg_base;
+	kmsg->msg_controllen = kcmlen;
+	return 0;
+
+out_free_efault:
+	if(kcmsg_base != (struct cmsghdr *)stackbuf)
+		kfree(kcmsg_base);
+	return -EFAULT;
+}
+
+asmlinkage long sys32_sendmsg(int fd, struct msghdr32* user_msg, unsigned int user_flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];
+	unsigned char *ctl_buf = ctl;
+	struct msghdr kern_msg;
+	int err, total_len;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sendmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags);
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	if(kern_msg.msg_controllen) {
+		err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
+		if(err)
+			goto out_freeiov;
+		ctl_buf = kern_msg.msg_control;
+	}
+	kern_msg.msg_flags = user_flags;
+
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			kern_msg.msg_flags |= MSG_DONTWAIT;
+		err = sock_sendmsg(sock, &kern_msg, total_len);
+		sockfd_put(sock);
+	}
+
+	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
+	if(ctl_buf != ctl)
+		kfree(ctl_buf);
+out_freeiov:
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sendmsg - exited w/ %lx \n", err);
+	return err;
+}
+
+static void put_cmsg32(struct msghdr *kmsg, int level, int type,
+		       int len, void *data)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	struct cmsghdr32 cmhdr;
+	int cmlen = CMSG32_LEN(len);
+
+	if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+
+	if (kmsg->msg_controllen < cmlen) {
+		kmsg->msg_flags |= MSG_CTRUNC;
+		cmlen = kmsg->msg_controllen;
+	}
+	cmhdr.cmsg_level = level;
+	cmhdr.cmsg_type = type;
+	cmhdr.cmsg_len = cmlen;
+
+	if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
+		return;
+	if (copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))
+		return;
+	cmlen = CMSG32_SPACE(len);
+	kmsg->msg_control += cmlen;
+	kmsg->msg_controllen -= cmlen;
+}
+
+
+static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
+{
+	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);
+	int fdnum = scm->fp->count;
+	struct file **fp = scm->fp->fp;
+	int *cmfptr;
+	int err = 0, i;
+
+	if (fdnum < fdmax)
+		fdmax = fdnum;
+
+	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {
+		int new_fd;
+		err = get_unused_fd();
+		if (err < 0)
+			break;
+		new_fd = err;
+		err = put_user(new_fd, cmfptr);
+		if (err) {
+			put_unused_fd(new_fd);
+			break;
+		}
+		/* Bump the usage count and install the file. */
+		get_file(fp[i]);
+		fd_install(new_fd, fp[i]);
+	}
+
+	if (i > 0) {
+		int cmlen = CMSG32_LEN(i * sizeof(int));
+		if (!err)
+			err = put_user(SOL_SOCKET, &cm->cmsg_level);
+		if (!err)
+			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+		if (!err)
+			err = put_user(cmlen, &cm->cmsg_len);
+		if (!err) {
+			cmlen = CMSG32_SPACE(i * sizeof(int));
+			kmsg->msg_control += cmlen;
+			kmsg->msg_controllen -= cmlen;
+		}
+	}
+	if (i < fdnum)
+		kmsg->msg_flags |= MSG_CTRUNC;
+
+	/*
+	 * All of the files that fit in the message have had their
+	 * usage counts incremented, so we just free the list.
+	 */
+	__scm_destroy(scm);
+}
+
+/* In these cases we (currently) can just copy to data over verbatim
+ * because all CMSGs created by the kernel have well defined types which
+ * have the same layout in both the 32-bit and 64-bit API.  One must add
+ * some special cased conversions here if we start sending control messages
+ * with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work.  The remaining cases are:
+ *
+ * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
+ *		IP_TTL		int			32-bit clean
+ *		IP_TOS		__u8			32-bit clean
+ *		IP_RECVOPTS	variable length		32-bit clean
+ *		IP_RETOPTS	variable length		32-bit clean
+ *		(these last two are clean because the types are defined
+ *		 by the IPv4 protocol)
+ *		IP_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in	32-bit clean
+ * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
+ *				struct sockaddr_in6	32-bit clean
+ *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
+ *		IPV6_HOPLIMIT	int			32-bit clean
+ *		IPV6_FLOWINFO	u32			32-bit clean
+ *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
+ *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
+ *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
+ *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
+ */
+static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+	unsigned char *workbuf, *wp;
+	unsigned long bufsz, space_avail;
+	struct cmsghdr *ucmsg;
+
+	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+	space_avail = kmsg->msg_controllen + bufsz;
+	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+	if(workbuf == NULL)
+		goto fail;
+
+	/* To make this more sane we assume the kernel sends back properly
+	 * formatted control messages.  Because of how the kernel will truncate
+	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+	 */
+	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+	while(((unsigned long)ucmsg) <=
+	      (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
+		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+		int clen64, clen32;
+
+		/* UCMSG is the 64-bit format CMSG entry in user-space.
+		 * KCMSG32 is within the kernel space temporary buffer
+		 * we use to convert into a 32-bit style CMSG.
+		 */
+		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+
+		clen64 = kcmsg32->cmsg_len;
+		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		kcmsg32->cmsg_len = clen32;
+
+		switch (kcmsg32->cmsg_type) {
+			/*
+			 * The timestamp type's data needs to be converted
+			 * from 64-bit time values to 32-bit time values
+			 */
+		case SO_TIMESTAMP: {
+			__kernel_time_t32* ptr_time32 = CMSG32_DATA(kcmsg32);
+			__kernel_time_t*   ptr_time   = CMSG_DATA(ucmsg);
+			*ptr_time32     = *ptr_time;
+			*(ptr_time32+1) = *(ptr_time+1);
+			kcmsg32->cmsg_len -= 2*(sizeof(__kernel_time_t) -
+						sizeof(__kernel_time_t32));
+		}
+		default:;
+		}
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(kcmsg32->cmsg_len));
+	}
+
+	/* Copy back fixed up data, and adjust pointers. */
+	bufsz = (wp - workbuf);
+	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
+
+	kmsg->msg_control = (struct cmsghdr *)
+		(((char *)orig_cmsg_uptr) + bufsz);
+	kmsg->msg_controllen = space_avail - bufsz;
+
+	kfree(workbuf);
+	return;
+
+fail:
+	/* If we leave the 64-bit format CMSG chunks in there,
+	 * the application could get confused and crash.  So to
+	 * ensure greater recovery, we report no CMSGs.
+	 */
+	kmsg->msg_controllen += bufsz;
+	kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
+asmlinkage long sys32_recvmsg(int fd, struct msghdr32* user_msg, unsigned int user_flags)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct msghdr kern_msg;
+	char addr[MAX_SOCK_ADDR];
+	struct socket *sock;
+	struct iovec *iov = iovstack;
+	struct sockaddr *uaddr;
+	int *uaddr_len;
+	unsigned long cmsg_ptr;
+	int err, total_len, len = 0;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags);
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+
+	uaddr = kern_msg.msg_name;
+	uaddr_len = &user_msg->msg_namelen;
+	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	cmsg_ptr = (unsigned long) kern_msg.msg_control;
+	kern_msg.msg_flags = 0;
+
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		struct scm_cookie scm;
+
+		if (sock->file->f_flags & O_NONBLOCK)
+			user_flags |= MSG_DONTWAIT;
+		memset(&scm, 0, sizeof(scm));
+		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
+					 user_flags, &scm);
+		if(err >= 0) {
+			len = err;
+			if(!kern_msg.msg_control) {
+				if(sock->passcred || scm.fp)
+					kern_msg.msg_flags |= MSG_CTRUNC;
+				if(scm.fp)
+					__scm_destroy(&scm);
+			} else {
+				/* If recvmsg processing itself placed some
+				 * control messages into user space, it's is
+				 * using 64-bit CMSG processing, so we need
+				 * to fix it up before we tack on more stuff.
+				 */
+				if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+					cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
+
+				/* Wheee... */
+				if(sock->passcred)
+					put_cmsg32(&kern_msg,
+						   SOL_SOCKET, SCM_CREDENTIALS,
+						   sizeof(scm.creds), &scm.creds);
+				if(scm.fp != NULL)
+					scm_detach_fds32(&kern_msg, &scm);
+			}
+		}
+		sockfd_put(sock);
+	}
+
+  if (uaddr != NULL && err >= 0 && kern_msg.msg_namelen)
+		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+	if(cmsg_ptr != 0 && err >= 0) {
+		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
+		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
+		err |= __put_user(uclen, &user_msg->msg_controllen);
+	}
+	if(err >= 0)
+		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	if(err < 0)
+		return err;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - exited w/ %lx \n", len);
+	return len;
+}
+
+/*
+ * count32() counts the number of arguments/envelopes
+ */
+static int count32(u32 * argv, int max)
+{
+	int i = 0;
+
+	if (argv != NULL) {
+		for (;;) {
+			u32 p; int error;
+
+			error = get_user(p,argv);
+			if (error)
+				return error;
+			if (!p)
+				break;
+			argv++;
+			if (++i > max)
+				return -E2BIG;
+		}
+	}
+	return i;
+}
+
+/*
+ * 'copy_string32()' copies argument/envelope strings from user
+ * memory to free pages in kernel mem. These are in a format ready
+ * to be put directly into the top of new user memory.
+ */
+static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
+{
+	while (argc-- > 0) {
+		u32 str;
+		int len;
+		unsigned long pos;
+
+		if (get_user(str, argv + argc) ||
+		    !str ||
+		    !(len = strnlen_user((char *)A(str), bprm->p)))
+			return -EFAULT;
+
+		if (bprm->p < len)
+			return -E2BIG;
+
+		bprm->p -= len;
+
+		pos = bprm->p;
+		while (len) {
+			char *kaddr;
+			struct page *page;
+			int offset, bytes_to_copy, new, err;
+
+			offset = pos % PAGE_SIZE;
+			page = bprm->page[pos / PAGE_SIZE];
+			new = 0;
+			if (!page) {
+				page = alloc_page(GFP_USER);
+				bprm->page[pos / PAGE_SIZE] = page;
+				if (!page)
+					return -ENOMEM;
+				new = 1;
+			}
+			kaddr = (char *)kmap(page);
+
+			if (new && offset)
+				memset(kaddr, 0, offset);
+			bytes_to_copy = PAGE_SIZE - offset;
+			if (bytes_to_copy > len) {
+				bytes_to_copy = len;
+				if (new)
+					memset(kaddr+offset+len, 0,
+					       PAGE_SIZE-offset-len);
+			}
+
+			err = copy_from_user(kaddr + offset, (char *)A(str),
+					     bytes_to_copy);
+			flush_page_to_ram(page);
+			kunmap((unsigned long)kaddr);
+
+			if (err)
+				return -EFAULT;
+
+			pos += bytes_to_copy;
+			str += bytes_to_copy;
+			len -= bytes_to_copy;
+		}
+	}
+	return 0;
+}
+
+/*
+ * sys32_execve() executes a new program.
+ */
+static int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
+{
+	struct linux_binprm bprm;
+	struct file * file;
+	int retval;
+	int i;
+
+	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
+
+	file = open_exec(filename);
+
+	retval = PTR_ERR(file);
+	if (IS_ERR(file))
+		return retval;
+
+	bprm.file = file;
+	bprm.filename = filename;
+	bprm.sh_bang = 0;
+	bprm.loader = 0;
+	bprm.exec = 0;
+	if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) {
+		allow_write_access(file);
+		fput(file);
+		return bprm.argc;
+	}
+	if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) {
+		allow_write_access(file);
+		fput(file);
+		return bprm.argc;
+	}
+  
+	retval = prepare_binprm(&bprm);
+	if (retval < 0)
+		goto out;
+	
+	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+	if (retval < 0)
+		goto out;
+
+	bprm.exec = bprm.p;
+	retval = copy_strings32(bprm.envc, envp, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = copy_strings32(bprm.argc, argv, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = search_binary_handler(&bprm, regs);
+	if (retval >= 0)
+		/* execve success */
+		return retval;
+
+out:
+	/* Something went wrong, return the inode and free the argument pages*/
+	allow_write_access(bprm.file);
+	if (bprm.file)
+		fput(bprm.file);
+
+	for (i=0 ; i<MAX_ARG_PAGES ; i++)
+		if (bprm.page[i])
+			__free_page(bprm.page[i]);
+
+	return retval;
+}
+
+asmlinkage long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+			                       unsigned long a3, unsigned long a4, unsigned long a5,
+			                       struct pt_regs *regs)
+{
+	int error;
+	char * filename;
+	
+	ifppcdebug(PPCDBG_SYS32) {
+		udbg_printf("sys32_execve - entered - pid=%ld, comm=%s \n", current->pid, current->comm);
+		//PPCDBG(PPCDBG_SYS32NI, "               a0=%lx, a1=%lx, a2=%lx, a3=%lx, a4=%lx, a5=%lx, regs=%p \n", a0, a1, a2, a3, a4, a5, regs);
+	}
+
+	filename = getname((char *) a0);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	error = do_execve32(filename, (u32*) a1, (u32*) a2, regs);
+
+	if (error == 0)
+		current->ptrace &= ~PT_DTRACE;
+	putname(filename);
+
+out:
+	ifppcdebug(PPCDBG_SYS32) {
+		udbg_printf("sys32_execve - exited - returning %x - pid=%ld \n", error, current->pid);
+		//udbg_printf("sys32_execve - at exit - regs->gpr[1]=%lx, gpr[3]=%lx, gpr[4]=%lx, gpr[5]=%lx, gpr[6]=%lx \n", regs->gpr[1], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]);
+	}
+	return error;
+}
+
+/* Set up a thread for executing a new program. */
+void start_thread32(struct pt_regs* regs, unsigned long nip, unsigned long sp)
+{
+	set_fs(USER_DS);
+	memset(regs->gpr, 0, sizeof(regs->gpr));
+	memset(&regs->ctr, 0, 4 * sizeof(regs->ctr));
+	regs->nip = nip;
+	regs->gpr[1] = sp;
+	regs->msr = MSR_USER32;
+	if (last_task_used_math == current)
+		last_task_used_math = 0;
+	current->thread.fpscr = 0;
+}
+
+extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
+				unsigned long arg4, unsigned long arg5);
+
+/* Note: it is necessary to treat option as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+{
+	PPCDBG(PPCDBG_SYS32, "sys32_prctl - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return sys_prctl((int)option,
+			 (unsigned long) arg2,
+			 (unsigned long) arg3,
+			 (unsigned long) arg4,
+			 (unsigned long) arg5);
+}
+
+extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+
+/* Note: it is necessary to treat pid as an unsigned int, 
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_sched_rr_get_interval(u32 pid, struct timespec32 *interval)
+{
+	struct timespec t;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sched_rr_get_interval - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	
+	set_fs (KERNEL_DS);
+	ret = sys_sched_rr_get_interval((int)pid, &t);
+	set_fs (old_fs);
+	if (put_user (t.tv_sec, &interval->tv_sec) ||
+	    __put_user (t.tv_nsec, &interval->tv_nsec))
+		return -EFAULT;
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_sched_rr_get_interval - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return ret;
+}
+
+extern asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off,
+					 unsigned long len, unsigned char *buf);
+
+asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
+{
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_pciconfig_read - running - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
+
+	return sys_pciconfig_read((unsigned long) bus,
+				  (unsigned long) dfn,
+				  (unsigned long) off,
+				  (unsigned long) len,
+				  (unsigned char *)AA(ubuf));
+}
+
+
+
+
+extern asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off,
+					                                unsigned long len, unsigned char *buf);
+
+asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
+{
+	
+	PPCDBG(PPCDBG_SYS32, "sys32_pciconfig_write - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	return sys_pciconfig_write((unsigned long) bus,
+				   (unsigned long) dfn,
+				   (unsigned long) off,
+				   (unsigned long) len,
+				   (unsigned char *)AA(ubuf));
+}
+
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
+asmlinkage int ppc64_newuname(struct new_utsname * name)
+{
+	int errno = sys_newuname(name);
+
+	if (current->personality == PER_LINUX32 && !errno) {
+		if(copy_to_user(name->machine, "ppc\0\0", 8)) {
+			errno = -EFAULT;
+		}
+	}
+	return errno;
+}
+
+extern asmlinkage long sys_personality(unsigned long);
+
+asmlinkage int sys32_personality(unsigned long personality)
+{
+	int ret;
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
+		ret = PER_LINUX;
+	return ret;
+}
+
+
+
+extern asmlinkage long sys_access(const char * filename, int mode);
+
+/* Note: it is necessary to treat mode as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_access(const char * filename, u32 mode)
+{
+	return sys_access(filename, (int)mode);
+}
+
+
+extern asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs);
+
+/* Note: it is necessary to treat p1, p2, p3, p4, p5, p7, and regs as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_clone(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs)
+{
+	return sys_clone((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
+}
+
+
+extern asmlinkage long sys_creat(const char * pathname, int mode);
+
+/* Note: it is necessary to treat mode as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_creat(const char * pathname, u32 mode)
+{
+	return sys_creat(pathname, (int)mode);
+}
+
+
+extern asmlinkage long sys_exit(int error_code);
+
+/* Note: it is necessary to treat error_code as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_exit(u32 error_code)
+{
+	return sys_exit((int)error_code);
+}
+
+
+extern asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, struct rusage * ru);
+
+/* Note: it is necessary to treat pid and options as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_wait4(u32 pid, unsigned int * stat_addr, u32 options, struct rusage * ru)
+{
+        PPCDBG(PPCDBG_SYS32, "sys32_wait4 - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	if (!ru)
+		return sys_wait4((int)pid, stat_addr, options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+		mm_segment_t old_fs = get_fs();
+		
+		set_fs (KERNEL_DS);
+		ret = sys_wait4((int)pid, stat_addr ? &status : NULL, options, &r);
+		set_fs (old_fs);
+		if (put_rusage ((struct rusage32 *)ru, &r)) return -EFAULT;
+		if (stat_addr && put_user (status, stat_addr))
+			return -EFAULT;
+		return ret;
+	}
+	
+}
+
+
+extern asmlinkage long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
+
+/* Note: it is necessary to treat pid and options as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_waitpid(u32 pid, unsigned int * stat_addr, u32 options)
+{
+	return sys_waitpid((int)pid, stat_addr, (int)options);
+}
+
+
+extern asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs);
+
+/* Note: it is necessary to treat p1, p2, p3, p4, p5, and p6 as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_fork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs)
+{
+	return sys_fork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
+}
+
+
+extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
+
+/* Note: it is necessary to treat gidsetsize as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t *grouplist)
+{
+	return sys_getgroups((int)gidsetsize, grouplist);
+}
+
+
+extern asmlinkage long sys_getpgid(pid_t pid);
+
+/* Note: it is necessary to treat pid as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_getpgid(u32 pid)
+{
+	return sys_getpgid((int)pid);
+}
+
+
+extern asmlinkage long sys_getpriority(int which, int who);
+
+/* Note: it is necessary to treat which and who as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_getpriority(u32 which, u32 who)
+{
+	return sys_getpriority((int)which, (int)who);
+}
+
+
+extern asmlinkage long sys_getsid(pid_t pid);
+
+/* Note: it is necessary to treat pid as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_getsid(u32 pid)
+{
+	return sys_getsid((int)pid);
+}
+
+
+extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
+
+/* Note: it is necessary to treat on as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_ioperm(unsigned long from, unsigned long num, u32 on)
+{
+	return sys_ioperm(from, num, (int)on);
+}
+
+
+extern asmlinkage int sys_iopl(int a1, int a2, int a3, int a4);
+
+/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_iopl(u32 a1, u32 a2, u32 a3, u32 a4)
+{
+	return sys_iopl((int)a1, (int)a2, (int)a3, (int)a4);
+}
+
+
+extern asmlinkage long sys_kill(int pid, int sig);
+
+/* Note: it is necessary to treat pid and sig as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_kill(u32 pid, u32 sig)
+{
+	return sys_kill((int)pid, (int)sig);
+}
+
+
+extern asmlinkage long sys_mkdir(const char * pathname, int mode);
+
+/* Note: it is necessary to treat mode as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_mkdir(const char * pathname, u32 mode)
+{
+	return sys_mkdir(pathname, (int)mode);
+}
+
+
+extern asmlinkage long sys_mlockall(int flags);
+
+/* Note: it is necessary to treat flags as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_mlockall(u32 flags)
+{
+	return sys_mlockall((int)flags);
+}
+
+
+extern asmlinkage int sys_modify_ldt(int a1, int a2, int a3, int a4);
+
+/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_modify_ldt(u32 a1, u32 a2, u32 a3, u32 a4)
+{
+	return sys_modify_ldt((int)a1, (int)a2, (int)a3, (int)a4);
+}
+
+
+extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
+
+/* Note: it is necessary to treat flags as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_msync(unsigned long start, size_t len, u32 flags)
+{
+	return sys_msync(start, len, (int)flags);
+}
+
+
+extern asmlinkage long sys_nice(int increment);
+
+/* Note: it is necessary to treat increment as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_nice(u32 increment)
+{
+	return sys_nice((int)increment);
+}
+
+
+extern asmlinkage long sys_open(const char * filename, int flags, int mode);
+
+/* Note: it is necessary to treat flags and mode as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_open(const char * filename, int flags, int mode)
+{
+	return sys_open(filename, (int)flags, (int)mode);
+}
+
+
+extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
+
+/* Note: it is necessary to treat bufsiz as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_readlink(const char * path, char * buf, u32 bufsiz)
+{
+	return sys_readlink(path, buf, (int)bufsiz);
+}
+
+
+extern asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg);
+
+/* Note: it is necessary to treat magic1 and magic2 as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_reboot(u32 magic1, u32 magic2, unsigned int cmd, void * arg)
+{
+	return sys_reboot((int)magic1, (int)magic2, cmd, arg);
+}
+
+
+extern asmlinkage long sys_sched_get_priority_max(int policy);
+
+/* Note: it is necessary to treat option as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sched_get_priority_max(u32 policy)
+{
+	return sys_sched_get_priority_max((int)policy);
+}
+
+
+extern asmlinkage long sys_sched_get_priority_min(int policy);
+
+/* Note: it is necessary to treat policy as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sched_get_priority_min(u32 policy)
+{
+	return sys_sched_get_priority_min((int)policy);
+}
+
+
+extern asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param);
+
+/* Note: it is necessary to treat pid as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param *param)
+{
+	return sys_sched_getparam((int)pid, param);
+}
+
+
+extern asmlinkage long sys_sched_getscheduler(pid_t pid);
+
+/* Note: it is necessary to treat pid as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sched_getscheduler(u32 pid)
+{
+	return sys_sched_getscheduler((int)pid);
+}
+
+
+extern asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param *param);
+
+/* Note: it is necessary to treat pid as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param *param)
+{
+	return sys_sched_setparam((int)pid, param);
+}
+
+
+extern asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param);
+
+/* Note: it is necessary to treat pid and policy as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param *param)
+{
+	return sys_sched_setscheduler((int)pid, (int)policy, param);
+}
+
+
+extern asmlinkage long sys_setdomainname(char *name, int len);
+
+/* Note: it is necessary to treat len as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_setdomainname(char *name, u32 len)
+{
+	return sys_setdomainname(name, (int)len);
+}
+
+
+extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist);
+
+/* Note: it is necessary to treat gidsetsize as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_setgroups(u32 gidsetsize, gid_t *grouplist)
+{
+	return sys_setgroups((int)gidsetsize, grouplist);
+}
+
+
+extern asmlinkage long sys_sethostname(char *name, int len);
+
+/* Note: it is necessary to treat len as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_sethostname(char *name, u32 len)
+{
+	return sys_sethostname(name, (int)len);
+}
+
+
+extern asmlinkage long sys_setpgid(pid_t pid, pid_t pgid);
+
+/* Note: it is necessary to treat pid and pgid as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_setpgid(u32 pid, u32 pgid)
+{
+	return sys_setpgid((int)pid, (int)pgid);
+}
+
+
+extern asmlinkage long sys_setpriority(int which, int who, int niceval);
+
+/* Note: it is necessary to treat which, who, and niceval as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_setpriority(u32 which, u32 who, u32 niceval)
+{
+	return sys_setpriority((int)which, (int)who, (int)niceval);
+}
+
+
+extern asmlinkage long sys_ssetmask(int newmask);
+
+/* Note: it is necessary to treat newmask as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_ssetmask(u32 newmask)
+{
+	return sys_ssetmask((int) newmask);
+}
+
+
+extern asmlinkage long sys_swapon(const char * specialfile, int swap_flags);
+
+/* Note: it is necessary to treat swap_flags as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_swapon(const char * specialfile, u32 swap_flags)
+{
+	return sys_swapon(specialfile, (int)swap_flags);
+}
+
+
+extern asmlinkage long sys_syslog(int type, char * buf, int len);
+
+/* Note: it is necessary to treat type and len as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_syslog(u32 type, char * buf, u32 len)
+{
+	return sys_syslog((int)type, buf, (int)len);
+}
+
+
+extern asmlinkage long sys_umask(int mask);
+
+/* Note: it is necessary to treat mask as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_umask(u32 mask)
+{
+	return sys_umask((int)mask);
+}
+
+
+extern asmlinkage long sys_umount(char * name, int flags);
+
+/* Note: it is necessary to treat flags as an unsigned int,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long sys32_umount(char * name, u32 flags)
+{
+	return sys_umount(name, (int)flags);
+}
+
+
+extern asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs);
+
+/* Note: it is necessary to treat p1, p2, p3, p4, p5, and p6 as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_vfork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs)
+{
+	return sys_vfork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
+}
+
+
+extern asmlinkage int sys_vm86(int a1, int a2, int a3, int a4);
+
+/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
+ * with the corresponding cast to a signed int to insure that the 
+ * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
+ * and the register representation of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage int sys32_vm86(u32 a1, u32 a2, u32 a3, u32 a4)
+{
+	return sys_vm86((int)a1, (int)a2, (int)a3, (int)a4);
+}
+
+
+
+
+
+extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
+				    size_t count, loff_t pos);
+
+extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
+				     size_t count, loff_t pos);
+
+typedef __kernel_ssize_t32 ssize_t32;
+
+asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
+				 __kernel_size_t32 count, u32 reg6, u32 poshi, u32 poslo)
+{
+	return sys_pread(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
+				  __kernel_size_t32 count, u32 reg6 ,u32 poshi, u32 poslo)
+{
+	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+
+extern asmlinkage long sys_truncate(const char * path, unsigned long length);
+extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
+
+asmlinkage int sys32_truncate64(const char * path, u32 reg4, unsigned long high, unsigned long low)
+{
+     	if ((int)high < 0)
+		return -EINVAL;
+	else
+		return sys_truncate(path, (high << 32) | low);
+}
+
+asmlinkage int sys32_ftruncate64(unsigned int fd, u32 reg4, unsigned long high, unsigned long low)
+{
+     	if ((int)high < 0)
+		return -EINVAL;
+	else
+		return sys_ftruncate(fd, (high << 32) | low);
+}
+
+
+
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+     	if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
+		return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg);
+	return sys32_fcntl(fd, cmd, arg);
+}
+
+
+
+
+struct __sysctl_args32 {
+	u32 name;
+	int nlen;
+	u32 oldval;
+	u32 oldlenp;
+	u32 newval;
+	u32 newlen;
+	u32 __unused[4];
+};
+
+extern asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+{
+	struct __sysctl_args32 tmp;
+	int error;
+	size_t oldlen, *oldlenp = NULL;
+	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+
+	if (copy_from_user(&tmp, args, sizeof(tmp)))
+		return -EFAULT;
+
+	if (tmp.oldval && tmp.oldlenp) {
+		/* Duh, this is ugly and might not work if sysctl_args
+		   is in read-only memory, but do_sysctl does indirectly
+		   a lot of uaccess in both directions and we'd have to
+		   basically copy the whole sysctl.c here, and
+		   glibc's __sysctl uses rw memory for the structure
+		   anyway.  */
+		if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
+		    put_user(oldlen, (size_t *)addr))
+			return -EFAULT;
+		oldlenp = (size_t *)addr;
+	}
+
+	lock_kernel();
+	error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
+			  oldlenp, (void *)A(tmp.newval), tmp.newlen);
+	unlock_kernel();
+	if (oldlenp) {
+		if (!error) {
+			if (get_user(oldlen, (size_t *)addr) ||
+			    put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+				error = -EFAULT;
+		}
+		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
+	}
+	return error;
+}
+
+asmlinkage long sys32_time(__kernel_time_t32* tloc)
+{
+	__kernel_time_t32 secs;
+
+	struct timeval tv;
+
+	do_gettimeofday( &tv );
+	secs = tv.tv_sec;
+
+	if (tloc) {
+		if (put_user(secs,tloc))
+			secs = -EFAULT;
+	}
+
+	return secs;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/syscalls.c linux-2.4.19-pre5/arch/ppc64/kernel/syscalls.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/syscalls.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/syscalls.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,316 @@
+/*
+ * linux/arch/ppc/kernel/sys_ppc.c
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
+ * Adapted from the i386 version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au).
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/PPC
+ * platform.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/sys.h>
+#include <linux/ipc.h>
+#include <linux/utsname.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/personality.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+#include <asm/semaphore.h>
+#include <asm/ppcdebug.h>
+
+#include <asm/time.h>
+
+extern unsigned long wall_jiffies;
+#define USEC_PER_SEC (1000000)
+
+void
+check_bugs(void)
+{
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+	printk(KERN_ERR "sys_ioperm()\n");
+	return -EIO;
+}
+
+int sys_iopl(int a1, int a2, int a3, int a4)
+{
+	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+	return (-ENOSYS);
+}
+
+int sys_vm86(int a1, int a2, int a3, int a4)
+{
+	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+	return (-ENOSYS);
+}
+
+int sys_modify_ldt(int a1, int a2, int a3, int a4)
+{
+	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+	return (-ENOSYS);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int 
+sys_ipc (uint call, int first, int second, long third, void *ptr, long fifth)
+{
+	int version, ret;
+
+	PPCDBG(PPCDBG_SYS64X, "sys_ipc - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	ret = -EINVAL;
+	switch (call) {
+	case SEMOP:
+		ret = sys_semop (first, (struct sembuf *)ptr, second);
+		break;
+	case SEMGET:
+		ret = sys_semget (first, second, third);
+		break;
+	case SEMCTL: {
+		union semun fourth;
+
+		if (!ptr)
+			break;
+		if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+		    || (ret = get_user(fourth.__pad, (void **)ptr)))
+			break;
+		ret = sys_semctl (first, second, third, fourth);
+		break;
+	}
+	case MSGSND:
+		ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+		break;
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+
+			if (!ptr)
+				break;
+			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+			    || (ret = copy_from_user(&tmp,
+						(struct ipc_kludge *) ptr,
+						sizeof (tmp))))
+				break;
+			ret = sys_msgrcv (first, (struct msgbuf *)(unsigned long)tmp.msgp,
+						second, tmp.msgtyp, third);
+			break;
+		}
+		default:
+			ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+					  second, fifth, third);
+			break;
+		}
+		break;
+	case MSGGET:
+		ret = sys_msgget ((key_t) first, second);
+		break;
+	case MSGCTL:
+		ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+		break;
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+
+			if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
+					       sizeof(ulong))))
+				break;
+			ret = sys_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				break;
+			ret = put_user (raddr, (ulong *) third);
+			break;
+		}
+		case 1:	/* iBCS2 emulator entry point */
+			if (!segment_eq(get_fs(), get_ds()))
+				break;
+			ret = sys_shmat (first, (char *) ptr, second,
+					 (ulong *) third);
+			break;
+		}
+		break;
+	case SHMDT: 
+		ret = sys_shmdt ((char *)ptr);
+		break;
+	case SHMGET:
+		ret = sys_shmget (first, second, third);
+		break;
+	case SHMCTL:
+		ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+		break;
+	}
+
+	PPCDBG(PPCDBG_SYS64X, "sys_ipc - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return ret;
+}
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(int *fildes)
+{
+	int fd[2];
+	int error;
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_pipe - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	error = do_pipe(fd);
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2*sizeof(int)))
+			error = -EFAULT;
+	}
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_pipe - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return error;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+				  unsigned long prot, unsigned long flags,
+				  unsigned long fd, off_t offset)
+{
+	struct file * file = NULL;
+	unsigned long ret = -EBADF;
+
+	PPCDBG(PPCDBG_SYS64X, "sys_mmap - entered - addr=%lx, len=%lx - pid=%ld, comm=%s \n", addr, len, current->pid, current->comm);
+	
+	if (!(flags & MAP_ANONYMOUS)) {
+		if (!(file = fget(fd)))
+			goto out;
+	}
+	
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	down_write(&current->mm->mmap_sem);
+	ret = do_mmap(file, addr, len, prot, flags, offset);
+	up_write(&current->mm->mmap_sem);
+	if (file)
+		fput(file);
+
+out:
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_mmap - exited - ret=%x \n", ret);
+	
+	return ret;
+}
+
+asmlinkage int sys_pause(void)
+{
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_pause - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_pause - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return -ERESTARTNOHAND;
+}
+
+static int __init set_fakeppc(char *str)
+{
+	if (*str)
+		return 0;
+	init_task.personality = PER_LINUX32;
+	return 1;
+}
+__setup("fakeppc", set_fakeppc);
+
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+	int err = -EFAULT;
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_uname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	down_read(&uts_sem);
+	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+		err = 0;
+	up_read(&uts_sem);
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_uname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return err;
+}
+
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_olduname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+	down_read(&uts_sem);
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error -= __put_user(0,name->release+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error -= __put_user(0,name->version+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error = __put_user(0,name->machine+__OLD_UTS_LEN);
+	up_read(&uts_sem);
+
+	error = error ? -EFAULT : 0;
+	
+	PPCDBG(PPCDBG_SYS64X, "sys_olduname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	return error;
+}
+
+asmlinkage time_t sys64_time(time_t* tloc)
+{
+	time_t secs;
+	time_t usecs;
+
+	long tb_delta = tb_ticks_since(tb_last_stamp);
+	tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
+
+	secs  = xtime.tv_sec;  
+	usecs = xtime.tv_usec + tb_delta / tb_ticks_per_usec;
+	while (usecs >= USEC_PER_SEC) {
+		++secs;
+		usecs -= USEC_PER_SEC;
+	}
+
+	if (tloc) {
+		if (put_user(secs,tloc))
+			secs = -EFAULT;
+	}
+
+	return secs;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/time.c linux-2.4.19-pre5/arch/ppc64/kernel/time.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/time.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,686 @@
+/*
+ * 
+ * Common time routines among all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net).
+ * Converted for 64-bit by Mike Corrigan (mikejc@us.ibm.com)
+ *
+ * First round of bugfixes by Gabriel Paubert (paubert@iram.es)
+ * to make clock more stable (2.4.0-test5). The only thing
+ * that this code assumes is that the timebases have been synchronized
+ * by firmware on SMP and are never stopped (never do sleep
+ * on SMP then, nap and doze are OK).
+ * 
+ * Speeded up do_gettimeofday by getting rid of references to
+ * xtime (which required locks for consistency). (mikejc@us.ibm.com)
+ *
+ * TODO (not necessarily in this file):
+ * - improve precision and reproducibility of timebase frequency
+ * measurement at boot time. (for iSeries, we calibrate the timebase
+ * against the Titan chip's clock.)
+ * - for astronomical applications: add a new function to get
+ * non ambiguous timestamps even around leap seconds. This needs
+ * a new timestamp format and a good name.
+ *
+ * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
+ *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/time.h>
+#include <linux/init.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+#include <asm/cache.h>
+#include <asm/machdep.h>
+#ifdef CONFIG_PPC_ISERIES
+#include <asm/iSeries/HvCallXm.h>
+#endif
+#include <asm/uaccess.h>
+
+#include <asm/time.h>
+#include <asm/ppcdebug.h>
+
+void smp_local_timer_interrupt(struct pt_regs *);
+
+/* keep track of when we need to update the rtc */
+time_t last_rtc_update;
+extern rwlock_t xtime_lock;
+extern int piranha_simulator;
+#ifdef CONFIG_PPC_ISERIES
+unsigned long iSeries_recal_titan = 0;
+unsigned long iSeries_recal_tb = 0; 
+static unsigned long first_settimeofday = 1;
+#endif
+
+#define XSEC_PER_SEC (1024*1024)
+#define USEC_PER_SEC (1000000)
+
+unsigned long tb_ticks_per_jiffy;
+unsigned long tb_ticks_per_usec;
+unsigned long tb_ticks_per_sec;
+unsigned long next_xtime_sync_tb;
+unsigned long xtime_sync_interval;
+unsigned long tb_to_xs;
+unsigned      tb_to_us;
+unsigned long processor_freq;
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+
+struct gettimeofday_struct do_gtod;
+
+extern unsigned long wall_jiffies;
+extern unsigned long lpEvent_count;
+extern int smp_tb_synchronized;
+
+extern unsigned long prof_cpu_mask;
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+extern char _stext;
+
+static inline void ppc_do_profile (unsigned long nip)
+{
+	if (!prof_buffer)
+		return;
+
+	/*
+	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
+	 * (default is all CPUs.)
+	 */
+	if (!((1<<smp_processor_id()) & prof_cpu_mask))
+		return;
+
+	nip -= (unsigned long) &_stext;
+	nip >>= prof_shift;
+	/*
+	 * Don't ignore out-of-bounds EIP values silently,
+	 * put them into the last histogram slot, so if
+	 * present, they will show up as a sharp peak.
+	 */
+	if (nip > prof_len-1)
+		nip = prof_len-1;
+	atomic_inc((atomic_t *)&prof_buffer[nip]);
+}
+
+
+static __inline__ void timer_check_rtc(void)
+{
+        /*
+         * update the rtc when needed, this should be performed on the
+         * right fraction of a second. Half or full second ?
+         * Full second works on mk48t59 clocks, others need testing.
+         * Note that this update is basically only used through 
+         * the adjtimex system calls. Setting the HW clock in
+         * any other way is a /dev/rtc and userland business.
+         * This is still wrong by -0.5/+1.5 jiffies because of the
+         * timer interrupt resolution and possible delay, but here we 
+         * hit a quantization limit which can only be solved by higher
+         * resolution timers and decoupling time management from timer
+         * interrupts. This is also wrong on the clocks
+         * which require being written at the half second boundary.
+         * We should have an rtc call that only sets the minutes and
+         * seconds like on Intel to avoid problems with non UTC clocks.
+         */
+        if ( (time_status & STA_UNSYNC) == 0 &&
+             xtime.tv_sec - last_rtc_update >= 659 &&
+             abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
+             jiffies - wall_jiffies == 1) {
+	    struct rtc_time tm;
+	    to_tm(xtime.tv_sec+1, &tm);
+	    tm.tm_year -= 1900;
+	    tm.tm_mon -= 1;
+            if (ppc_md.set_rtc_time(&tm) == 0)
+                last_rtc_update = xtime.tv_sec+1;
+            else
+                /* Try again one minute later */
+                last_rtc_update += 60;
+        }
+}
+
+/* Synchronize xtime with do_gettimeofday */ 
+
+static __inline__ void timer_sync_xtime( unsigned long cur_tb )
+{
+	struct timeval my_tv;
+
+	if ( cur_tb > next_xtime_sync_tb ) {
+		next_xtime_sync_tb = cur_tb + xtime_sync_interval;
+		do_gettimeofday( &my_tv );
+		if ( xtime.tv_sec <= my_tv.tv_sec ) {
+			xtime.tv_sec = my_tv.tv_sec;
+			xtime.tv_usec = my_tv.tv_usec;
+		}
+	}
+}
+
+#ifdef CONFIG_PPC_ISERIES
+
+/* 
+ * This function recalibrates the timebase based on the 49-bit time-of-day value in the Titan chip.
+ * The Titan is much more accurate than the value returned by the service processor for the
+ * timebase frequency.  
+ */
+
+static void iSeries_tb_recal(void)
+{
+	struct div_result divres;
+	unsigned long titan, tb;
+	tb = get_tb();
+	titan = HvCallXm_loadTod();
+	if ( iSeries_recal_titan ) {
+		unsigned long tb_ticks = tb - iSeries_recal_tb;
+		unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12;
+		unsigned long new_tb_ticks_per_sec   = (tb_ticks * USEC_PER_SEC)/titan_usec;
+		unsigned long new_tb_ticks_per_jiffy = (new_tb_ticks_per_sec+(HZ/2))/HZ;
+		long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy;
+		char sign = '+';		
+		/* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */
+		new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ;
+
+		if ( tick_diff < 0 ) {
+			tick_diff = -tick_diff;
+			sign = '-';
+		}
+		if ( tick_diff ) {
+			if ( tick_diff < tb_ticks_per_jiffy/25 ) {
+				printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n",
+						new_tb_ticks_per_jiffy, sign, tick_diff );
+				tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
+				tb_ticks_per_sec   = new_tb_ticks_per_sec;
+				div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
+				do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
+				tb_to_xs = divres.result_low;
+				do_gtod.varp->tb_to_xs = tb_to_xs;
+			}
+			else {
+				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
+					"                   new tb_ticks_per_jiffy = %lu\n"
+					"                   old tb_ticks_per_jiffy = %lu\n",
+					new_tb_ticks_per_jiffy, tb_ticks_per_jiffy );
+			}
+		}
+	}
+	iSeries_recal_titan = titan;
+	iSeries_recal_tb = tb;
+}
+#endif
+
+/*
+ * For iSeries shared processors, we have to let the hypervisor
+ * set the hardware decrementer.  We set a virtual decrementer
+ * in the ItLpPaca and call the hypervisor if the virtual
+ * decrementer is less than the current value in the hardware
+ * decrementer. (almost always the new decrementer value will
+ * be greater than the current hardware decementer so the hypervisor
+ * call will not be needed)
+ */
+
+unsigned long tb_last_stamp=0;
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ */
+int timer_interrupt(struct pt_regs * regs)
+{
+	int next_dec;
+	unsigned long cur_tb;
+	struct Paca * paca = (struct Paca *)mfspr(SPRG3);
+	unsigned long cpu = paca->xPacaIndex;
+	struct ItLpQueue * lpq;
+
+	irq_enter(cpu);
+
+#ifndef CONFIG_PPC_ISERIES
+	if (!user_mode(regs))
+		ppc_do_profile(instruction_pointer(regs));
+#endif
+
+	paca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
+
+	while (paca->next_jiffy_update_tb <= (cur_tb = get_tb())) {
+
+#ifdef CONFIG_SMP
+		smp_local_timer_interrupt(regs);
+#endif
+		if (cpu == 0) {
+			write_lock(&xtime_lock);
+			tb_last_stamp = paca->next_jiffy_update_tb;
+			do_timer(regs);
+			timer_sync_xtime( cur_tb );
+			timer_check_rtc();
+			write_unlock(&xtime_lock);
+		}
+		paca->next_jiffy_update_tb += tb_ticks_per_jiffy;
+	}
+	
+	next_dec = paca->next_jiffy_update_tb - cur_tb;
+	if (next_dec > paca->default_decr)
+        	next_dec = paca->default_decr;
+	set_dec(next_dec);
+
+	lpq = paca->lpQueuePtr;
+	if (lpq && ItLpQueue_isLpIntPending(lpq))
+		lpEvent_count += ItLpQueue_process(lpq, regs); 
+
+	irq_exit(cpu);
+
+	if (softirq_pending(cpu))
+		do_softirq();
+	
+	return 1;
+}
+
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+        unsigned long sec, usec, tb_ticks;
+	unsigned long xsec, tb_xsec;
+	struct gettimeofday_vars * temp_varp;
+	unsigned long temp_tb_to_xs, temp_stamp_xsec;
+
+	/* These calculations are faster (gets rid of divides)
+	 * if done in units of 1/2^20 rather than microseconds.
+	 * The conversion to microseconds at the end is done
+	 * without a divide (and in fact, without a multiply) */
+	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
+	temp_varp = do_gtod.varp;
+	temp_tb_to_xs = temp_varp->tb_to_xs;
+	temp_stamp_xsec = temp_varp->stamp_xsec;
+	tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs );
+	xsec = temp_stamp_xsec + tb_xsec;
+	sec = xsec / XSEC_PER_SEC;
+	xsec -= sec * XSEC_PER_SEC;
+	usec = (xsec * USEC_PER_SEC)/XSEC_PER_SEC;
+
+        tv->tv_sec = sec;
+        tv->tv_usec = usec;
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long delta_xsec;
+	long int tb_delta, new_usec, new_sec;
+	unsigned long new_xsec;
+
+	write_lock_irqsave(&xtime_lock, flags);
+	/* Updating the RTC is not the job of this code. If the time is
+	 * stepped under NTP, the RTC will be update after STA_UNSYNC
+	 * is cleared. Tool like clock/hwclock either copy the RTC
+	 * to the system time, in which case there is no point in writing
+	 * to the RTC again, or write to the RTC but then they don't call
+	 * settimeofday to perform this operation.
+	 */
+#ifdef CONFIG_PPC_ISERIES
+	if ( first_settimeofday ) {
+		iSeries_tb_recal();
+		first_settimeofday = 0;
+	}
+#endif
+	tb_delta = tb_ticks_since(tb_last_stamp);
+	tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
+
+	new_sec = tv->tv_sec;
+	new_usec = tv->tv_usec - tb_delta / tb_ticks_per_usec;
+	while (new_usec <0) {
+		new_sec--; 
+		new_usec += USEC_PER_SEC;
+	}
+	xtime.tv_usec = new_usec;
+	xtime.tv_sec = new_sec;
+
+	/* In case of a large backwards jump in time with NTP, we want the 
+	 * clock to be updated as soon as the PLL is again in lock.
+	 */
+	last_rtc_update = new_sec - 658;
+
+	time_adjust = 0;                /* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+
+	delta_xsec = mulhdu( (tb_last_stamp-do_gtod.tb_orig_stamp), do_gtod.varp->tb_to_xs );
+	new_xsec = (new_usec * XSEC_PER_SEC) / USEC_PER_SEC;
+	new_xsec += new_sec * XSEC_PER_SEC;
+	if ( new_xsec > delta_xsec ) {
+		do_gtod.varp->stamp_xsec = new_xsec - delta_xsec;
+	}
+	else {
+		/* This is only for the case where the user is setting the time
+		 * way back to a time such that the boot time would have been
+		 * before 1970 ... eg. we booted ten days ago, and we are setting
+		 * the time to Jan 5, 1970 */
+		do_gtod.varp->stamp_xsec = new_xsec;
+		do_gtod.tb_orig_stamp = tb_last_stamp;
+	}
+
+	write_unlock_irqrestore(&xtime_lock, flags);
+}
+
+/*
+ * This function is a copy of the architecture independent function
+ * but which calls do_settimeofday rather than setting the xtime
+ * fields itself.  This way, the fields which are used for 
+ * do_settimeofday get updated too.
+ */
+long ppc64_sys32_stime(int* tptr)
+{
+	int value;
+	struct timeval myTimeval;
+
+	if (!capable(CAP_SYS_TIME))
+		return -EPERM;
+
+	if (get_user(value, tptr))
+		return -EFAULT;
+
+	myTimeval.tv_sec = value;
+	myTimeval.tv_usec = 0;
+
+	do_settimeofday(&myTimeval);
+
+	return 0;
+}
+
+/*
+ * This function is a copy of the architecture independent function
+ * but which calls do_settimeofday rather than setting the xtime
+ * fields itself.  This way, the fields which are used for 
+ * do_settimeofday get updated too.
+ */
+long ppc64_sys_stime(long* tptr)
+{
+	long value;
+	struct timeval myTimeval;
+
+	if (!capable(CAP_SYS_TIME))
+		return -EPERM;
+
+	if (get_user(value, tptr))
+		return -EFAULT;
+
+	myTimeval.tv_sec = value;
+	myTimeval.tv_usec = 0;
+
+	do_settimeofday(&myTimeval);
+
+	return 0;
+}
+
+void __init time_init(void)
+{
+	/* This function is only called on the boot processor */
+	unsigned long flags;
+	struct rtc_time tm;
+
+	ppc_md.calibrate_decr();
+
+	if ( ! piranha_simulator ) {
+		ppc_md.get_boot_time(&tm);
+	}
+	write_lock_irqsave(&xtime_lock, flags);
+	xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+			      tm.tm_hour, tm.tm_min, tm.tm_sec);
+	tb_last_stamp = get_tb();
+	do_gtod.tb_orig_stamp = tb_last_stamp;
+	do_gtod.varp = &do_gtod.vars[0];
+	do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
+	do_gtod.varp->tb_to_xs = tb_to_xs;
+	do_gtod.tb_to_us = tb_to_us;
+
+	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
+	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
+
+	xtime.tv_usec = 0;
+	last_rtc_update = xtime.tv_sec;
+	write_unlock_irqrestore(&xtime_lock, flags);
+
+#ifdef CONFIG_PPC_ISERIES
+	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
+	prof_shift = 0;
+#endif
+
+	/* Not exact, but the timer interrupt takes care of this */
+	set_dec(tb_ticks_per_jiffy);
+}
+
+/* 
+ * After adjtimex is called, adjust the conversion of tb ticks
+ * to microseconds to keep do_gettimeofday synchronized 
+ * with ntpd.
+
+ * Use the time_freq and time_offset computed by adjtimex to 
+ * adjust the frequency.
+*/
+
+void ppc_adjtimex(void)
+{
+	unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, new_tb_to_xs, new_xsec, new_stamp_xsec;
+	unsigned long tb_ticks_per_sec_delta;
+	long delta_freq, ltemp;
+	struct div_result divres; 
+	unsigned long flags;
+	struct gettimeofday_vars * temp_varp;
+
+	if ( time_offset < 0 ) {
+		ltemp = -time_offset;
+		ltemp <<= SHIFT_USEC - SHIFT_UPDATE;
+		ltemp >>= SHIFT_KG + time_constant;
+		ltemp = -ltemp;
+	}
+	else {
+		ltemp = time_offset;
+		ltemp <<= SHIFT_USEC - SHIFT_UPDATE;
+		ltemp >>= SHIFT_KG + time_constant;
+	}
+	delta_freq = time_freq + ltemp;
+
+	den = 1000000 * (1 << (SHIFT_USEC - 8));
+	if ( delta_freq < 0 ) {
+		tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( (-delta_freq) >> (SHIFT_USEC - 8))) / den;
+		new_tb_ticks_per_sec = tb_ticks_per_sec + tb_ticks_per_sec_delta;
+	}
+	else {
+		tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( delta_freq >> (SHIFT_USEC - 8))) / den;
+		new_tb_ticks_per_sec = tb_ticks_per_sec - tb_ticks_per_sec_delta;
+	}
+	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
+	div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
+	new_tb_to_xs = divres.result_low;
+	new_xsec = mulhdu( tb_ticks, new_tb_to_xs );
+
+	write_lock_irqsave( &xtime_lock, flags );
+	old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs );
+	new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec;
+
+	if (do_gtod.varp == &do_gtod.vars[0])
+		temp_varp = &do_gtod.vars[1];
+	else
+		temp_varp = &do_gtod.vars[0];
+	temp_varp->tb_to_xs = new_tb_to_xs;
+	temp_varp->stamp_xsec = new_stamp_xsec;
+	mb();
+	do_gtod.varp = temp_varp;
+
+	write_unlock_irqrestore( &xtime_lock, flags );
+
+}
+
+
+#define TICK_SIZE tick
+#define FEBRUARY	2
+#define	STARTOFTIME	1970
+#define SECDAY		86400L
+#define SECYR		(SECDAY * 365)
+#define	leapyear(year)		((year) % 4 == 0)
+#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
+#define	days_in_month(a) 	(month_days[(a) - 1])
+
+static int month_days[12] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
+ */
+void GregorianDay(struct rtc_time * tm)
+{
+	int leapsToDate;
+	int lastYear;
+	int day;
+	int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+	lastYear=tm->tm_year-1;
+
+	/*
+	 * Number of leap corrections to apply up to end of last year
+	 */
+	leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
+
+	/*
+	 * This year is a leap year if it is divisible by 4 except when it is
+	 * divisible by 100 unless it is divisible by 400
+	 *
+	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
+	 */
+	if((tm->tm_year%4==0) &&
+	   ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
+	   (tm->tm_mon>2))
+	{
+		/*
+		 * We are past Feb. 29 in a leap year
+		 */
+		day=1;
+	}
+	else
+	{
+		day=0;
+	}
+
+	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
+		   tm->tm_mday;
+
+	tm->tm_wday=day%7;
+}
+
+void to_tm(int tim, struct rtc_time * tm)
+{
+	register int    i;
+	register long   hms, day;
+
+	day = tim / SECDAY;
+	hms = tim % SECDAY;
+
+	/* Hours, minutes, seconds are easy */
+	tm->tm_hour = hms / 3600;
+	tm->tm_min = (hms % 3600) / 60;
+	tm->tm_sec = (hms % 3600) % 60;
+
+	/* Number of years in days */
+	for (i = STARTOFTIME; day >= days_in_year(i); i++)
+		day -= days_in_year(i);
+	tm->tm_year = i;
+
+	/* Number of months in days left */
+	if (leapyear(tm->tm_year))
+		days_in_month(FEBRUARY) = 29;
+	for (i = 1; day >= days_in_month(i); i++)
+		day -= days_in_month(i);
+	days_in_month(FEBRUARY) = 28;
+	tm->tm_mon = i;
+
+	/* Days are what is left over (+1) from all that. */
+	tm->tm_mday = day + 1;
+
+	/*
+	 * Determine the day of week
+	 */
+	GregorianDay(tm);
+}
+
+/* Auxiliary function to compute scaling factors */
+/* Actually the choice of a timebase running at 1/4 the of the bus
+ * frequency giving resolution of a few tens of nanoseconds is quite nice.
+ * It makes this computation very precise (27-28 bits typically) which
+ * is optimistic considering the stability of most processor clock
+ * oscillators and the precision with which the timebase frequency
+ * is measured but does not harm.
+ */
+unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) {
+        unsigned mlt=0, tmp, err;
+        /* No concern for performance, it's done once: use a stupid
+         * but safe and compact method to find the multiplier.
+         */
+  
+        for (tmp = 1U<<31; tmp != 0; tmp >>= 1) {
+                if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp;
+        }
+  
+        /* We might still be off by 1 for the best approximation.
+         * A side effect of this is that if outscale is too large
+         * the returned value will be zero.
+         * Many corner cases have been checked and seem to work,
+         * some might have been forgotten in the test however.
+         */
+  
+        err = inscale*(mlt+1);
+        if (err <= inscale/2) mlt++;
+        return mlt;
+  }
+
+/*
+ * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit
+ * result.
+ */
+
+void div128_by_32( unsigned long dividend_high, unsigned long dividend_low,
+		   unsigned divisor, struct div_result *dr )
+{
+	unsigned long a,b,c,d, w,x,y,z, ra,rb,rc;
+
+	a = dividend_high >> 32;
+	b = dividend_high & 0xffffffff;
+	c = dividend_low >> 32;
+	d = dividend_low & 0xffffffff;
+
+	w = a/divisor;
+	ra = (a - (w * divisor)) << 32;
+
+	x = (ra + b)/divisor;
+	rb = ((ra + b) - (x * divisor)) << 32;
+
+	y = (rb + c)/divisor;
+	rc = ((rb + b) - (y * divisor)) << 32;
+
+	z = (rc + d)/divisor;
+
+	dr->result_high = (w << 32) + x;
+	dr->result_low  = (y << 32) + z;
+
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/traps.c linux-2.4.19-pre5/arch/ppc64/kernel/traps.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/traps.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/traps.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,257 @@
+/*
+ *  linux/arch/ppc/kernel/traps.c
+ *
+ *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  and Paul Mackerras (paulus@cs.anu.edu.au)
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/ppcdebug.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *regs);
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern int xmon_dabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
+
+#ifdef CONFIG_XMON
+void (*debugger)(struct pt_regs *regs) = xmon;
+int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
+int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
+int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
+int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#ifdef CONFIG_KGDB
+void (*debugger)(struct pt_regs *regs);
+int (*debugger_bpt)(struct pt_regs *regs);
+int (*debugger_sstep)(struct pt_regs *regs);
+int (*debugger_iabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs);
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif
+#endif
+/*
+ * Trap & Exception support
+ */
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	if (!user_mode(regs))
+	{
+		show_regs(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		debugger(regs);
+#endif
+#if defined(CONFIG_KDB)
+		kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs);
+#endif
+		print_backtrace((unsigned long *)regs->gpr[1]);
+		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+#if defined(CONFIG_PPCDBG) && (defined(CONFIG_XMON) || defined(CONFIG_KGDB))
+	/* Allow us to catch SIGILLs for 64-bit app/glibc debugging. -Peter */
+	} else if (signr == SIGILL) {
+		ifppcdebug(PPCDBG_SIGNALXMON)
+			debugger(regs);
+#endif
+	}
+	force_sig(signr, current);
+}
+
+void
+SystemResetException(struct pt_regs *regs)
+{
+	udbg_printf("System Reset in kernel mode.\n");
+	printk("System Reset in kernel mode.\n");
+#if defined(CONFIG_XMON)
+	xmon(regs);
+#endif
+	for(;;);
+}
+
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	if ( !user_mode(regs) )
+	{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		if (debugger_fault_handler) {
+			debugger_fault_handler(regs);
+			return;
+		}
+#endif
+#ifdef CONFIG_KDB
+		if (kdb(KDB_REASON_FAULT, 0, regs))
+			return;
+#endif
+		printk("Machine check in kernel mode.\n");
+		printk("Caused by (from SRR1=%lx): ", regs->msr);
+		show_regs(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		debugger(regs);
+#endif
+#ifdef CONFIG_KDB
+		if (kdb(KDB_REASON_FAULT, 0, regs))
+			return ;
+#endif
+		print_backtrace((unsigned long *)regs->gpr[1]);
+		panic("machine check");
+	}
+	_exception(SIGSEGV, regs);	
+}
+
+void
+SMIException(struct pt_regs *regs)
+{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	{
+		debugger(regs);
+		return;
+	}
+#endif
+#ifdef CONFIG_KDB
+	{
+		kdb(KDB_REASON_OOPS, 0, regs);
+		return;
+	}
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("System Management Interrupt");
+}
+
+void
+UnknownException(struct pt_regs *regs)
+{
+	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(SIGTRAP, regs);	
+}
+
+void
+InstructionBreakpointException(struct pt_regs *regs)
+{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	if (debugger_iabr_match(regs))
+		return;
+#endif
+#ifdef CONFIG_KDB
+	if (kdb(KDB_REASON_BREAK, 0, regs))
+		return ;
+#endif
+	_exception(SIGTRAP, regs);
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	if (regs->msr & 0x100000) {
+		/* IEEE FP exception */
+		_exception(SIGFPE, regs);
+	} else if (regs->msr & 0x20000) {
+		/* trap exception */
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		if (debugger_bpt(regs))
+			return;
+#endif
+#ifdef CONFIG_KDB
+		if (kdb(KDB_REASON_BREAK, 0, regs))
+			return;
+#endif
+		_exception(SIGTRAP, regs);
+	} else {
+		_exception(SIGILL, regs);
+	}
+}
+
+void
+SingleStepException(struct pt_regs *regs)
+{
+	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	if (debugger_sstep(regs))
+		return;
+#endif
+#ifdef CONFIG_KDB
+	if (kdb(KDB_REASON_DEBUG, 0, regs))
+		return;
+#endif
+	_exception(SIGTRAP, regs);	
+}
+
+/* Dummy handler for Performance Monitor */
+
+void
+PerformanceMonitorException(struct pt_regs *regs)
+{
+	_exception(SIGTRAP, regs);
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+	int fixed;
+
+	fixed = fix_alignment(regs);
+	if (fixed == 1) {
+		ifppcdebug(PPCDBG_ALIGNFIXUP)
+			if (!user_mode(regs))
+				PPCDBG(PPCDBG_ALIGNFIXUP, "fix alignment at %lx\n", regs->nip);
+		regs->nip += 4;	/* skip over emulated instruction */
+		return;
+	}
+	if (fixed == -EFAULT) {
+		/* fixed == -EFAULT means the operand address was bad */
+		if (user_mode(regs))
+			force_sig(SIGSEGV, current);
+		else
+			bad_page_fault(regs, regs->dar);
+		return;
+	}
+	_exception(SIGBUS, regs);	
+}
+
+void __init trap_init(void)
+{
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/udbg.c linux-2.4.19-pre5/arch/ppc64/kernel/udbg.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/udbg.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/udbg.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,253 @@
+/*
+ * NS16550 Serial Port (uart) debugging stuff.
+ *
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * NOTE: I am trying to make this code avoid any static data references to
+ *  simplify debugging early boot.  We'll see how that goes...
+ *
+ * To use this call udbg_init() first.  It will init the uart to 9600 8N1.
+ * You may need to update the COM1 define if your uart is at a different addr.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <stdarg.h>
+#define WANT_PPCDBG_TAB /* Only defined here */
+#include <asm/ppcdebug.h>
+#include <asm/processor.h>
+#include <asm/Naca.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+extern struct Naca *naca;
+extern int _machine;
+
+struct NS16550 {
+	/* this struct must be packed */
+	unsigned char rbr;  /* 0 */
+	unsigned char ier;  /* 1 */
+	unsigned char fcr;  /* 2 */
+	unsigned char lcr;  /* 3 */
+	unsigned char mcr;  /* 4 */
+	unsigned char lsr;  /* 5 */
+	unsigned char msr;  /* 6 */
+	unsigned char scr;  /* 7 */
+};
+
+#define thr rbr
+#define iir fcr
+#define dll rbr
+#define dlm ier
+#define dlab lcr
+
+#define LSR_DR   0x01  /* Data ready */
+#define LSR_OE   0x02  /* Overrun */
+#define LSR_PE   0x04  /* Parity error */
+#define LSR_FE   0x08  /* Framing error */
+#define LSR_BI   0x10  /* Break */
+#define LSR_THRE 0x20  /* Xmit holding register empty */
+#define LSR_TEMT 0x40  /* Xmitter empty */
+#define LSR_ERR  0x80  /* Error */
+
+volatile struct NS16550 *udbg_comport;
+
+spinlock_t udbg_lock = SPIN_LOCK_UNLOCKED;
+
+void
+udbg_init_uart(void *comport)
+{
+	if (comport) {
+		udbg_comport = (struct NS16550 *)comport;
+		udbg_comport->lcr = 0x00; eieio();
+		udbg_comport->ier = 0xFF; eieio();
+		udbg_comport->ier = 0x00; eieio();
+		udbg_comport->lcr = 0x80; eieio();	/* Access baud rate */
+		udbg_comport->dll = 12;   eieio();	/* 1 = 115200,  2 = 57600, 3 = 38400, 12 = 9600 baud */
+		udbg_comport->dlm = 0;    eieio();	/* dll >> 8 which should be zero for fast rates; */
+		udbg_comport->lcr = 0x03; eieio();	/* 8 data, 1 stop, no parity */
+		udbg_comport->mcr = 0x03; eieio();	/* RTS/DTR */
+		udbg_comport->fcr = 0x07; eieio();	/* Clear & enable FIFOs */
+	}
+}
+
+void
+udbg_putc(unsigned char c)
+{
+	if ( udbg_comport ) {
+		while ((udbg_comport->lsr & LSR_THRE) == 0)
+			/* wait for idle */;
+		udbg_comport->thr = c; eieio();
+		if (c == '\n') {
+			/* Also put a CR.  This is for convenience. */
+			while ((udbg_comport->lsr & LSR_THRE) == 0)
+				/* wait for idle */;
+			udbg_comport->thr = '\r'; eieio();
+		}
+	} else if ( _machine == _MACH_iSeries ) {
+		/* ToDo: switch this via ppc_md */
+		printk("%c", c);
+	}
+}
+
+int udbg_getc_poll(void)
+{
+	if (udbg_comport) {
+		if ((udbg_comport->lsr & LSR_DR) != 0)
+			return udbg_comport->rbr;
+		else
+			return -1;
+	}
+	return -1;
+}
+
+unsigned char
+udbg_getc(void)
+{
+	if ( udbg_comport ) {
+		while ((udbg_comport->lsr & LSR_DR) == 0)
+			/* wait for char */;
+		return udbg_comport->rbr;
+	}
+	return 0;
+}
+
+void
+udbg_puts(const char *s)
+{
+	if (ppc_md.udbg_putc) {
+		char c;
+
+		if (s && *s != '\0') {
+			while ((c = *s++) != '\0')
+				ppc_md.udbg_putc(c);
+		} else {
+			udbg_puts("NULL");
+		}
+	} else {
+		printk("%s", s);
+	}
+}
+
+int
+udbg_write(const char *s, int n)
+{
+	int remain = n;
+	char c;
+	if (!ppc_md.udbg_putc)
+		for (;;);	/* stop here for cpuctl */
+	if ( s && *s != '\0' ) {
+		while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
+			ppc_md.udbg_putc(c);
+		}
+	} else
+		udbg_puts("NULL");
+	return n - remain;
+}
+
+int
+udbg_read(char *buf, int buflen) {
+	char c, *p = buf;
+	int i;
+	if (!ppc_md.udbg_putc)
+		for (;;);	/* stop here for cpuctl */
+	for (i = 0; i < buflen; ++i) {
+		do {
+			c = ppc_md.udbg_getc();
+		} while (c == 0x11 || c == 0x13);
+		*p++ = c;
+	}
+	return i;
+}
+
+void
+udbg_puthex(unsigned long val)
+{
+	int i, nibbles = sizeof(val)*2;
+	unsigned char buf[sizeof(val)*2+1];
+	for (i = nibbles-1;  i >= 0;  i--) {
+		buf[i] = (val & 0xf) + '0';
+		if (buf[i] > '9')
+		    buf[i] += ('a'-'0'-10);
+		val >>= 4;
+	}
+	buf[nibbles] = '\0';
+	udbg_puts(buf);
+}
+
+void
+udbg_printSP(const char *s)
+{
+	if (_machine == _MACH_pSeries) {
+		unsigned long sp;
+		asm("mr %0,1" : "=r" (sp) :);
+		if (s)
+			udbg_puts(s);
+		udbg_puthex(sp);
+	}
+}
+
+void
+udbg_printf(const char *fmt, ...)
+{
+	unsigned long flags;
+	unsigned char buf[256];
+
+	va_list args;
+	va_start(args, fmt);
+
+	spin_lock_irqsave(&udbg_lock, flags);
+	vsprintf(buf, fmt, args);
+	udbg_puts(buf);
+	spin_unlock_irqrestore(&udbg_lock, flags);
+
+	va_end(args);
+}
+
+/* Special print used by PPCDBG() macro */
+void
+udbg_ppcdbg(unsigned long flags, const char *fmt, ...)
+{
+	unsigned long flags;
+	unsigned long active_debugs = flags & naca->debug_switch;
+
+	if ( active_debugs ) {
+		va_list ap;
+		unsigned char buf[256];
+		unsigned long i, len = 0;
+
+		spin_lock_irqsave(&udbg_lock, flags);
+		for(i=0; i < PPCDBG_NUM_FLAGS ;i++) {
+			if (((1U << i) & active_debugs) && 
+			    trace_names[i]) {
+				len += strlen(trace_names[i]); 
+				udbg_puts(trace_names[i]);
+				break;
+			}
+		}
+		sprintf(buf, " [%s]: ", current->comm);
+		len += strlen(buf); 
+		udbg_puts(buf);
+
+		while(len < 18) {
+			udbg_puts(" ");
+			len++;
+		}
+
+		va_start(ap, fmt);
+		vsprintf(buf, fmt, ap);
+		udbg_puts(buf);
+		spin_unlock_irqrestore(&udbg_lock, flags);
+		
+		va_end(ap);
+	}
+}
+
+unsigned long
+udbg_ifdebug(unsigned long flags)
+{
+	return (flags & naca->debug_switch);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/xics.c linux-2.4.19-pre5/arch/ppc64/kernel/xics.c
--- linux-2.4.19-pre4/arch/ppc64/kernel/xics.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/xics.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,467 @@
+/* 
+ * arch/ppc/kernel/xics.c
+ *
+ * Copyright 2000 IBM Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/threads.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/smp.h>
+#include <asm/Naca.h>
+#include <asm/rtas.h>
+#include "i8259.h"
+#include "xics.h"
+#include <asm/ppcdebug.h>
+
+extern struct Naca *naca;
+
+void xics_enable_irq(u_int irq);
+void xics_disable_irq(u_int irq);
+void xics_mask_and_ack_irq(u_int irq);
+void xics_end_irq(u_int irq);
+void xics_set_affinity(unsigned int irq_nr, unsigned long cpumask);
+
+struct hw_interrupt_type xics_pic = {
+	" XICS     ",
+	NULL,
+	NULL,
+	xics_enable_irq,
+	xics_disable_irq,
+	xics_mask_and_ack_irq,
+	xics_end_irq,
+	xics_set_affinity
+};
+
+struct hw_interrupt_type xics_8259_pic = {
+	" XICS/8259",
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	xics_mask_and_ack_irq,
+	NULL
+};
+
+#define XICS_IPI		2
+#define XICS_IRQ_OFFSET		0x10
+#define XICS_IRQ_SPURIOUS	0
+
+/* Want a priority other than 0.  Various HW issues require this. */
+#define	DEFAULT_PRIORITY	5
+
+struct xics_ipl {
+	union {
+		u32	word;
+		u8	bytes[4];
+	} xirr_poll;
+	union {
+		u32 word;
+		u8	bytes[4];
+	} xirr;
+	u32	dummy;
+	union {
+		u32	word;
+		u8	bytes[4];
+	} qirr;
+};
+
+struct xics_info {
+	volatile struct xics_ipl *	per_cpu[NR_CPUS];
+};
+
+struct xics_info	xics_info;
+
+unsigned long long intr_base = 0;
+int xics_irq_8259_cascade = 0;
+int xics_irq_8259_cascade_real = 0;
+unsigned int default_server = 0xFF;
+unsigned int default_distrib_server = 0;
+
+/* RTAS service tokens */
+int ibm_get_xive;
+int ibm_set_xive;
+int ibm_int_off;
+
+struct xics_interrupt_node {
+	unsigned long long addr;
+	unsigned long long size;
+} inodes[NR_CPUS*2];	 
+
+typedef struct {
+	int (*xirr_info_get)(int cpu);
+	void (*xirr_info_set)(int cpu, int val);
+	void (*cppr_info)(int cpu, u8 val);
+	void (*qirr_info)(int cpu, u8 val);
+} xics_ops;
+
+
+static int pSeries_xirr_info_get(int n_cpu)
+{
+	return (xics_info.per_cpu[n_cpu]->xirr.word);
+}
+
+static void pSeries_xirr_info_set(int n_cpu, int value)
+{
+	xics_info.per_cpu[n_cpu]->xirr.word = value;
+}
+
+static void pSeries_cppr_info(int n_cpu, u8 value)
+{
+	xics_info.per_cpu[n_cpu]->xirr.bytes[0] = value;
+}
+
+static void pSeries_qirr_info(int n_cpu , u8 value)
+{
+	xics_info.per_cpu[n_cpu]->qirr.bytes[0] = value;
+}
+
+static xics_ops pSeries_ops = {
+	pSeries_xirr_info_get,
+	pSeries_xirr_info_set,
+	pSeries_cppr_info,
+	pSeries_qirr_info
+};
+
+static xics_ops *ops = &pSeries_ops;
+extern xics_ops pSeriesLP_ops;
+
+
+void
+xics_enable_irq(
+	u_int	virq
+	)
+{
+	u_int		irq;
+	unsigned long	status;
+	long	        call_status;
+
+	virq -= XICS_IRQ_OFFSET;
+	irq = virt_irq_to_real(virq);
+	if (irq == XICS_IPI)
+		return;
+#ifdef CONFIG_IRQ_ALL_CPUS
+	call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status,
+				irq, smp_threads_ready ? default_distrib_server : default_server, DEFAULT_PRIORITY);
+#else
+	call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status,
+				irq, default_server, DEFAULT_PRIORITY);
+#endif
+	if( call_status != 0 ) {
+		printk("xics_enable_irq: irq=%x: rtas_call failed; retn=%lx, status=%lx\n",
+		       irq, call_status, status);
+		return;
+	}
+}
+
+void
+xics_disable_irq(
+	u_int	virq
+	)
+{
+	u_int		irq;
+	unsigned long 	status;
+	long 	        call_status;
+
+	virq -= XICS_IRQ_OFFSET;
+	irq = virt_irq_to_real(virq);
+	call_status = rtas_call(ibm_int_off, 1, 1, (unsigned long*)&status, 
+				irq);
+	if( call_status != 0 ) {
+		printk("xics_disable_irq: irq=%x: rtas_call failed, retn=%lx\n",
+		       irq, call_status);
+		return;
+	}
+}
+
+void
+xics_end_irq(
+	u_int	irq
+	)
+{
+	int cpu = smp_processor_id();
+
+	ops->cppr_info(cpu, 0); /* actually the value overwritten by ack */
+	iosync();
+	ops->xirr_info_set(cpu, ((0xff<<24) | (virt_irq_to_real(irq-XICS_IRQ_OFFSET))));
+	iosync();
+}
+
+void
+xics_mask_and_ack_irq(u_int	irq)
+{
+	int cpu = smp_processor_id();
+
+	if( irq < XICS_IRQ_OFFSET ) {
+		i8259_pic.ack(irq);
+		iosync();
+		ops->xirr_info_set(cpu, ((0xff<<24) | xics_irq_8259_cascade_real));
+		iosync();
+	}
+	else {
+		ops->cppr_info(cpu, 0xff);
+		iosync();
+	}
+}
+
+int
+xics_get_irq(struct pt_regs *regs)
+{
+	u_int	cpu = smp_processor_id();
+	u_int	vec;
+	int irq;
+
+	vec = ops->xirr_info_get(cpu);
+	/*  (vec >> 24) == old priority */
+	vec &= 0x00ffffff;
+	/* for sanity, this had better be < NR_IRQS - 16 */
+	if( vec == xics_irq_8259_cascade_real ) {
+		irq = i8259_irq(cpu);
+		if(irq == -1) {
+			/* Spurious cascaded interrupt.  Still must ack xics */
+                        xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade);
+			irq = -1;
+		}
+	} else if( vec == XICS_IRQ_SPURIOUS ) {
+		irq = -1;
+		printk("spurious PPC interrupt!\n");
+	} else
+		irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;
+	return irq;
+}
+
+
+#ifdef CONFIG_SMP
+void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+	extern volatile unsigned long xics_ipi_message[];
+	int cpu = smp_processor_id();
+
+	ops->qirr_info(cpu, 0xff);
+	while (xics_ipi_message[cpu]) {
+		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu])) {
+			mb();
+			smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);
+		}
+		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu])) {
+			mb();
+			smp_message_recv(PPC_MSG_RESCHEDULE, regs);
+		}
+	}
+}
+
+void xics_cause_IPI(int cpu)
+{
+	ops->qirr_info(cpu,0) ;
+}
+
+void xics_setup_cpu(void)
+{
+	int cpu = smp_processor_id();
+
+	ops->cppr_info(cpu, 0xff);
+	iosync();
+}
+#endif /* CONFIG_SMP */
+
+void
+xics_init_IRQ( void )
+{
+	int i;
+	unsigned long intr_size = 0;
+	struct device_node *np;
+	uint *ireg, ilen, indx=0;
+
+	ibm_get_xive = rtas_token("ibm,get-xive");
+	ibm_set_xive = rtas_token("ibm,set-xive");
+	ibm_int_off = rtas_token("ibm,int-off");
+
+	np = find_type_devices("PowerPC-External-Interrupt-Presentation");
+	if (!np) {
+		printk(KERN_WARNING "Can't find Interrupt Presentation\n");
+		udbg_printf("Can't find Interrupt Presentation\n");
+		while (1);
+	}
+nextnode:
+	ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", 0);
+	if (ireg) {
+		/*
+		 * set node starting index for this node
+		 */
+		indx = *ireg;
+	}
+
+	ireg = (uint *)get_property(np, "reg", &ilen);
+	if (!ireg) {
+		printk(KERN_WARNING "Can't find Interrupt Reg Property\n");
+		udbg_printf("Can't find Interrupt Reg Property\n");
+		while (1);
+	}
+	
+	while (ilen) {
+		inodes[indx].addr = (unsigned long long)*ireg++ << 32;
+		ilen -= sizeof(uint);
+		inodes[indx].addr |= *ireg++;
+		ilen -= sizeof(uint);
+		inodes[indx].size = (unsigned long long)*ireg++ << 32;
+		ilen -= sizeof(uint);
+		inodes[indx].size |= *ireg++;
+		ilen -= sizeof(uint);
+		indx++;
+		if (indx >= NR_CPUS) break;
+	}
+
+	np = np->next;
+	if ((indx < NR_CPUS) && np) goto nextnode;
+
+	/* Find the server numbers for the boot cpu. */
+	for (np = find_type_devices("cpu"); np; np = np->next) {
+		ireg = (uint *)get_property(np, "reg", &ilen);
+		if (ireg && ireg[0] == hard_smp_processor_id()) {
+			ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+			i = ilen / sizeof(int);
+			if (ireg && i > 0) {
+				default_server = ireg[0];
+				default_distrib_server = ireg[i-1]; /* take last element */
+			}
+			break;
+		}
+	}
+
+	intr_base = inodes[0].addr;
+	intr_size = (ulong)inodes[0].size;
+
+	np = find_type_devices("interrupt-controller");
+	if (!np) {
+		printk(KERN_WARNING "xics:  no ISA Interrupt Controller\n");
+		xics_irq_8259_cascade = -1;
+	} else {
+		ireg = (uint *) get_property(np, "interrupts", 0);
+		if (!ireg) {
+			printk(KERN_WARNING "Can't find ISA Interrupts Property\n");
+			udbg_printf("Can't find ISA Interrupts Property\n");
+			while (1);
+		}
+		xics_irq_8259_cascade_real = *ireg;
+		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
+	}
+
+	if (_machine == _MACH_pSeries) {
+#ifdef CONFIG_SMP
+		for (i = 0; i < naca->processorCount; ++i) {
+			xics_info.per_cpu[i] =
+			  __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, 
+				  (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE);
+		}
+#else
+		xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE);
+#endif /* CONFIG_SMP */
+#ifdef CONFIG_PPC_PSERIES
+	/* actually iSeries does not use any of xics...but it has link dependencies
+	 * for now, except this new one...
+	 */
+	} else if (_machine == _MACH_pSeriesLP) {
+		ops = &pSeriesLP_ops;
+#endif
+	}
+
+	xics_8259_pic.enable = i8259_pic.enable;
+	xics_8259_pic.disable = i8259_pic.disable;
+	for (i = 0; i < 16; ++i)
+		irq_desc[i].handler = &xics_8259_pic;
+	for (; i < NR_IRQS; ++i)
+		irq_desc[i].handler = &xics_pic;
+
+	ops->cppr_info(0, 0xff);
+	iosync();
+	if (xics_irq_8259_cascade != -1) {
+		if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,
+				0, "8259 cascade", 0))
+			printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
+		i8259_init();
+	}
+
+#ifdef CONFIG_SMP
+	real_irq_to_virt_map[XICS_IPI] = virt_irq_to_real_map[XICS_IPI] = XICS_IPI;
+	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
+	irq_desc[XICS_IPI+XICS_IRQ_OFFSET].status |= IRQ_PER_CPU;
+#endif
+}
+
+void xics_isa_init(void)
+{
+	return;
+	if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,
+			0, "8259 cascade", 0))
+		printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
+	i8259_init();
+}
+
+/*
+ * Find first logical cpu and return its physical cpu number
+ */
+static inline u32 physmask(u32 cpumask)
+{
+	int i;
+
+	for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1) {
+		if (cpumask & 1)
+			return get_hard_smp_processor_id(i);
+	}
+
+	printk(KERN_ERR "xics_set_affinity: invalid irq mask\n");
+
+	return default_distrib_server;
+}
+
+void xics_set_affinity(unsigned int virq, unsigned long cpumask)
+{
+        irq_desc_t *desc = irq_desc + virq;
+	unsigned int irq;
+	unsigned long flags;
+	long status;
+	unsigned long xics_status[2];
+	u32 newmask;
+
+	virq -= XICS_IRQ_OFFSET;
+	irq = virt_irq_to_real(virq);
+	if (irq == XICS_IPI)
+		return;
+
+        spin_lock_irqsave(&desc->lock, flags);
+
+	status = rtas_call(ibm_get_xive, 1, 3, (void *)&xics_status, irq);
+
+	if (status) {
+		printk("xics_set_affinity: irq=%d ibm,get-xive returns %ld\n",
+			irq, status);
+		goto out;
+	}
+
+	/* For the moment only implement delivery to all cpus or one cpu */
+	if (cpumask == 0xffffffff)
+		newmask = default_distrib_server;
+	else
+		newmask = physmask(cpumask);
+
+	status = rtas_call(ibm_set_xive, 3, 1, NULL,
+				irq, newmask, xics_status[1]);
+
+	if (status) {
+		printk("xics_set_affinity irq=%d ibm,set-xive returns %ld\n",
+			irq, status);
+		goto out;
+	}
+
+out:
+        spin_unlock_irqrestore(&desc->lock, flags);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/kernel/xics.h linux-2.4.19-pre5/arch/ppc64/kernel/xics.h
--- linux-2.4.19-pre4/arch/ppc64/kernel/xics.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/kernel/xics.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,24 @@
+/* 
+ * arch/ppc/kernel/xics.h
+ *
+ * Copyright 2000 IBM Corporation.
+ *
+ *  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.
+ */
+
+#ifndef _PPC_KERNEL_XICS_H
+#define _PPC_KERNEL_XICS_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type xics_pic;
+extern struct hw_interrupt_type xics_8259_pic;
+
+void xics_init_IRQ(void);
+int xics_get_irq(struct pt_regs *);
+void xics_isa_init(void);
+
+#endif /* _PPC_KERNEL_XICS_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/lib/Makefile linux-2.4.19-pre5/arch/ppc64/lib/Makefile
--- linux-2.4.19-pre4/arch/ppc64/lib/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/lib/Makefile	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,11 @@
+#
+# Makefile for ppc64-specific library files..
+#
+
+USE_STANDARD_AS_RULE    := true
+
+O_TARGET = lib.o
+
+obj-y           := checksum.o dec_and_lock.o string.o strcase.o
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/arch/ppc64/lib/checksum.S linux-2.4.19-pre5/arch/ppc64/lib/checksum.S
--- linux-2.4.19-pre4/arch/ppc64/lib/checksum.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/lib/checksum.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,231 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *	
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+	.text
+
+/*
+ * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ *
+ * In practice len == 5, but this is not guaranteed.  So this code does not
+ * attempt to use doubleword instructions.
+ */
+_GLOBAL(ip_fast_csum)
+	lwz	r0,0(r3)
+	lwzu	r5,4(r3)
+	addic.	r4,r4,-2
+	addc	r0,r0,r5
+	mtctr	r4
+	blelr-
+1:	lwzu	r4,4(r3)
+	adde	r0,r0,r4
+	bdnz	1b
+	addze	r0,r0		/* add in final carry */
+        rldicl  r4,r0,32,0      /* fold two 32-bit halves together */
+        add     r0,r0,r4
+        srdi    r0,r0,32
+	rlwinm	r3,r0,16,0,31	/* fold two halves together */
+	add	r3,r0,r3
+	not	r3,r3
+	srwi	r3,r3,16
+	blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ *   csum_tcpudp_magic(r3=saddr, r4=daddr, r5=len, r6=proto, r7=sum)
+ * No real gain trying to do this specially for 64 bit, but
+ * the 32 bit addition may spill into the upper bits of
+ * the doubleword so we still must fold it down from 64.
+ */	
+_GLOBAL(csum_tcpudp_magic)
+	rlwimi	r5,r6,16,0,15	/* put proto in upper half of len */
+	addc	r0,r3,r4	/* add 4 32-bit words together */
+	adde	r0,r0,r5
+	adde	r0,r0,r7
+        rldicl  r4,r0,32,0      /* fold 64 bit value */
+        add     r0,r4,r0
+        srdi    r0,r0,32
+	rlwinm	r3,r0,16,0,31	/* fold two halves together */
+	add	r3,r0,r3
+	not	r3,r3
+	srwi	r3,r3,16
+	blr
+
+/*
+ * Computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit).
+ *
+ * This code assumes at least halfword alignment, though the length
+ * can be any number of bytes.  The sum is accumulated in r5.
+ *
+ * csum_partial(r3=buff, r4=len, r5=sum)
+ */
+_GLOBAL(csum_partial)
+        subi	r3,r3,8		/* we'll offset by 8 for the loads */
+        srdi.	r6,r4,3         /* divide by 8 for doubleword count */
+        addic   r5,r5,0         /* clear carry */
+        beq	3f              /* if we're doing < 8 bytes */
+        andi.	r0,r3,2         /* aligned on a word boundary already? */
+        beq+	1f
+        lhz     r6,8(r3)        /* do 2 bytes to get aligned */
+        addi    r3,r3,2
+        subi    r4,r4,2
+        addc    r5,r5,r6
+        srdi.   r6,r4,3         /* recompute number of doublewords */
+        beq     3f              /* any left? */
+1:      mtctr   r6
+2:      ldu     r6,8(r3)        /* main sum loop */
+        adde    r5,r5,r6
+        bdnz    2b
+        andi.	r4,r4,7         /* compute bytes left to sum after doublewords */
+3:	cmpi	0,r4,4		/* is at least a full word left? */
+	blt	4f
+	lwz	r6,8(r3)	/* sum this word */
+	addi	r3,r3,4
+	subi	r4,r4,4
+	adde	r5,r5,r6
+4:      cmpi    0,r4,2		/* is at least a halfword left? */
+        blt+	5f
+        lhz     r6,8(r3)        /* sum this halfword */
+        addi    r3,r3,2
+        subi    r4,r4,2
+        adde    r5,r5,r6
+5:      cmpi    0,r4,1		/* is at least a byte left? */
+        bne+    6f
+        lbz     r6,8(r3)        /* sum this byte */
+        slwi    r6,r6,8         /* this byte is assumed to be the upper byte of a halfword */
+        adde    r5,r5,r6
+6:      addze	r5,r5		/* add in final carry */
+	rldicl  r4,r5,32,0      /* fold two 32-bit halves together */
+        add     r3,r4,r5
+        srdi    r3,r3,32
+        blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * This code needs to be reworked to take advantage of 64 bit sum+copy.
+ * However, due to tokenring halfword alignment problems this will be very
+ * tricky.  For now we'll leave it until we instrument it somehow.
+ *
+ * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+	addic	r0,r6,0
+	subi	r3,r3,4
+	subi	r4,r4,4
+	srwi.	r6,r5,2
+	beq	3f		/* if we're doing < 4 bytes */
+	andi.	r9,r4,2		/* Align dst to longword boundary */
+	beq+	1f
+81:	lhz	r6,4(r3)	/* do 2 bytes to get aligned */
+	addi	r3,r3,2
+	subi	r5,r5,2
+91:	sth	r6,4(r4)
+	addi	r4,r4,2
+	addc	r0,r0,r6
+	srwi.	r6,r5,2		/* # words to do */
+	beq	3f
+1:	mtctr	r6
+82:	lwzu	r6,4(r3)	/* the bdnz has zero overhead, so it should */
+92:	stwu	r6,4(r4)	/* be unnecessary to unroll this loop */
+	adde	r0,r0,r6
+	bdnz	82b
+	andi.	r5,r5,3
+3:	cmpi	0,r5,2
+	blt+	4f
+83:	lhz	r6,4(r3)
+	addi	r3,r3,2
+	subi	r5,r5,2
+93:	sth	r6,4(r4)
+	addi	r4,r4,2
+	adde	r0,r0,r6
+4:	cmpi	0,r5,1
+	bne+	5f
+84:	lbz	r6,4(r3)
+94:	stb	r6,4(r4)
+	slwi	r6,r6,8		/* Upper byte of word */
+	adde	r0,r0,r6
+5:	addze	r3,r0		/* add in final carry (unlikely with 64-bit regs) */
+        rldicl  r4,r3,32,0      /* fold 64 bit value */
+        add     r3,r4,r3
+        srdi    r3,r3,32
+	blr
+
+/* These shouldn't go in the fixup section, since that would
+   cause the ex_table addresses to get out of order. */
+
+	.globl src_error_1
+src_error_1:
+	li	r6,0
+	subi	r5,r5,2
+95:	sth	r6,4(r4)
+	addi	r4,r4,2
+	srwi.	r6,r5,2
+	beq	3f
+	mtctr	r6
+	.globl src_error_2
+src_error_2:
+	li	r6,0
+96:	stwu	r6,4(r4)
+	bdnz	96b
+3:	andi.	r5,r5,3
+	beq	src_error
+	.globl src_error_3
+src_error_3:
+	li	r6,0
+	mtctr	r5
+	addi	r4,r4,3
+97:	stbu	r6,1(r4)
+	bdnz	97b
+	.globl src_error
+src_error:
+	cmpi	0,r7,0
+	beq	1f
+	li	r6,-EFAULT
+	stw	r6,0(r7)
+1:	addze	r3,r0
+	blr
+
+	.globl dst_error
+dst_error:
+	cmpi	0,r8,0
+	beq	1f
+	li	r6,-EFAULT
+	stw	r6,0(r8)
+1:	addze	r3,r0
+	blr
+
+.section __ex_table,"a"
+	.align  3
+	.llong	81b,src_error_1
+	.llong	91b,dst_error
+	.llong	82b,src_error_2
+	.llong	92b,dst_error
+	.llong	83b,src_error_3
+	.llong	93b,dst_error
+	.llong	84b,src_error_3
+	.llong	94b,dst_error
+	.llong	95b,dst_error
+	.llong	96b,dst_error
+	.llong	97b,dst_error
diff -urN linux-2.4.19-pre4/arch/ppc64/lib/dec_and_lock.c linux-2.4.19-pre5/arch/ppc64/lib/dec_and_lock.c
--- linux-2.4.19-pre4/arch/ppc64/lib/dec_and_lock.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/lib/dec_and_lock.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,38 @@
+/*
+ * ppc64 version of atomic_dec_and_lock() using cmpxchg
+ *
+ * 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/spinlock.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	int counter;
+	int newcount;
+
+repeat:
+	counter = atomic_read(atomic);
+	newcount = counter-1;
+
+	if (!newcount)
+		goto slow_path;
+
+	newcount = cmpxchg(&atomic->counter, counter, newcount);
+
+	if (newcount != counter)
+		goto repeat;
+	return 0;
+
+slow_path:
+	spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	spin_unlock(lock);
+	return 0;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/lib/strcase.c linux-2.4.19-pre5/arch/ppc64/lib/strcase.c
--- linux-2.4.19-pre4/arch/ppc64/lib/strcase.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/lib/strcase.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,31 @@
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while (c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
+
+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 -urN linux-2.4.19-pre4/arch/ppc64/lib/string.S linux-2.4.19-pre5/arch/ppc64/lib/string.S
--- linux-2.4.19-pre4/arch/ppc64/lib/string.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/lib/string.S	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,660 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
+#include <asm/errno.h>
+
+#define CACHE_LINE_SIZE		128
+#define LG_CACHE_LINE_SIZE	7
+#define MAX_COPY_PREFETCH	1
+
+#define COPY_16_BYTES		\
+	lwz	r7,4(r4);	\
+	lwz	r8,8(r4);	\
+	lwz	r9,12(r4);	\
+	lwzu	r10,16(r4);	\
+	stw	r7,4(r6);	\
+	stw	r8,8(r6);	\
+	stw	r9,12(r6);	\
+	stwu	r10,16(r6)
+
+#define COPY_16_BYTES_WITHEX(n)	\
+8 ## n ## 0:			\
+	lwz	r7,4(r4);	\
+8 ## n ## 1:			\
+	lwz	r8,8(r4);	\
+8 ## n ## 2:			\
+	lwz	r9,12(r4);	\
+8 ## n ## 3:			\
+	lwzu	r10,16(r4);	\
+8 ## n ## 4:			\
+	stw	r7,4(r6);	\
+8 ## n ## 5:			\
+	stw	r8,8(r6);	\
+8 ## n ## 6:			\
+	stw	r9,12(r6);	\
+8 ## n ## 7:			\
+	stwu	r10,16(r6)
+
+#define COPY_16_BYTES_EXCODE(n)			\
+9 ## n ## 0:					\
+	addi	r5,r5,-(16 * n);		\
+	b	104f;				\
+9 ## n ## 1:					\
+	addi	r5,r5,-(16 * n);		\
+	b	105f;				\
+.section __ex_table,"a";			\
+	.align	3;				\
+	.llong	8 ## n ## 0b,9 ## n ## 0b;	\
+	.llong	8 ## n ## 1b,9 ## n ## 0b;	\
+	.llong	8 ## n ## 2b,9 ## n ## 0b;	\
+	.llong	8 ## n ## 3b,9 ## n ## 0b;	\
+	.llong	8 ## n ## 4b,9 ## n ## 1b;	\
+	.llong	8 ## n ## 5b,9 ## n ## 1b;	\
+	.llong	8 ## n ## 6b,9 ## n ## 1b;	\
+	.llong	8 ## n ## 7b,9 ## n ## 1b;	\
+.text
+
+CACHELINE_BYTES = CACHE_LINE_SIZE
+LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE
+CACHELINE_MASK = (CACHE_LINE_SIZE-1)
+
+_GLOBAL(strcpy)
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+_GLOBAL(strncpy)
+	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	blr
+
+_GLOBAL(strcat)
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r5)
+	cmpwi	0,r0,0
+	bne	1b
+	addi	r5,r5,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+_GLOBAL(strcmp)
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r5)
+	cmpwi	1,r3,0
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	beqlr	1
+	beq	1b
+	blr
+
+_GLOBAL(strlen)
+	addi	r4,r3,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	bne	1b
+	subf	r3,r3,r4
+	blr
+
+/*
+ * Use dcbz on the complete cache lines in the destination
+ * to set them to zero.  This requires that the destination
+ * area is cacheable.  -- paulus
+ */
+_GLOBAL(cacheable_memzero)
+	mr	r5,r4
+	li	r4,0
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
+	add	r8,r7,r5
+	srwi	r9,r8,LG_CACHELINE_BYTES
+	addic.	r9,r9,-1	/* total number of complete cachelines */
+	ble	2f
+	xori	r0,r7,CACHELINE_MASK & ~3
+	srwi.	r0,r0,2
+	beq	3f
+	mtctr	r0
+4:	stwu	r4,4(r6)
+	bdnz	4b
+3:	mtctr	r9
+	li	r7,4
+10:	dcbz	r7,r6
+	addi	r6,r6,CACHELINE_BYTES
+	bdnz	10b
+	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
+	addi	r5,r5,4
+2:	srwi	r0,r5,2
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+
+_GLOBAL(memset)
+	rlwimi	r4,r4,8,16,23
+	rlwimi	r4,r4,16,0,15
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	srwi	r0,r5,2
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+
+_GLOBAL(bcopy)
+	mr	r6,r3
+	mr	r3,r4
+	mr	r4,r6
+	b	.memcpy
+
+/*
+ * This version uses dcbz on the complete cache lines in the
+ * destination area to reduce memory traffic.  This requires that
+ * the destination area is cacheable.
+ * We only use this version if the source and dest don't overlap.
+ * -- paulus.
+ */
+_GLOBAL(cacheable_memcpy)
+	add	r7,r3,r5		/* test if the src & dst overlap */
+	add	r8,r4,r5
+	cmplw	0,r4,r7
+	cmplw	1,r3,r8
+	crand	0,0,4			/* cr0.lt &= cr1.lt */
+	blt	.memcpy			/* if regions overlap */
+
+	addi	r4,r4,-4
+	addi	r6,r3,-4
+	neg	r0,r3
+	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
+	beq	58f
+
+	cmplw	0,r5,r0			/* is this more than total to do? */
+	blt	63f			/* if not much to do */
+	andi.	r8,r0,3			/* get it word-aligned first */
+	subf	r5,r0,r5
+	mtctr	r8
+	beq+	61f
+70:	lbz	r9,4(r4)		/* do some bytes */
+	stb	r9,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	70b
+61:	srwi.	r0,r0,2
+	mtctr	r0
+	beq	58f
+72:	lwzu	r9,4(r4)		/* do some words */
+	stwu	r9,4(r6)
+	bdnz	72b
+
+58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
+	li	r11,4
+	mtctr	r0
+	beq	63f
+53:
+	dcbz	r11,r6
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 32
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 64
+	COPY_16_BYTES
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 128
+	COPY_16_BYTES
+	COPY_16_BYTES
+	COPY_16_BYTES
+	COPY_16_BYTES
+#endif
+#endif
+#endif
+	bdnz	53b
+
+63:	srwi.	r0,r5,2
+	mtctr	r0
+	beq	64f
+30:	lwzu	r0,4(r4)
+	stwu	r0,4(r6)
+	bdnz	30b
+
+64:	andi.	r0,r5,3
+	mtctr	r0
+	beq+	65f
+40:	lbz	r0,4(r4)
+	stb	r0,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	40b
+65:	blr
+
+_GLOBAL(memmove)
+	cmplw	0,r3,r4
+	bgt	.backwards_memcpy
+	/* fall through */
+
+_GLOBAL(memcpy)
+	srwi.	r7,r5,3
+	addi	r6,r3,-4
+	addi	r4,r4,-4
+	beq	2f			/* if less than 8 bytes to do */
+	andi.	r0,r6,3			/* get dest word aligned */
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,4(r4)
+	lwzu	r8,8(r4)
+	stw	r7,4(r6)
+	stwu	r8,8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,4(r4)
+	addi	r5,r5,-4
+	stwu	r0,4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r4,r4,3
+	addi	r6,r6,3
+4:	lbzu	r0,1(r4)
+	stbu	r0,1(r6)
+	bdnz	4b
+	blr
+5:	subfic	r0,r0,4
+	mtctr	r0
+6:	lbz	r7,4(r4)
+	addi	r4,r4,1
+	stb	r7,4(r6)
+	addi	r6,r6,1
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+_GLOBAL(backwards_memcpy)
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	add	r6,r3,r5
+	add	r4,r4,r5
+	beq	2f
+	andi.	r0,r6,3
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,-4(r4)
+	lwzu	r8,-8(r4)
+	stw	r7,-4(r6)
+	stwu	r8,-8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,-4(r4)
+	subi	r5,r5,4
+	stwu	r0,-4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+4:	lbzu	r0,-1(r4)
+	stbu	r0,-1(r6)
+	bdnz	4b
+	blr
+5:	mtctr	r0
+6:	lbzu	r7,-1(r4)
+	stbu	r7,-1(r6)
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+	
+_GLOBAL(memcmp)
+	cmpwi	0,r5,0
+	ble-	2f
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r6)
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	bdnzt	2,1b
+	blr
+2:	li	r3,0
+	blr
+
+_GLOBAL(memchr)
+	cmpwi	0,r5,0
+	ble-	2f
+	mtctr	r5
+	addi	r3,r3,-1
+1:	lbzu	r0,1(r3)
+	cmpw	0,r0,r4
+	bdnzf	2,1b
+	beqlr
+2:	li	r3,0
+	blr
+
+_GLOBAL(__copy_tofrom_user)
+	addi	r4,r4,-4
+	addi	r6,r3,-4
+	neg	r0,r3
+	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
+	beq	58f
+
+	cmplw	0,r5,r0			/* is this more than total to do? */
+	blt	63f			/* if not much to do */
+	andi.	r8,r0,3			/* get it word-aligned first */
+	mtctr	r8
+	beq+	61f
+70:	lbz	r9,4(r4)		/* do some bytes */
+71:	stb	r9,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	70b
+61:	subf	r5,r0,r5
+	srwi.	r0,r0,2
+	mtctr	r0
+	beq	58f
+72:	lwzu	r9,4(r4)		/* do some words */
+73:	stwu	r9,4(r6)
+	bdnz	72b
+
+58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
+	li	r11,4
+	beq	63f
+
+	/* Here we decide how far ahead to prefetch the source */
+#if MAX_COPY_PREFETCH > 1
+	/* Heuristically, for large transfers we prefetch
+	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
+	   we prefetch 1 cacheline ahead. */
+	cmpwi	r0,MAX_COPY_PREFETCH
+	li	r7,1
+	li	r3,4
+	ble	111f
+	li	r7,MAX_COPY_PREFETCH
+111:	mtctr	r7
+112:	dcbt	r3,r4
+	addi	r3,r3,CACHELINE_BYTES
+	bdnz	112b
+#else /* MAX_COPY_PREFETCH == 1 */
+	li	r3,CACHELINE_BYTES + 4
+	dcbt	r11,r4
+#endif /* MAX_COPY_PREFETCH */
+
+	mtctr	r0
+53:
+	dcbt	r3,r4
+	dcbz	r11,r6
+/* had to move these to keep extable in order */
+	.section __ex_table,"a"
+	.align	3
+	.llong	70b,100f
+	.llong	71b,101f
+	.llong	72b,102f
+	.llong	73b,103f
+	.llong	53b,105f
+	.text
+/* the main body of the cacheline loop */
+	COPY_16_BYTES_WITHEX(0)
+#if CACHE_LINE_SIZE >= 32
+	COPY_16_BYTES_WITHEX(1)
+#if CACHE_LINE_SIZE >= 64
+	COPY_16_BYTES_WITHEX(2)
+	COPY_16_BYTES_WITHEX(3)
+#if CACHE_LINE_SIZE >= 128
+	COPY_16_BYTES_WITHEX(4)
+	COPY_16_BYTES_WITHEX(5)
+	COPY_16_BYTES_WITHEX(6)
+	COPY_16_BYTES_WITHEX(7)
+#endif
+#endif
+#endif
+	bdnz	53b
+
+63:	srwi.	r0,r5,2
+	mtctr	r0
+	beq	64f
+30:	lwzu	r0,4(r4)
+31:	stwu	r0,4(r6)
+	bdnz	30b
+
+64:	andi.	r0,r5,3
+	mtctr	r0
+	beq+	65f
+40:	lbz	r0,4(r4)
+41:	stb	r0,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	40b
+65:	li	r3,0
+	blr
+
+/* read fault, initial single-byte copy */
+100:	li	r4,0
+	b	90f
+/* write fault, initial single-byte copy */
+101:	li	r4,1
+90:	subf	r5,r8,r5
+	li	r3,0
+	b	99f
+/* read fault, initial word copy */
+102:	li	r4,0
+	b	91f
+/* write fault, initial word copy */
+103:	li	r4,1
+91:	li	r3,2
+	b	99f
+
+/*
+ * this stuff handles faults in the cacheline loop and branches to either
+ * 104f (if in read part) or 105f (if in write part), after updating r5
+ */
+	COPY_16_BYTES_EXCODE(0)
+#if CACHE_LINE_SIZE >= 32
+	COPY_16_BYTES_EXCODE(1)
+#if CACHE_LINE_SIZE >= 64
+	COPY_16_BYTES_EXCODE(2)
+	COPY_16_BYTES_EXCODE(3)
+#if CACHE_LINE_SIZE >= 128
+	COPY_16_BYTES_EXCODE(4)
+	COPY_16_BYTES_EXCODE(5)
+	COPY_16_BYTES_EXCODE(6)
+	COPY_16_BYTES_EXCODE(7)
+#endif
+#endif
+#endif
+
+/* read fault in cacheline loop */
+104:	li	r4,0
+	b	92f
+/* fault on dcbz (effectively a write fault) */
+/* or write fault in cacheline loop */
+105:	li	r4,1
+92:	li	r3,LG_CACHELINE_BYTES
+	b	99f
+/* read fault in final word loop */
+108:	li	r4,0
+	b	93f
+/* write fault in final word loop */
+109:	li	r4,1
+93:	andi.	r5,r5,3
+	li	r3,2
+	b	99f
+/* read fault in final byte loop */
+110:	li	r4,0
+	b	94f
+/* write fault in final byte loop */
+111:	li	r4,1
+94:	li	r5,0
+	li	r3,0
+/*
+ * At this stage the number of bytes not copied is
+ * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ */
+99:	mfctr	r0
+	slw	r3,r0,r3
+	add	r3,r3,r5
+	cmpwi	0,r4,0
+	bne	120f
+/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+	srwi.	r0,r3,2
+	li	r9,0
+	mtctr	r0
+	beq	113f
+112:	stwu	r9,4(r6)
+	bdnz	112b
+113:	andi.	r0,r3,3
+	mtctr	r0
+	beq	120f
+114:	stb	r9,4(r6)
+	addi	r6,r6,1
+	bdnz	114b
+120:	blr
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	30b,108b
+	.llong	31b,109b
+	.llong	40b,110b
+	.llong	41b,111b
+	.llong	112b,120b
+	.llong	114b,120b
+	.text
+
+_GLOBAL(__clear_user)
+	addi	r6,r3,-4
+	li	r3,0
+	li	r5,0
+	cmplwi	0,r4,4
+	blt	7f
+	/* clear a single word */
+11:	stwu	r5,4(r6)
+	beqlr
+	/* clear word sized chunks */
+	andi.	r0,r6,3
+	add	r4,r0,r4
+	subf	r6,r0,r6
+	srwi	r0,r4,2
+	mtctr	r0
+	bdz	6f
+1:	stwu	r5,4(r6)
+	bdnz	1b
+6:	andi.	r4,r4,3
+	/* clear byte sized chunks */
+7:	cmpwi	0,r4,0
+	beqlr
+	mtctr	r4
+	addi	r6,r6,3
+8:	stbu	r5,1(r6)
+	bdnz	8b
+	blr
+99:	li	r3,-EFAULT
+	blr
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	11b,99b
+	.llong	1b,99b
+	.llong	8b,99b
+	.text
+
+_GLOBAL(__strncpy_from_user)
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+	cmpwi	0,r5,0
+	beq	2f
+	mtctr	r5
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	beq	3f
+2:	addi	r6,r6,1
+3:	subf	r3,r3,r6
+	blr
+99:	li	r3,-EFAULT
+	blr
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	1b,99b
+	.text
+
+/* r3 = str, r4 = len (> 0), r5 = top (highest addr) */
+_GLOBAL(__strnlen_user)
+	addi	r7,r3,-1
+	subf	r6,r7,r5	/* top+1 - str */
+	cmplw	0,r4,r6
+	bge	0f
+	mr	r6,r4
+0:	mtctr	r6		/* ctr = min(len, top - str) */
+1:	lbzu	r0,1(r7)	/* get next byte */
+	cmpwi	0,r0,0
+	bdnzf	2,1b		/* loop if --ctr != 0 && byte != 0 */
+	addi	r7,r7,1
+	subf	r3,r3,r7	/* number of bytes we have looked at */
+	beqlr			/* return if we found a 0 byte */
+	cmpw	0,r3,r4		/* did we look at all len bytes? */
+	blt	99f		/* if not, must have hit top */
+	addi	r3,r4,1		/* return len + 1 to indicate no null found */
+	blr
+99:	li	r3,0		/* bad address, return 0 */
+	blr
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	1b,99b
diff -urN linux-2.4.19-pre4/arch/ppc64/mm/Makefile linux-2.4.19-pre5/arch/ppc64/mm/Makefile
--- linux-2.4.19-pre4/arch/ppc64/mm/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/mm/Makefile	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,16 @@
+#
+# Makefile for the linux ppc-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+EXTRA_CFLAGS = -mno-minimal-toc
+
+O_TARGET := mm.o
+
+obj-y           := fault.o init.o extable.o imalloc.o
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/arch/ppc64/mm/extable.c linux-2.4.19-pre5/arch/ppc64/mm/extable.c
--- linux-2.4.19-pre4/arch/ppc64/mm/extable.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/mm/extable.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/ppc/mm/extable.c
+ *
+ * from linux/arch/i386/mm/extable.c
+ *
+ *      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/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+		 const struct exception_table_entry *last,
+		 unsigned long value)
+{
+        while (first <= last) {
+		const struct exception_table_entry *mid;
+		long diff;
+
+		mid = (last - first) / 2 + first;
+		diff = mid->insn - value;
+                if (diff == 0)
+                        return mid->fixup;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+	unsigned long ret;
+
+	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+	if (ret) return ret;
+
+	return 0;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/mm/fault.c linux-2.4.19-pre5/arch/ppc64/mm/fault.c
--- linux-2.4.19-pre4/arch/ppc64/mm/fault.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/mm/fault.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,231 @@
+/*
+ *  arch/ppc/mm/fault.c
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/mm/fault.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Modified by Cort Dougan and Paul Mackerras.
+ *
+ *  Modified for PPC64 by Dave Engebretsen (engebret@ibm.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <asm/ppcdebug.h>
+
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+extern void (*debugger)(struct pt_regs *);
+extern void (*debugger_fault_handler)(struct pt_regs *);
+extern int (*debugger_dabr_match)(struct pt_regs *);
+int debugger_kernel_faults = 1;
+#endif
+
+extern void die_if_kernel(char *, struct pt_regs *, long);
+void bad_page_fault(struct pt_regs *, unsigned long);
+void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+
+#ifdef CONFIG_PPCDBG
+extern unsigned long get_srr0(void);
+extern unsigned long get_srr1(void);
+#endif
+
+/*
+ * For 600- and 800-family processors, the error_code parameter is DSISR
+ * for a data fault, SRR1 for an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+		   unsigned long error_code)
+{
+	struct vm_area_struct * vma;
+	struct mm_struct *mm = current->mm;
+	siginfo_t info;
+	unsigned long code = SEGV_MAPERR;
+	unsigned long is_write = error_code & 0x02000000;
+	unsigned long mm_fault_return;
+
+	PPCDBG(PPCDBG_MM, "Entering do_page_fault: addr = 0x%16.16lx, error_code = %lx\n\tregs_trap = %lx, srr0 = %lx, srr1 = %lx\n", address, error_code, regs->trap, get_srr0(), get_srr1());
+	/*
+	 * Fortunately the bit assignments in SRR1 for an instruction
+	 * fault and DSISR for a data fault are mostly the same for the
+	 * bits we are interested in.  But there are some bits which
+	 * indicate errors in DSISR but can validly be set in SRR1.
+	 */
+	if (regs->trap == 0x400)
+		error_code &= 0x48200000;
+
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	if (debugger_fault_handler && (regs->trap == 0x300 ||
+				regs->trap == 0x380)) {
+		debugger_fault_handler(regs);
+		return;
+	}
+
+	if (error_code & 0x00400000) {
+		/* DABR match */
+		if (debugger_dabr_match(regs))
+			return;
+	}
+#endif /* CONFIG_XMON || CONFIG_KGDB */
+
+	if (in_interrupt() || mm == NULL) {
+		bad_page_fault(regs, address);
+		return;
+	}
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, address);
+	PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma = 0x%16.16lx\n", vma);
+	if (!vma) {
+	        PPCDBG(PPCDBG_MM, "\tdo_page_fault: !vma\n");
+		goto bad_area;
+	}
+	PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_start = 0x%16.16lx, vma->vm_flags = 0x%16.16lx\n", vma->vm_start, vma->vm_flags);
+	if (vma->vm_start <= address) {
+		goto good_area;
+	}
+	if (!(vma->vm_flags & VM_GROWSDOWN)) {
+		PPCDBG(PPCDBG_MM, "\tdo_page_fault: vma->vm_flags = %lx, %lx\n", vma->vm_flags, VM_GROWSDOWN);
+		goto bad_area;
+	}
+	if (expand_stack(vma, address)) {
+		PPCDBG(PPCDBG_MM, "\tdo_page_fault: expand_stack\n");
+		goto bad_area;
+	}
+
+good_area:
+	code = SEGV_ACCERR;
+	
+	/* a write */
+	if (is_write) {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	/* a read */
+	} else {
+		/* protection fault */
+		if (error_code & 0x08000000)
+			goto bad_area;
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+			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.
+	 */
+	PPCDBG(PPCDBG_MM, "\tdo_page_fault: calling handle_mm_fault\n");
+        mm_fault_return = handle_mm_fault(mm, vma, address, is_write);
+	PPCDBG(PPCDBG_MM, "\tdo_page_fault: handle_mm_fault = 0x%lx\n", 
+	       mm_fault_return);
+        switch(mm_fault_return) {
+        case 1:
+                current->min_flt++;
+                break;
+        case 2:
+                current->maj_flt++;
+                break;
+        case 0:
+                goto do_sigbus;
+        default:
+                goto out_of_memory;
+	}
+
+	up_read(&mm->mmap_sem);
+	return;
+
+bad_area:
+	up_read(&mm->mmap_sem);
+	
+	/* User mode accesses cause a SIGSEGV */
+	if (user_mode(regs)) {
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		info.si_code = code;
+		info.si_addr = (void *) address;
+		PPCDBG(PPCDBG_SIGNAL, "Bad addr in user: 0x%lx\n", address);
+#ifdef CONFIG_XMON
+	        ifppcdebug(PPCDBG_SIGNALXMON)
+        	    PPCDBG_ENTER_DEBUGGER_REGS(regs);
+#endif
+
+		force_sig_info(SIGSEGV, &info, current);
+		return;
+	}
+
+	bad_page_fault(regs, address);
+	return;
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+	up_read(&mm->mmap_sem);
+	printk("VM: killing process %s\n", current->comm);
+	if (user_mode(regs))
+		do_exit(SIGKILL);
+	bad_page_fault(regs, address);
+	return;
+
+do_sigbus:
+	up_read(&mm->mmap_sem);
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRERR;
+	info.si_addr = (void *)address;
+	force_sig_info (SIGBUS, &info, current);
+	if (!user_mode(regs))
+		bad_page_fault(regs, address);
+}
+
+/*
+ * bad_page_fault is called when we have a bad access from the kernel.
+ * It is called from do_page_fault above and from some of the procedures
+ * in traps.c.
+ */
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address)
+{
+	unsigned long fixup;
+
+	/* Are we prepared to handle this fault?  */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return;
+	}
+
+	/* kernel has accessed a bad area */
+	show_regs(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	if (debugger_kernel_faults)
+		debugger(regs);
+#endif
+	print_backtrace( (unsigned long *)regs->gpr[1] );
+	panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
+	      regs->nip,regs->link,address,current->comm,current->pid);
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/mm/imalloc.c linux-2.4.19-pre5/arch/ppc64/mm/imalloc.c
--- linux-2.4.19-pre4/arch/ppc64/mm/imalloc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/mm/imalloc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,71 @@
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ * 
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+
+rwlock_t imlist_lock = RW_LOCK_UNLOCKED;
+struct vm_struct * imlist = NULL;
+
+struct vm_struct *get_im_area(unsigned long size)
+{
+	unsigned long addr;
+	struct vm_struct **p, *tmp, *area;
+  
+	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area)
+		return NULL;
+	addr = IMALLOC_START;
+	write_lock(&imlist_lock);
+	for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
+		if (size + addr < (unsigned long) tmp->addr)
+			break;
+		addr = tmp->size + (unsigned long) tmp->addr;
+		if (addr > IMALLOC_END-size) {
+			write_unlock(&imlist_lock);
+			kfree(area);
+			return NULL;
+		}
+	}
+	area->flags = 0;
+	area->addr = (void *)addr;
+	area->size = size;
+	area->next = *p;
+	*p = area;
+	write_unlock(&imlist_lock);
+	return area;
+}
+
+void ifree(void * addr)
+{
+	struct vm_struct **p, *tmp;
+  
+	if (!addr)
+		return;
+	if ((PAGE_SIZE-1) & (unsigned long) addr) {
+		printk(KERN_ERR "Trying to ifree() bad address (%p)\n", addr);
+		return;
+	}
+	write_lock(&imlist_lock);
+	for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
+		if (tmp->addr == addr) {
+			*p = tmp->next;
+			kfree(tmp);
+			write_unlock(&imlist_lock);
+			return;
+		}
+	}
+	write_unlock(&imlist_lock);
+	printk(KERN_ERR "Trying to ifree() nonexistent area (%p)\n", addr);
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/mm/init.c linux-2.4.19-pre5/arch/ppc64/mm/init.c
--- linux-2.4.19-pre4/arch/ppc64/mm/init.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/mm/init.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,715 @@
+/*
+ *  
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Dave Engebretsen <engebret@us.ibm.com>
+ *      Rework for PPC64 port.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>		/* for initrd_* */
+#endif
+
+#include <asm/pgalloc.h>
+#include <asm/page.h>
+#include <asm/abs_addr.h>
+#include <asm/prom.h>
+#include <asm/lmb.h>
+#include <asm/rtas.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/tlb.h>
+#include <asm/Naca.h>
+#ifdef CONFIG_PPC_EEH
+#include <asm/eeh.h>
+#endif
+
+#include <asm/ppcdebug.h>
+
+#define	PGTOKB(pages)	(((pages) * PAGE_SIZE) >> 10)
+
+#ifdef CONFIG_PPC_ISERIES
+#include <asm/iSeries/iSeries_dma.h>
+#endif
+
+struct mmu_context_queue_t mmu_context_queue;
+int mem_init_done;
+unsigned long ioremap_bot = IMALLOC_BASE;
+
+static int boot_mapsize;
+static unsigned long totalram_pages;
+
+extern pgd_t swapper_pg_dir[];
+extern char __init_begin, __init_end;
+extern char __chrp_begin, __chrp_end;
+extern char __openfirmware_begin, __openfirmware_end;
+extern struct _of_tce_table of_tce_table[];
+extern char _start[], _end[];
+extern char _stext[], etext[];
+extern struct task_struct *current_set[NR_CPUS];
+extern struct Naca *naca;
+
+void mm_init_ppc64(void);
+
+unsigned long *pmac_find_end_of_memory(void);
+extern unsigned long *find_end_of_memory(void);
+
+extern pgd_t ioremap_dir[];
+pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir;
+
+static void map_io_page(unsigned long va, unsigned long pa, int flags);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+
+unsigned long klimit = (unsigned long)_end;
+
+HPTE *Hash=0;
+unsigned long Hash_size=0;
+unsigned long _SDR1=0;
+unsigned long _ASR=0;
+
+/* max amount of RAM to use */
+unsigned long __max_memory;
+
+/* This is declared as we are using the more or less generic 
+ * include/asm-ppc64/tlb.h file -- tgall
+ */
+mmu_gather_t     mmu_gathers[NR_CPUS];
+
+int do_check_pgt_cache(int low, int high)
+{
+	int freed = 0;
+
+	if (pgtable_cache_size > high) {
+		do {
+			if (pgd_quicklist)
+				free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed;
+			if (pmd_quicklist)
+				free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed;
+			if (pte_quicklist)
+				free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed;
+		} while (pgtable_cache_size > low);
+	}
+	return freed;	
+}
+
+void show_mem(void)
+{
+	int i,free = 0,total = 0,reserved = 0;
+	int shared = 0, cached = 0;
+	struct task_struct *p;
+
+	printk("Mem-info:\n");
+	show_free_areas();
+	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+	i = max_mapnr;
+	while (i-- > 0) {
+		total++;
+		if (PageReserved(mem_map+i))
+			reserved++;
+		else if (PageSwapCache(mem_map+i))
+			cached++;
+		else if (!atomic_read(&mem_map[i].count))
+			free++;
+		else
+			shared += atomic_read(&mem_map[i].count) - 1;
+	}
+	printk("%d pages of RAM\n",total);
+	printk("%d free pages\n",free);
+	printk("%d reserved pages\n",reserved);
+	printk("%d pages shared\n",shared);
+	printk("%d pages swap cached\n",cached);
+	printk("%d pages in page table cache\n",(int)pgtable_cache_size);
+	show_buffers();
+	printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid",
+	       "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
+#ifdef CONFIG_SMP
+	printk(" %3s", "CPU");
+#endif /* CONFIG_SMP */
+	printk("\n");
+	for_each_task(p)
+	{
+		printk("%-8.8s %3d %8ld %8ld %8ld %c%08lx %08lx ",
+		       p->comm,p->pid,
+		       (p->mm)?p->mm->context:0,
+		       (p->mm)?(p->mm->context<<4):0,
+		       p->thread.last_syscall,
+		       (p->thread.regs)?user_mode(p->thread.regs) ? 'u' : 'k' : '?',
+		       (p->thread.regs)?p->thread.regs->nip:0,
+		       (ulong)p);
+		{
+			int iscur = 0;
+#ifdef CONFIG_SMP
+			printk("%3d ", p->processor);
+			if ( (p->processor != NO_PROC_ID) &&
+			     (p == current_set[p->processor]) )
+			{
+				iscur = 1;
+				printk("current");
+			}
+#else
+			if ( p == current )
+			{
+				iscur = 1;
+				printk("current");
+			}
+			
+			if ( p == last_task_used_math )
+			{
+				if ( iscur )
+					printk(",");
+				printk("last math");
+			}			
+#endif /* CONFIG_SMP */
+			printk("\n");
+		}
+	}
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ 	val->totalram = totalram_pages;
+	val->sharedram = 0;
+	val->freeram = nr_free_pages();
+	val->bufferram = atomic_read(&buffermem_pages);
+	val->totalhigh = 0;
+	val->freehigh = 0;
+	val->mem_unit = PAGE_SIZE;
+}
+
+void *
+ioremap(unsigned long addr, unsigned long size)
+{
+#ifdef CONFIG_PPC_ISERIES
+	return (void*)addr;
+#else
+#ifdef CONFIG_PPC_EEH
+	if(mem_init_done && (addr >> 60UL)) {
+		if (IS_EEH_TOKEN_DISABLED(addr))
+			return IO_TOKEN_TO_ADDR(addr);
+		return (void*)addr; /* already mapped address or EEH token. */
+	}
+#endif
+	return __ioremap(addr, size, _PAGE_NO_CACHE);
+#endif
+}
+
+extern struct vm_struct * get_im_area( unsigned long size );
+
+void *
+__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+{
+	unsigned long pa, ea, i;
+
+	/*
+	 * Choose an address to map it to.
+	 * Once the imalloc system is running, we use it.
+	 * Before that, we map using addresses going
+	 * up from ioremap_bot.  imalloc will use
+	 * the addresses from ioremap_bot through
+	 * IMALLOC_END (0xE000001fffffffff)
+	 * 
+	 */
+	pa = addr & PAGE_MASK;
+	size = PAGE_ALIGN(addr + size) - pa;
+
+	if (size == 0)
+		return NULL;
+
+	if (mem_init_done) {
+		struct vm_struct *area;
+		area = get_im_area(size);
+		if (area == 0)
+			return NULL;
+		ea = (unsigned long)(area->addr);
+	} 
+	else {
+		ea = ioremap_bot;
+		ioremap_bot += size;
+        }
+
+	if ((flags & _PAGE_PRESENT) == 0)
+		flags |= pgprot_val(PAGE_KERNEL);
+	if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
+		flags |= _PAGE_GUARDED;
+
+	for (i = 0; i < size; i += PAGE_SIZE) {
+		map_io_page(ea+i, pa+i, flags);
+	}
+
+	return (void *) (ea + (addr & ~PAGE_MASK));
+}
+
+void iounmap(void *addr) 
+{
+#ifdef CONFIG_PPC_ISERIES
+     /* iSeries I/O Remap is a noop              */
+	return;
+#else 
+	/* DRENG / PPPBBB todo */
+	return;
+#endif
+}
+
+/*
+ * map_io_page currently only called by __ioremap
+ * map_io_page adds an entry to the ioremap page table
+ * and adds an entry to the HPT, possibly bolting it
+ */
+static void map_io_page(unsigned long ea, unsigned long pa, int flags)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	unsigned long vsid;
+	
+	if (mem_init_done) {
+		spin_lock(&ioremap_mm.page_table_lock);
+		pgdp = pgd_offset_i(ea);
+		pmdp = pmd_alloc(&ioremap_mm, pgdp, ea);
+		ptep = pte_alloc(&ioremap_mm, pmdp, ea);
+
+		pa = absolute_to_phys(pa);
+		set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+		spin_unlock(&ioremap_mm.page_table_lock);
+	} else {
+		/* If the mm subsystem is not fully up, we cannot create a
+		 * linux page table entry for this mapping.  Simply bolt an
+		 * entry in the hardware page table. 
+ 		 */
+		vsid = get_kernel_vsid(ea);
+		make_pte(htab_data.htab,
+			(vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
+			pa, 
+			_PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX,
+			htab_data.htab_hash_mask, 0);
+	}
+}
+
+#if 0
+void
+local_flush_tlb_all(void)
+{
+	/* Implemented to just flush the vmalloc area.
+	 * vmalloc is the only user of flush_tlb_all.
+	 */
+	local_flush_tlb_range( NULL, VMALLOC_START, VMALLOC_END );
+}
+#endif
+
+void
+local_flush_tlb_mm(struct mm_struct *mm)
+{
+	if ( mm->map_count ) {
+		struct vm_area_struct *mp;
+		for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next )
+			local_flush_tlb_range( mm, mp->vm_start, mp->vm_end );
+	}
+	else	/* MIKEC: It is not clear why this is needed */
+		/* paulus: it is needed to clear out stale HPTEs
+		 * when an address space (represented by an mm_struct)
+		 * is being destroyed. */
+		local_flush_tlb_range( mm, USER_START, USER_END );
+}
+
+
+/*
+ * Callers should hold the mm->page_table_lock
+ */
+void
+local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+	unsigned long context = 0;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *ptep;
+	pte_t pte;
+	
+	switch( REGION_ID(vmaddr) ) {
+	case VMALLOC_REGION_ID:
+		pgd = pgd_offset_k( vmaddr );
+		break;
+	case IO_REGION_ID:
+		pgd = pgd_offset_i( vmaddr );
+		break;
+	case USER_REGION_ID:
+		pgd = pgd_offset( vma->vm_mm, vmaddr );
+		context = vma->vm_mm->context;
+		break;
+	default:
+		panic("local_flush_tlb_page: invalid region 0x%016lx", vmaddr);
+	
+	}
+
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, vmaddr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, vmaddr);
+			/* Check if HPTE might exist and flush it if so */
+			pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
+			if ( pte_val(pte) & _PAGE_HASHPTE ) {
+				flush_hash_page(context, vmaddr, pte);
+			}
+		}
+	}
+}
+
+void
+local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *ptep;
+	pte_t pte;
+	unsigned long pgd_end, pmd_end;
+	unsigned long context;
+
+	if ( start >= end )
+		panic("flush_tlb_range: start (%016lx) greater than end (%016lx)\n", start, end );
+
+	if ( REGION_ID(start) != REGION_ID(end) )
+		panic("flush_tlb_range: start (%016lx) and end (%016lx) not in same region\n", start, end );
+	
+	context = 0;
+
+	switch( REGION_ID(start) ) {
+	case VMALLOC_REGION_ID:
+		pgd = pgd_offset_k( start );
+		break;
+	case IO_REGION_ID:
+		pgd = pgd_offset_i( start );
+		break;
+	case USER_REGION_ID:
+		pgd = pgd_offset( mm, start );
+		context = mm->context;
+		break;
+	default:
+		panic("flush_tlb_range: invalid region for start (%016lx) and end (%016lx)\n", start, end);
+	
+	}
+
+	do {
+		pgd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
+		if ( pgd_end > end ) 
+			pgd_end = end;
+		if ( !pgd_none( *pgd ) ) {
+			pmd = pmd_offset( pgd, start );
+			do {
+				pmd_end = ( start + PMD_SIZE ) & PMD_MASK;
+				if ( pmd_end > end )
+					pmd_end = end;
+				if ( !pmd_none( *pmd ) ) {
+					ptep = pte_offset( pmd, start );
+					do {
+						if ( pte_val(*ptep) & _PAGE_HASHPTE ) {
+							pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
+							if ( pte_val(pte) & _PAGE_HASHPTE )
+								flush_hash_page( context, start, pte );
+						}
+						start += PAGE_SIZE;
+						++ptep;
+					} while ( start < pmd_end );
+				}
+				else
+					start = pmd_end;
+				++pmd;
+			} while ( start < pgd_end );
+		}
+		else
+			start = pgd_end;
+		++pgd;
+	} while ( start < end );
+}
+
+
+void __init free_initmem(void)
+{
+	unsigned long a;
+	unsigned long num_freed_pages = 0;
+#define FREESEC(START,END,CNT) do { \
+	a = (unsigned long)(&START); \
+	for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \
+	  	clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); \
+		set_page_count(mem_map+MAP_NR(a), 1); \
+		free_page(a); \
+		CNT++; \
+	} \
+} while (0)
+
+	FREESEC(__init_begin,__init_end,num_freed_pages);
+
+	printk ("Freeing unused kernel memory: %ldk init\n",
+		PGTOKB(num_freed_pages));
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	unsigned long xstart = start;
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(mem_map + MAP_NR(start));
+		set_page_count(mem_map+MAP_NR(start), 1);
+		free_page(start);
+		totalram_pages++;
+	}
+	printk ("Freeing initrd memory: %ldk freed\n", (end - xstart) >> 10);
+}
+#endif
+
+
+
+/*
+ * Do very early mm setup.
+ */
+void __init mm_init_ppc64(void) {
+	struct Paca *paca;
+	unsigned long guard_page, index;
+
+	ppc_md.progress("MM:init", 0);
+
+	/* Reserve all contexts < FIRST_USER_CONTEXT for kernel use.
+	 * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT)
+	 * are stored on a stack/queue for easy allocation and deallocation.
+	 */
+        mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
+        mmu_context_queue.head = 0;
+        mmu_context_queue.tail = NUM_USER_CONTEXT-1;
+        mmu_context_queue.size = NUM_USER_CONTEXT;
+	for(index=0; index < NUM_USER_CONTEXT ;index++) {
+                mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
+	}
+
+	/* Setup guard pages for the Paca's */
+	for (index = 0; index < NR_CPUS; index++) {
+		paca = &xPaca[index];
+		guard_page = ((unsigned long)paca) + 0x1000;
+		ppc_md.hpte_updateboltedpp(PP_RXRX, guard_page);
+	}
+
+	ppc_md.progress("MM:exit", 0x211);
+}
+
+
+
+/*
+ * Initialize the bootmem system and give it all the memory we
+ * have available.
+ */
+void __init do_init_bootmem(void)
+{
+	unsigned long i;
+	unsigned long start, bootmap_pages;
+	unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT;
+
+	PPCDBG(PPCDBG_MMINIT, "do_init_bootmem: start\n");
+	/*
+	 * Find an area to use for the bootmem bitmap.  Calculate the size of
+	 * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE.
+	 * Add 1 additional page in case the address isn't page-aligned.
+	 */
+	bootmap_pages = bootmem_bootmap_pages(total_pages);
+
+	start = (unsigned long)__a2p(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
+	if( start == 0 ) {
+		udbg_printf("do_init_bootmem: failed to allocate a bitmap.\n");
+		udbg_printf("\tbootmap_pages = 0x%lx.\n", bootmap_pages);
+		PPCDBG_ENTER_DEBUGGER(); 
+	}
+
+	PPCDBG(PPCDBG_MMINIT, "\tstart               = 0x%lx\n", start);
+	PPCDBG(PPCDBG_MMINIT, "\tbootmap_pages       = 0x%lx\n", bootmap_pages);
+	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", naca->physicalMemorySize);
+
+	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
+	PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize        = 0x%lx\n", boot_mapsize);
+
+	/* add all physical memory to the bootmem map */
+	for (i=0; i < lmb.memory.cnt ;i++) {
+		unsigned long physbase, size;
+		unsigned long type = lmb.memory.region[i].type;
+
+		if ( type != LMB_MEMORY_AREA )
+			continue;
+
+		physbase = lmb.memory.region[i].physbase;
+		size = lmb.memory.region[i].size;
+		free_bootmem(physbase, size);
+	}
+	/* reserve the sections we're already using */
+	for (i=0; i < lmb.reserved.cnt ;i++) {
+		unsigned long physbase = lmb.reserved.region[i].physbase;
+		unsigned long size = lmb.reserved.region[i].size;
+#if 0 /* PPPBBB */
+		if ( (physbase == 0) && (size < (16<<20)) ) {
+			size = 16 << 20;
+		}
+#endif
+		reserve_bootmem(physbase, size);
+	}
+
+	PPCDBG(PPCDBG_MMINIT, "do_init_bootmem: end\n");
+}
+
+/*
+ * paging_init() sets up the page tables - in fact we've already done this.
+ */
+void __init paging_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES], i;
+
+	/*
+	 * All pages are DMA-able so we put them all in the DMA zone.
+	 */
+	zones_size[0] = lmb_end_of_DRAM() >> PAGE_SHIFT;
+	for (i = 1; i < MAX_NR_ZONES; i++)
+		zones_size[i] = 0;
+	free_area_init(zones_size);
+}
+
+extern unsigned long prof_shift;
+extern unsigned long prof_len;
+extern unsigned int * prof_buffer;
+extern unsigned long dprof_shift;
+extern unsigned long dprof_len;
+extern unsigned int * dprof_buffer;
+
+void __init mem_init(void)
+{
+	extern char *sysmap; 
+	extern unsigned long sysmap_size;
+	unsigned long addr;
+	int codepages = 0;
+	int datapages = 0;
+	int initpages = 0;
+	unsigned long va_rtas_base = (unsigned long)__va(rtas.base);
+	max_mapnr = max_low_pfn;
+	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
+
+	totalram_pages += free_all_bootmem();
+
+	ifppcdebug(PPCDBG_MMINIT) {
+		udbg_printf("mem_init: totalram_pages = 0x%lx\n", totalram_pages);
+		udbg_printf("mem_init: va_rtas_base   = 0x%lx\n", va_rtas_base); 
+		udbg_printf("mem_init: va_rtas_end    = 0x%lx\n", PAGE_ALIGN(va_rtas_base+rtas.size)); 
+		udbg_printf("mem_init: pinned start   = 0x%lx\n", __va(0)); 
+		udbg_printf("mem_init: pinned end     = 0x%lx\n", PAGE_ALIGN(klimit)); 
+	}
+
+	if ( sysmap_size )
+		for (addr = (unsigned long)sysmap;
+		     addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ;
+		     addr += PAGE_SIZE)
+			SetPageReserved(mem_map + MAP_NR(addr));
+	
+	for (addr = KERNELBASE; addr <= (unsigned long)__va(lmb_end_of_DRAM());
+	     addr += PAGE_SIZE) {
+		if (!PageReserved(mem_map + MAP_NR(addr)))
+			continue;
+		if (addr < (ulong) etext)
+			codepages++;
+
+		else if (addr >= (unsigned long)&__init_begin
+			 && addr < (unsigned long)&__init_end)
+			initpages++;
+		else if (addr < klimit)
+			datapages++;
+	}
+
+        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+	       (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10),
+	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
+	       initpages<< (PAGE_SHIFT-10),
+	       PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM()));
+	mem_init_done = 1;
+
+    /* set the last page of each hardware interrupt stack to be protected       */
+    initialize_paca_hardware_interrupt_stack();
+
+#ifdef CONFIG_PPC_ISERIES
+	create_virtual_bus_tce_table();
+	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
+	prof_shift = dprof_shift;
+	prof_len = dprof_len;
+	prof_buffer = dprof_buffer;
+#endif
+}
+
+
+
+/*
+ * This is called when a page has been modified by the kernel.
+ * It just marks the page as not i-cache clean.  We do the i-cache
+ * flush later when the page is given to a user process, if necessary.
+ */
+void flush_dcache_page(struct page *page)
+{
+	clear_bit(PG_arch_1, &page->flags);
+}
+
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+	if (page->mapping && !PageReserved(page)
+	    && !test_bit(PG_arch_1, &page->flags)) {
+		__flush_dcache_icache(page_address(page));
+		set_bit(PG_arch_1, &page->flags);
+	}
+}
+
+void clear_user_page(void *page, unsigned long vaddr)
+{
+	clear_page(page);
+}
+
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr)
+{
+	copy_page(vto, vfrom);
+	__flush_dcache_icache(vto);
+}
+
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+			     unsigned long addr, int len)
+{
+	unsigned long maddr;
+
+	maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK);
+	flush_icache_range(maddr, maddr + len);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/vmlinux.lds linux-2.4.19-pre5/arch/ppc64/vmlinux.lds
--- linux-2.4.19-pre4/arch/ppc64/vmlinux.lds	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/vmlinux.lds	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,140 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)		}
+  .dynsym        : { *(.dynsym)		}
+  .dynstr        : { *(.dynstr)		}
+  .rel.text      : { *(.rel.text)		}
+  .rela.text     : { *(.rela.text) 	}
+  .rel.data      : { *(.rel.data)		}
+  .rela.data     : { *(.rela.data) 	}
+  .rel.rodata    : { *(.rel.rodata) 	}
+  .rela.rodata   : { *(.rela.rodata) 	}
+  .rel.got       : { *(.rel.got)		}
+  .rela.got      : { *(.rela.got)		}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.bss       : { *(.rel.bss)		}
+  .rela.bss      : { *(.rela.bss)		}
+  .rel.plt       : { *(.rel.plt)		}
+  .rela.plt      : { *(.rela.plt)		}
+/*  .init          : { *(.init)	} =0*/
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  . = ALIGN(4096);
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFFFFFFFFFF000;
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  . = ALIGN(4096);
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  .fixup   : { *(.fixup) }
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;        /* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+  __start___kallsyms = .;	/* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.page_aligned) }
+
+  . = ALIGN(128);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { 
+    *(.data.init);
+    __vtop_table_begin = .;
+    *(.vtop_fixup);
+    __vtop_table_end = .;
+    __ptov_table_begin = .;
+    *(.ptov_fixup);
+    __ptov_table_end = .;
+  }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+
+
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __chrp_begin = .;
+  .text.chrp : { *(.text.chrp) }
+  .data.chrp : { *(.data.chrp) }
+  . = ALIGN(4096);
+  __chrp_end = .;
+
+  . = ALIGN(4096);
+  __openfirmware_begin = .;
+  .text.openfirmware : { *(.text.openfirmware) }
+  .data.openfirmware : { *(.data.openfirmware) }
+  . = ALIGN(4096);
+  __openfirmware_end = .;
+
+  __toc_start = .;
+  .toc       :
+  {
+   *(.toc)
+  }
+  . = ALIGN(4096);
+  __toc_end = .;
+
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+
+  . = ALIGN(4096);
+  _end = . ;
+  PROVIDE (end = .);
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/Makefile linux-2.4.19-pre5/arch/ppc64/xmon/Makefile
--- linux-2.4.19-pre4/arch/ppc64/xmon/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/Makefile	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,9 @@
+# Makefile for xmon
+
+EXTRA_CFLAGS = -mno-minimal-toc
+
+O_TARGET = x.o
+
+obj-y       := start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/adb.c linux-2.4.19-pre5/arch/ppc64/xmon/adb.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/adb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/adb.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "privinst.h"
+
+#define scanhex	xmon_scanhex
+#define skipbl	xmon_skipbl
+
+#define ADB_B		(*(volatile unsigned char *)0xf3016000)
+#define ADB_SR		(*(volatile unsigned char *)0xf3017400)
+#define ADB_ACR		(*(volatile unsigned char *)0xf3017600)
+#define ADB_IFR		(*(volatile unsigned char *)0xf3017a00)
+
+static inline void eieio(void) { asm volatile ("eieio" : :); }
+
+#define N_ADB_LOG	1000
+struct adb_log {
+    unsigned char b;
+    unsigned char ifr;
+    unsigned char acr;
+    unsigned int time;
+} adb_log[N_ADB_LOG];
+int n_adb_log;
+
+void
+init_adb_log(void)
+{
+    adb_log[0].b = ADB_B;
+    adb_log[0].ifr = ADB_IFR;
+    adb_log[0].acr = ADB_ACR;
+    adb_log[0].time = get_dec();
+    n_adb_log = 0;
+}
+
+void
+dump_adb_log(void)
+{
+    unsigned t, t0;
+    struct adb_log *ap;
+    int i;
+
+    ap = adb_log;
+    t0 = ap->time;
+    for (i = 0; i <= n_adb_log; ++i, ++ap) {
+	t = t0 - ap->time;
+	printf("b=%x ifr=%x acr=%x at %d.%.7d\n", ap->b, ap->ifr, ap->acr,
+	       t / 1000000000, (t % 1000000000) / 100);
+    }
+}
+
+void
+adb_chklog(void)
+{
+    struct adb_log *ap = &adb_log[n_adb_log + 1];
+
+    ap->b = ADB_B;
+    ap->ifr = ADB_IFR;
+    ap->acr = ADB_ACR;
+    if (ap->b != ap[-1].b || (ap->ifr & 4) != (ap[-1].ifr & 4)
+	|| ap->acr != ap[-1].acr) {
+	ap->time = get_dec();
+	++n_adb_log;
+    }
+}
+
+int
+adb_bitwait(int bmask, int bval, int fmask, int fval)
+{
+    int i;
+    struct adb_log *ap;
+
+    for (i = 10000; i > 0; --i) {
+	adb_chklog();
+	ap = &adb_log[n_adb_log];
+	if ((ap->b & bmask) == bval && (ap->ifr & fmask) == fval)
+	    return 0;
+    }
+    return -1;
+}
+
+int
+adb_wait(void)
+{
+    if (adb_bitwait(0, 0, 4, 4) < 0) {
+	printf("adb: ready wait timeout\n");
+	return -1;
+    }
+    return 0;
+}
+
+void
+adb_readin(void)
+{
+    int i, j;
+    unsigned char d[64];
+
+    if (ADB_B & 8) {
+	printf("ADB_B: %x\n", ADB_B);
+	return;
+    }
+    i = 0;
+    adb_wait();
+    j = ADB_SR;
+    eieio();
+    ADB_B &= ~0x20;
+    eieio();
+    for (;;) {
+	if (adb_wait() < 0)
+	    break;
+	d[i++] = ADB_SR;
+	eieio();
+	if (ADB_B & 8)
+	    break;
+	ADB_B ^= 0x10;
+	eieio();
+    }
+    ADB_B |= 0x30;
+    if (adb_wait() == 0)
+	j = ADB_SR;
+    for (j = 0; j < i; ++j)
+	printf("%.2x ", d[j]);
+    printf("\n");
+}
+
+int
+adb_write(unsigned char *d, int i)
+{
+    int j;
+    unsigned x;
+
+    if ((ADB_B & 8) == 0) {
+	printf("r: ");
+	adb_readin();
+    }
+    for (;;) {
+	ADB_ACR = 0x1c;
+	eieio();
+	ADB_SR = d[0];
+	eieio();
+	ADB_B &= ~0x20;
+	eieio();
+	if (ADB_B & 8)
+	    break;
+	ADB_ACR = 0xc;
+	eieio();
+	ADB_B |= 0x20;
+	eieio();
+	adb_readin();
+    }
+    adb_wait();
+    for (j = 1; j < i; ++j) {
+	ADB_SR = d[j];
+	eieio();
+	ADB_B ^= 0x10;
+	eieio();
+	if (adb_wait() < 0)
+	    break;
+    }
+    ADB_ACR = 0xc;
+    eieio();
+    x = ADB_SR;
+    eieio();
+    ADB_B |= 0x30;
+    return j;
+}
+
+void
+adbcmds(void)
+{
+    char cmd;
+    unsigned rtcu, rtcl, dec, pdec, x;
+    int i, j;
+    unsigned char d[64];
+
+    cmd = skipbl();
+    switch (cmd) {
+    case 't':
+	for (;;) {
+	    rtcl = get_rtcl();
+	    rtcu = get_rtcu();
+	    dec = get_dec();
+	    printf("rtc u=%u l=%u dec=%x (%d = %d.%.7d)\n",
+		   rtcu, rtcl, dec, pdec - dec, (pdec - dec) / 1000000000,
+		   ((pdec - dec) % 1000000000) / 100);
+	    pdec = dec;
+	    if (cmd == 'x')
+		break;
+	    while (xmon_read(stdin, &cmd, 1) != 1)
+		;
+	}
+	break;
+    case 'r':
+	init_adb_log();
+	while (adb_bitwait(8, 0, 0, 0) == 0)
+	    adb_readin();
+	break;
+    case 'w':
+	i = 0;
+	while (scanhex(&x))
+	    d[i++] = x;
+	init_adb_log();
+	j = adb_write(d, i);
+	printf("sent %d bytes\n", j);
+	while (adb_bitwait(8, 0, 0, 0) == 0)
+	    adb_readin();
+	break;
+    case 'l':
+	dump_adb_log();
+	break;
+    }
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/ansidecl.h linux-2.4.19-pre5/arch/ppc64/xmon/ansidecl.h
--- linux-2.4.19-pre4/arch/ppc64/xmon/ansidecl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/ansidecl.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,141 @@
+/* ANSI and traditional C compatability macros
+   Copyright 1991, 1992 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* ANSI and traditional C compatibility macros
+
+   ANSI C is assumed if __STDC__ is #defined.
+
+   Macro	ANSI C definition	Traditional C definition
+   -----	---- - ----------	----------- - ----------
+   PTR		`void *'		`char *'
+   LONG_DOUBLE	`long double'		`double'
+   VOLATILE	`volatile'		`'
+   SIGNED	`signed'		`'
+   PTRCONST	`void *const'		`char *'
+   ANSI_PROTOTYPES  1			not defined
+
+   CONST is also defined, but is obsolete.  Just use const.
+
+   DEFUN (name, arglist, args)
+
+	Defines function NAME.
+
+	ARGLIST lists the arguments, separated by commas and enclosed in
+	parentheses.  ARGLIST becomes the argument list in traditional C.
+
+	ARGS list the arguments with their types.  It becomes a prototype in
+	ANSI C, and the type declarations in traditional C.  Arguments should
+	be separated with `AND'.  For functions with a variable number of
+	arguments, the last thing listed should be `DOTS'.
+
+   DEFUN_VOID (name)
+
+	Defines a function NAME, which takes no arguments.
+
+   obsolete --     EXFUN (name, (prototype))	-- obsolete.
+
+	Replaced by PARAMS.  Do not use; will disappear someday soon.
+	Was used in external function declarations.
+	In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in
+	parentheses).  In traditional C it is `NAME()'.
+	For a function that takes no arguments, PROTOTYPE should be `(void)'.
+
+    PARAMS ((args))
+
+	We could use the EXFUN macro to handle prototype declarations, but
+	the name is misleading and the result is ugly.  So we just define a
+	simple macro to handle the parameter lists, as in:
+
+	      static int foo PARAMS ((int, char));
+
+	This produces:  `static int foo();' or `static int foo (int, char);'
+
+	EXFUN would have done it like this:
+
+	      static int EXFUN (foo, (int, char));
+
+	but the function is not external...and it's hard to visually parse
+	the function name out of the mess.   EXFUN should be considered
+	obsolete; new code should be written to use PARAMS.
+
+    For example:
+	extern int printf PARAMS ((CONST char *format DOTS));
+	int DEFUN(fprintf, (stream, format),
+		  FILE *stream AND CONST char *format DOTS) { ... }
+	void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef	_ANSIDECL_H
+
+#define	_ANSIDECL_H	1
+
+
+/* Every source file includes this file,
+   so they will all get the switch for lint.  */
+/* LINTLIBRARY */
+
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32)
+/* All known AIX compilers implement these things (but don't always
+   define __STDC__).  The RISC/OS MIPS compiler defines these things
+   in SVR4 mode, but does not define __STDC__.  */
+
+#define	PTR		void *
+#define	PTRCONST	void *CONST
+#define	LONG_DOUBLE	long double
+
+#define	AND		,
+#define	NOARGS		void
+#define	CONST		const
+#define	VOLATILE	volatile
+#define	SIGNED		signed
+#define	DOTS		, ...
+
+#define	EXFUN(name, proto)		name proto
+#define	DEFUN(name, arglist, args)	name(args)
+#define	DEFUN_VOID(name)		name(void)
+
+#define PROTO(type, name, arglist)	type name arglist
+#define PARAMS(paramlist)		paramlist
+#define ANSI_PROTOTYPES			1
+
+#else	/* Not ANSI C.  */
+
+#define	PTR		char *
+#define	PTRCONST	PTR
+#define	LONG_DOUBLE	double
+
+#define	AND		;
+#define	NOARGS
+#define	CONST
+#ifndef const /* some systems define it in header files for non-ansi mode */
+#define	const
+#endif
+#define	VOLATILE
+#define	SIGNED
+#define	DOTS
+
+#define	EXFUN(name, proto)		name()
+#define	DEFUN(name, arglist, args)	name arglist args;
+#define	DEFUN_VOID(name)		name()
+#define PROTO(type, name, arglist) type name ()
+#define PARAMS(paramlist)		()
+
+#endif	/* ANSI C.  */
+
+#endif	/* ansidecl.h	*/
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/nonstdio.h linux-2.4.19-pre5/arch/ppc64/xmon/nonstdio.h
--- linux-2.4.19-pre4/arch/ppc64/xmon/nonstdio.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/nonstdio.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,22 @@
+typedef int	FILE;
+extern FILE *xmon_stdin, *xmon_stdout;
+#define EOF	(-1)
+#define stdin	xmon_stdin
+#define stdout	xmon_stdout
+#define printf	xmon_printf
+#define fprintf	xmon_fprintf
+#define fputs	xmon_fputs
+#define fgets	xmon_fgets
+#define putchar	xmon_putchar
+#define getchar	xmon_getchar
+#define putc	xmon_putc
+#define getc	xmon_getc
+#define fopen(n, m)	NULL
+#define fflush(f)	do {} while (0)
+#define fclose(f)	do {} while (0)
+extern char *fgets(char *, int, void *);
+extern void xmon_printf(const char *, ...);
+extern void xmon_fprintf(void *, const char *, ...);
+extern void xmon_sprintf(char *, const char *, ...);
+
+#define perror(s)	printf("%s: no files!\n", (s))
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/ppc-dis.c linux-2.4.19-pre5/arch/ppc64/xmon/ppc-dis.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/ppc-dis.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/ppc-dis.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,190 @@
+/* ppc-dis.c -- Disassemble PowerPC instructions
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "nonstdio.h"
+#include "ansidecl.h"
+#include "ppc.h"
+
+static int print_insn_powerpc PARAMS ((FILE *, unsigned long insn,
+				       unsigned long memaddr, int dialect));
+
+extern void print_address PARAMS((unsigned long memaddr));
+
+/* Print a big endian PowerPC instruction.  For convenience, also
+   disassemble instructions supported by the Motorola PowerPC 601.  */
+
+int
+print_insn_big_powerpc (FILE *out, unsigned long insn, unsigned long memaddr)
+{
+  return print_insn_powerpc (out, insn, memaddr,
+			     PPC_OPCODE_PPC | PPC_OPCODE_601);
+}
+
+/* Print a PowerPC or POWER instruction.  */
+
+static int
+print_insn_powerpc (FILE *out, unsigned long insn, unsigned long memaddr,
+		    int dialect)
+{
+  const struct powerpc_opcode *opcode;
+  const struct powerpc_opcode *opcode_end;
+  unsigned long op;
+
+  /* Get the major opcode of the instruction.  */
+  op = PPC_OP (insn);
+
+  /* Find the first match in the opcode table.  We could speed this up
+     a bit by doing a binary search on the major opcode.  */
+  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
+  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
+    {
+      unsigned long table_op;
+      const unsigned char *opindex;
+      const struct powerpc_operand *operand;
+      int invalid;
+      int need_comma;
+      int need_paren;
+
+      table_op = PPC_OP (opcode->opcode);
+      if (op < table_op)
+		break;
+      if (op > table_op)
+		continue;
+
+      if ((insn & opcode->mask) != opcode->opcode
+	  || (opcode->flags & dialect) == 0)
+		continue;
+
+      /* Make two passes over the operands.  First see if any of them
+		 have extraction functions, and, if they do, make sure the
+		 instruction is valid.  */
+      invalid = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+		{
+		  operand = powerpc_operands + *opindex;
+		  if (operand->extract)
+		    (*operand->extract) (insn, &invalid);
+		}
+      if (invalid)
+		continue;
+
+      /* The instruction is valid.  */
+      fprintf(out, "%s", opcode->name);
+      if (opcode->operands[0] != 0)
+		fprintf(out, "\t");
+
+      /* Now extract and print the operands.  */
+      need_comma = 0;
+      need_paren = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+		{
+		  long value;
+
+		  operand = powerpc_operands + *opindex;
+
+		  /* Operands that are marked FAKE are simply ignored.  We
+		     already made sure that the extract function considered
+		     the instruction to be valid.  */
+		  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
+		    continue;
+
+		  /* Extract the value from the instruction.  */
+		  if (operand->extract)
+		    value = (*operand->extract) (insn, (int *) 0);
+		  else
+		    {
+		      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+		      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
+			  && (value & (1 << (operand->bits - 1))) != 0)
+			value -= 1 << operand->bits;
+		    }
+
+		  /* If the operand is optional, and the value is zero, don't
+		     print anything.  */
+		  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+		      && (operand->flags & PPC_OPERAND_NEXT) == 0
+		      && value == 0)
+		    continue;
+
+		  if (need_comma)
+		    {
+		      fprintf(out, ",");
+		      need_comma = 0;
+		    }
+
+		  /* Print the operand as directed by the flags.  */
+		  if ((operand->flags & PPC_OPERAND_GPR) != 0)
+		    fprintf(out, "r%ld", value);
+		  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+		    fprintf(out, "f%ld", value);
+		  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
+		    print_address (memaddr + value);
+		  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+		    print_address (value & 0xffffffff);
+		  else if ((operand->flags & PPC_OPERAND_CR) == 0
+			   || (dialect & PPC_OPCODE_PPC) == 0)
+		    fprintf(out, "%ld", value);
+		  else
+		    {
+		      if (operand->bits == 3)
+				fprintf(out, "cr%d", value);
+		      else
+			{
+			  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
+			  int cr;
+			  int cc;
+
+			  cr = value >> 2;
+			  if (cr != 0)
+			    fprintf(out, "4*cr%d", cr);
+			  cc = value & 3;
+			  if (cc != 0)
+			    {
+			      if (cr != 0)
+					fprintf(out, "+");
+			      fprintf(out, "%s", cbnames[cc]);
+			    }
+			}
+	    }
+
+	  if (need_paren)
+	    {
+	      fprintf(out, ")");
+	      need_paren = 0;
+	    }
+
+	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
+	    need_comma = 1;
+	  else
+	    {
+	      fprintf(out, "(");
+	      need_paren = 1;
+	    }
+	}
+
+      /* We have found and printed an instruction; return.  */
+      return 4;
+    }
+
+  /* We could not find a match.  */
+  fprintf(out, ".long 0x%lx", insn);
+
+  return 4;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/ppc-opc.c linux-2.4.19-pre5/arch/ppc64/xmon/ppc-opc.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/ppc-opc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/ppc-opc.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,2816 @@
+/* ppc-opc.c -- PowerPC opcode list
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+2, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <linux/posix_types.h>
+#include "ansidecl.h"
+#include "ppc.h"
+
+/* This file holds the PowerPC opcode table.  The opcode table
+   includes almost all of the extended instruction mnemonics.  This
+   permits the disassembler to use them, and simplifies the assembler
+   logic, at the cost of increasing the table size.  The table is
+   strictly constant data, so the compiler should be able to put it in
+   the .text section.
+
+   This file also holds the operand table.  All knowledge about
+   inserting operands into instructions and vice-versa is kept in this
+   file.  */
+
+/* Local insertion and extraction functions.  */
+
+static unsigned long insert_bat PARAMS ((unsigned long, long, const char **));
+static long extract_bat PARAMS ((unsigned long, int *));
+static unsigned long insert_bba PARAMS ((unsigned long, long, const char **));
+static long extract_bba PARAMS ((unsigned long, int *));
+static unsigned long insert_bd PARAMS ((unsigned long, long, const char **));
+static long extract_bd PARAMS ((unsigned long, int *));
+static unsigned long insert_bdm PARAMS ((unsigned long, long, const char **));
+static long extract_bdm PARAMS ((unsigned long, int *));
+static unsigned long insert_bdp PARAMS ((unsigned long, long, const char **));
+static long extract_bdp PARAMS ((unsigned long, int *));
+static unsigned long insert_bo PARAMS ((unsigned long, long, const char **));
+static long extract_bo PARAMS ((unsigned long, int *));
+static unsigned long insert_boe PARAMS ((unsigned long, long, const char **));
+static long extract_boe PARAMS ((unsigned long, int *));
+static unsigned long insert_ds PARAMS ((unsigned long, long, const char **));
+static long extract_ds PARAMS ((unsigned long, int *));
+static unsigned long insert_li PARAMS ((unsigned long, long, const char **));
+static long extract_li PARAMS ((unsigned long, int *));
+static unsigned long insert_mbe PARAMS ((unsigned long, long, const char **));
+static long extract_mbe PARAMS ((unsigned long, int *));
+static unsigned long insert_mb6 PARAMS ((unsigned long, long, const char **));
+static long extract_mb6 PARAMS ((unsigned long, int *));
+static unsigned long insert_nb PARAMS ((unsigned long, long, const char **));
+static long extract_nb PARAMS ((unsigned long, int *));
+static unsigned long insert_nsi PARAMS ((unsigned long, long, const char **));
+static long extract_nsi PARAMS ((unsigned long, int *));
+static unsigned long insert_ral PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_ram PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_ras PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_rbs PARAMS ((unsigned long, long, const char **));
+static long extract_rbs PARAMS ((unsigned long, int *));
+static unsigned long insert_sh6 PARAMS ((unsigned long, long, const char **));
+static long extract_sh6 PARAMS ((unsigned long, int *));
+static unsigned long insert_spr PARAMS ((unsigned long, long, const char **));
+static long extract_spr PARAMS ((unsigned long, int *));
+static unsigned long insert_tbr PARAMS ((unsigned long, long, const char **));
+static long extract_tbr PARAMS ((unsigned long, int *));
+
+/* The operands table.
+
+   The fields are bits, shift, signed, insert, extract, flags.  */
+
+const struct powerpc_operand powerpc_operands[] =
+{
+  /* The zero index is used to indicate the end of the list of
+     operands.  */
+#define UNUSED (0)
+  { 0, 0, 0, 0, 0 },
+
+  /* The BA field in an XL form instruction.  */
+#define BA (1)
+#define BA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_CR },
+
+  /* The BA field in an XL form instruction when it must be the same
+     as the BT field in the same instruction.  */
+#define BAT (2)
+  { 5, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE },
+
+  /* The BB field in an XL form instruction.  */
+#define BB (3)
+#define BB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_CR },
+
+  /* The BB field in an XL form instruction when it must be the same
+     as the BA field in the same instruction.  */
+#define BBA (4)
+  { 5, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE },
+
+  /* The BD field in a B form instruction.  The lower two bits are
+     forced to zero.  */
+#define BD (5)
+  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when absolute addressing is
+     used.  */
+#define BDA (6)
+  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDM (7)
+  { 16, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used
+     and absolute address is used.  */
+#define BDMA (8)
+  { 16, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDP (9)
+  { 16, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used
+     and absolute addressing is used.  */
+#define BDPA (10)
+  { 16, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BF field in an X or XL form instruction.  */
+#define BF (11)
+  { 3, 23, 0, 0, PPC_OPERAND_CR },
+
+  /* An optional BF field.  This is used for comparison instructions,
+     in which an omitted BF field is taken as zero.  */
+#define OBF (12)
+  { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The BFA field in an X or XL form instruction.  */
+#define BFA (13)
+  { 3, 18, 0, 0, PPC_OPERAND_CR },
+
+  /* The BI field in a B form or XL form instruction.  */
+#define BI (14)
+#define BI_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_CR },
+
+  /* The BO field in a B form instruction.  Certain values are
+     illegal.  */
+#define BO (15)
+#define BO_MASK (0x1f << 21)
+  { 5, 21, insert_bo, extract_bo, 0 },
+
+  /* The BO field in a B form instruction when the + or - modifier is
+     used.  This is like the BO field, but it must be even.  */
+#define BOE (16)
+  { 5, 21, insert_boe, extract_boe, 0 },
+
+  /* The BT field in an X or XL form instruction.  */
+#define BT (17)
+  { 5, 21, 0, 0, PPC_OPERAND_CR },
+
+  /* The condition register number portion of the BI field in a B form
+     or XL form instruction.  This is used for the extended
+     conditional branch mnemonics, which set the lower two bits of the
+     BI field.  This field is optional.  */
+#define CR (18)
+  { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The D field in a D form instruction.  This is a displacement off
+     a register, and implies that the next operand is a register in
+     parentheses.  */
+#define D (19)
+  { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DS field in a DS form instruction.  This is like D, but the
+     lower two bits are forced to zero.  */
+#define DS (20)
+  { 16, 0, insert_ds, extract_ds, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The FL1 field in a POWER SC form instruction.  */
+#define FL1 (21)
+  { 4, 12, 0, 0, 0 },
+
+  /* The FL2 field in a POWER SC form instruction.  */
+#define FL2 (22)
+  { 3, 2, 0, 0, 0 },
+
+  /* The FLM field in an XFL form instruction.  */
+#define FLM (23)
+  { 8, 17, 0, 0, 0 },
+
+  /* The FRA field in an X or A form instruction.  */
+#define FRA (24)
+#define FRA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRB field in an X or A form instruction.  */
+#define FRB (25)
+#define FRB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRC field in an A form instruction.  */
+#define FRC (26)
+#define FRC_MASK (0x1f << 6)
+  { 5, 6, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRS field in an X form instruction or the FRT field in a D, X
+     or A form instruction.  */
+#define FRS (27)
+#define FRT (FRS)
+  { 5, 21, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FXM field in an XFX instruction.  */
+#define FXM (28)
+#define FXM_MASK (0xff << 12)
+  { 8, 12, 0, 0, 0 },
+
+  /* The L field in a D or X form instruction.  */
+#define L (29)
+  { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+
+  /* The LEV field in a POWER SC form instruction.  */
+#define LEV (30)
+  { 7, 5, 0, 0, 0 },
+
+  /* The LI field in an I form instruction.  The lower two bits are
+     forced to zero.  */
+#define LI (31)
+  { 26, 0, insert_li, extract_li, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The LI field in an I form instruction when used as an absolute
+     address.  */
+#define LIA (32)
+  { 26, 0, insert_li, extract_li, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The MB field in an M form instruction.  */
+#define MB (33)
+#define MB_MASK (0x1f << 6)
+  { 5, 6, 0, 0, 0 },
+
+  /* The ME field in an M form instruction.  */
+#define ME (34)
+#define ME_MASK (0x1f << 1)
+  { 5, 1, 0, 0, 0 },
+
+  /* The MB and ME fields in an M form instruction expressed a single
+     operand which is a bitmask indicating which bits to select.  This
+     is a two operand form using PPC_OPERAND_NEXT.  See the
+     description in opcode/ppc.h for what this means.  */
+#define MBE (35)
+  { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+  { 32, 0, insert_mbe, extract_mbe, 0 },
+
+  /* The MB or ME field in an MD or MDS form instruction.  The high
+     bit is wrapped to the low end.  */
+#define MB6 (37)
+#define ME6 (MB6)
+#define MB6_MASK (0x3f << 5)
+  { 6, 5, insert_mb6, extract_mb6, 0 },
+
+  /* The NB field in an X form instruction.  The value 32 is stored as
+     0.  */
+#define NB (38)
+  { 6, 11, insert_nb, extract_nb, 0 },
+
+  /* The NSI field in a D form instruction.  This is the same as the
+     SI field, only negated.  */
+#define NSI (39)
+  { 16, 0, insert_nsi, extract_nsi,
+      PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
+
+  /* The RA field in an D, DS, X, XO, M, or MDS form instruction.  */
+#define RA (40)
+#define RA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in a D or X form instruction which is an updating
+     load, which means that the RA field may not be zero and may not
+     equal the RT field.  */
+#define RAL (41)
+  { 5, 16, insert_ral, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in an lmw instruction, which has special value
+     restrictions.  */
+#define RAM (42)
+  { 5, 16, insert_ram, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in a D or X form instruction which is an updating
+     store or an updating floating point load, which means that the RA
+     field may not be zero.  */
+#define RAS (43)
+  { 5, 16, insert_ras, 0, PPC_OPERAND_GPR },
+
+  /* The RB field in an X, XO, M, or MDS form instruction.  */
+#define RB (44)
+#define RB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_GPR },
+
+  /* The RB field in an X form instruction when it must be the same as
+     the RS field in the instruction.  This is used for extended
+     mnemonics like mr.  */
+#define RBS (45)
+  { 5, 1, insert_rbs, extract_rbs, PPC_OPERAND_FAKE },
+
+  /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
+     instruction or the RT field in a D, DS, X, XFX or XO form
+     instruction.  */
+#define RS (46)
+#define RT (RS)
+#define RT_MASK (0x1f << 21)
+  { 5, 21, 0, 0, PPC_OPERAND_GPR },
+
+  /* The SH field in an X or M form instruction.  */
+#define SH (47)
+#define SH_MASK (0x1f << 11)
+  { 5, 11, 0, 0, 0 },
+
+  /* The SH field in an MD form instruction.  This is split.  */
+#define SH6 (48)
+#define SH6_MASK ((0x1f << 11) | (1 << 1))
+  { 6, 1, insert_sh6, extract_sh6, 0 },
+
+  /* The SI field in a D form instruction.  */
+#define SI (49)
+  { 16, 0, 0, 0, PPC_OPERAND_SIGNED },
+
+  /* The SI field in a D form instruction when we accept a wide range
+     of positive values.  */
+#define SISIGNOPT (50)
+  { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
+
+  /* The SPR field in an XFX form instruction.  This is flipped--the
+     lower 5 bits are stored in the upper 5 and vice- versa.  */
+#define SPR (51)
+#define SPR_MASK (0x3ff << 11)
+  { 10, 11, insert_spr, extract_spr, 0 },
+
+  /* The BAT index number in an XFX form m[ft]ibat[lu] instruction.  */
+#define SPRBAT (52)
+#define SPRBAT_MASK (0x3 << 17)
+  { 2, 17, 0, 0, 0 },
+
+  /* The SPRG register number in an XFX form m[ft]sprg instruction.  */
+#define SPRG (53)
+#define SPRG_MASK (0x3 << 16)
+  { 2, 16, 0, 0, 0 },
+
+  /* The SR field in an X form instruction.  */
+#define SR (54)
+  { 4, 16, 0, 0, 0 },
+
+  /* The SV field in a POWER SC form instruction.  */
+#define SV (55)
+  { 14, 2, 0, 0, 0 },
+
+  /* The TBR field in an XFX form instruction.  This is like the SPR
+     field, but it is optional.  */
+#define TBR (56)
+  { 10, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL },
+
+  /* The TO field in a D or X form instruction.  */
+#define TO (57)
+#define TO_MASK (0x1f << 21)
+  { 5, 21, 0, 0, 0 },
+
+  /* The U field in an X form instruction.  */
+#define U (58)
+  { 4, 12, 0, 0, 0 },
+
+  /* The UI field in a D form instruction.  */
+#define UI (59)
+  { 16, 0, 0, 0, 0 },
+};
+
+/* The functions used to insert and extract complicated operands.  */
+
+/* The BA field in an XL form instruction when it must be the same as
+   the BT field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BT field into the BA field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+/*ARGSUSED*/
+static unsigned long 
+insert_bat (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (((insn >> 21) & 0x1f) << 16);
+}
+
+static long
+extract_bat (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BB field in an XL form instruction when it must be the same as
+   the BA field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BA field into the BB field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bba (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (((insn >> 16) & 0x1f) << 11);
+}
+
+static long
+extract_bba (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BD field in a B form instruction.  The lower two bits are
+   forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bd (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (value & 0xfffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_bd (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The BD field in a B form instruction when the - modifier is used.
+   This modifier means that the branch is not expected to be taken.
+   We must set the y bit of the BO field to 1 if the offset is
+   negative.  When extracting, we require that the y bit be 1 and that
+   the offset be positive, since if the y bit is 0 we just want to
+   print the normal form of the instruction.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bdm (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if ((value & 0x8000) != 0)
+    insn |= 1 << 21;
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdm (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn & (1 << 21)) == 0
+	  || (insn & (1 << 15)) == 0))
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The BD field in a B form instruction when the + modifier is used.
+   This is like BDM, above, except that the branch is expected to be
+   taken.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bdp (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if ((value & 0x8000) == 0)
+    insn |= 1 << 21;
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdp (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn & (1 << 21)) == 0
+	  || (insn & (1 << 15)) != 0))
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* Check for legal values of a BO field.  */
+
+static int
+valid_bo (long value)
+{
+  /* Certain encodings have bits that are required to be zero.  These
+     are (z must be zero, y may be anything):
+         001zy
+	 011zy
+	 1z00y
+	 1z01y
+	 1z1zz
+     */
+  switch (value & 0x14)
+    {
+    default:
+    case 0:
+      return 1;
+    case 0x4:
+      return (value & 0x2) == 0;
+    case 0x10:
+      return (value & 0x8) == 0;
+    case 0x14:
+      return value == 0x14;
+    }
+}
+
+/* The BO field in a B form instruction.  Warn about attempts to set
+   the field to an illegal value.  */
+
+static unsigned long
+insert_bo (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (errmsg != (const char **) NULL
+      && ! valid_bo (value))
+    *errmsg = "invalid conditional option";
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_bo (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (invalid != (int *) NULL
+      && ! valid_bo (value))
+    *invalid = 1;
+  return value;
+}
+
+/* The BO field in a B form instruction when the + or - modifier is
+   used.  This is like the BO field, but it must be even.  When
+   extracting it, we force it to be even.  */
+
+static unsigned long
+insert_boe (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (errmsg != (const char **) NULL)
+    {
+      if (! valid_bo (value))
+	*errmsg = "invalid conditional option";
+      else if ((value & 1) != 0)
+	*errmsg = "attempt to set y bit when using + or - modifier";
+    }
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_boe (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (invalid != (int *) NULL
+      && ! valid_bo (value))
+    *invalid = 1;
+  return value & 0x1e;
+}
+
+/* The DS field in a DS form instruction.  This is like D, but the
+   lower two bits are forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_ds (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (value & 0xfffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_ds (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The LI field in an I form instruction.  The lower two bits are
+   forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_li (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (value & 0x3fffffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_li (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if ((insn & 0x2000000) != 0)
+    return (insn & 0x3fffffc) - 0x4000000;
+  else
+    return insn & 0x3fffffc;
+}
+
+/* The MB and ME fields in an M form instruction expressed as a single
+   operand which is itself a bitmask.  The extraction function always
+   marks it as invalid, since we never want to recognize an
+   instruction which uses a field of this type.  */
+
+static unsigned long
+insert_mbe (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  unsigned long uval;
+  int mb, me;
+
+  uval = value;
+
+  if (uval == 0)
+    {
+      if (errmsg != (const char **) NULL)
+	*errmsg = "illegal bitmask";
+      return insn;
+    }
+
+  me = 31;
+  while ((uval & 1) == 0)
+    {
+      uval >>= 1;
+      --me;
+    }
+
+  mb = me;
+  uval >>= 1;
+  while ((uval & 1) != 0)
+    {
+      uval >>= 1;
+      --mb;
+    }
+
+  if (uval != 0)
+    {
+      if (errmsg != (const char **) NULL)
+	*errmsg = "illegal bitmask";
+    }
+
+  return insn | (mb << 6) | (me << 1);
+}
+
+static long
+extract_mbe (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+  int mb, me;
+  int i;
+
+  if (invalid != (int *) NULL)
+    *invalid = 1;
+
+  ret = 0;
+  mb = (insn >> 6) & 0x1f;
+  me = (insn >> 1) & 0x1f;
+  for (i = mb; i < me; i++)
+    ret |= 1 << (31 - i);
+  return ret;
+}
+
+/* The MB or ME field in an MD or MDS form instruction.  The high bit
+   is wrapped to the low end.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_mb6 (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((value & 0x1f) << 6) | (value & 0x20);
+}
+
+/*ARGSUSED*/
+static long
+extract_mb6 (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  return ((insn >> 6) & 0x1f) | (insn & 0x20);
+}
+
+/* The NB field in an X form instruction.  The value 32 is stored as
+   0.  */
+
+static unsigned long
+insert_nb (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value < 0 || value > 32)
+    *errmsg = "value out of range";
+  if (value == 32)
+    value = 0;
+  return insn | ((value & 0x1f) << 11);
+}
+
+/*ARGSUSED*/
+static long
+extract_nb (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+
+  ret = (insn >> 11) & 0x1f;
+  if (ret == 0)
+    ret = 32;
+  return ret;
+}
+
+/* The NSI field in a D form instruction.  This is the same as the SI
+   field, only negated.  The extraction function always marks it as
+   invalid, since we never want to recognize an instruction which uses
+   a field of this type.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_nsi (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((- value) & 0xffff);
+}
+
+static long
+extract_nsi (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL)
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return - ((insn & 0xffff) - 0x10000);
+  else
+    return - (insn & 0xffff);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   load, which means that the RA field may not be zero and may not
+   equal the RT field.  */
+
+static unsigned long
+insert_ral (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0
+      || value == ((insn >> 21) & 0x1f))
+    *errmsg = "invalid register operand when updating";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in an lmw instruction, which has special value
+   restrictions.  */
+
+static unsigned long
+insert_ram (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value >= ((insn >> 21) & 0x1f))
+    *errmsg = "index register in load range";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   store or an updating floating point load, which means that the RA
+   field may not be zero.  */
+
+static unsigned long
+insert_ras (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0)
+    *errmsg = "invalid register operand when updating";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RB field in an X form instruction when it must be the same as
+   the RS field in the instruction.  This is used for extended
+   mnemonics like mr.  This operand is marked FAKE.  The insertion
+   function just copies the BT field into the BA field, and the
+   extraction function just checks that the fields are the same.  */
+
+/*ARGSUSED*/
+static unsigned long 
+insert_rbs (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (((insn >> 21) & 0x1f) << 11);
+}
+
+static long
+extract_rbs (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The SH field in an MD form instruction.  This is split.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_sh6 (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
+}
+
+/*ARGSUSED*/
+static long
+extract_sh6 (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
+}
+
+/* The SPR field in an XFX form instruction.  This is flipped--the
+   lower 5 bits are stored in the upper 5 and vice- versa.  */
+
+static unsigned long
+insert_spr (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_spr (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+}
+
+/* The TBR field in an XFX instruction.  This is just like SPR, but it
+   is optional.  When TBR is omitted, it must be inserted as 268 (the
+   magic number of the TB register).  These functions treat 0
+   (indicating an omitted optional operand) as 268.  This means that
+   ``mftb 4,0'' is not handled correctly.  This does not matter very
+   much, since the architecture manual does not define mftb as
+   accepting any values other than 268 or 269.  */
+
+#define TB (268)
+
+static unsigned long
+insert_tbr (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0)
+    value = TB;
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_tbr (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+
+  ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+  if (ret == TB)
+    ret = 0;
+  return ret;
+}
+
+/* Macros used to form opcodes.  */
+
+/* The main opcode.  */
+#define OP(x) (((x) & 0x3f) << 26)
+#define OP_MASK OP (0x3f)
+
+/* The main opcode combined with a trap code in the TO field of a D
+   form instruction.  Used for extended mnemonics for the trap
+   instructions.  */
+#define OPTO(x,to) (OP (x) | (((to) & 0x1f) << 21))
+#define OPTO_MASK (OP_MASK | TO_MASK)
+
+/* The main opcode combined with a comparison size bit in the L field
+   of a D form or X form instruction.  Used for extended mnemonics for
+   the comparison instructions.  */
+#define OPL(x,l) (OP (x) | (((l) & 1) << 21))
+#define OPL_MASK OPL (0x3f,1)
+
+/* An A form instruction.  */
+#define A(op, xop, rc) (OP (op) | (((xop) & 0x1f) << 1) | ((rc) & 1))
+#define A_MASK A (0x3f, 0x1f, 1)
+
+/* An A_MASK with the FRB field fixed.  */
+#define AFRB_MASK (A_MASK | FRB_MASK)
+
+/* An A_MASK with the FRC field fixed.  */
+#define AFRC_MASK (A_MASK | FRC_MASK)
+
+/* An A_MASK with the FRA and FRC fields fixed.  */
+#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
+
+/* A B form instruction.  */
+#define B(op, aa, lk) (OP (op) | (((aa) & 1) << 1) | ((lk) & 1))
+#define B_MASK B (0x3f, 1, 1)
+
+/* A B form instruction setting the BO field.  */
+#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | (((bo) & 0x1f) << 21))
+#define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
+
+/* A BBO_MASK with the y bit of the BO field removed.  This permits
+   matching a conditional branch regardless of the setting of the y
+   bit.  */
+#define Y_MASK (1 << 21)
+#define BBOY_MASK (BBO_MASK &~ Y_MASK)
+
+/* A B form instruction setting the BO field and the condition bits of
+   the BI field.  */
+#define BBOCB(op, bo, cb, aa, lk) \
+  (BBO ((op), (bo), (aa), (lk)) | (((cb) & 0x3) << 16))
+#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
+
+/* A BBOCB_MASK with the y bit of the BO field removed.  */
+#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
+
+/* A BBOYCB_MASK in which the BI field is fixed.  */
+#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
+
+/* The main opcode mask with the RA field clear.  */
+#define DRA_MASK (OP_MASK | RA_MASK)
+
+/* A DS form instruction.  */
+#define DSO(op, xop) (OP (op) | ((xop) & 0x3))
+#define DS_MASK DSO (0x3f, 3)
+
+/* An M form instruction.  */
+#define M(op, rc) (OP (op) | ((rc) & 1))
+#define M_MASK M (0x3f, 1)
+
+/* An M form instruction with the ME field specified.  */
+#define MME(op, me, rc) (M ((op), (rc)) | (((me) & 0x1f) << 1))
+
+/* An M_MASK with the MB and ME fields fixed.  */
+#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
+
+/* An M_MASK with the SH and ME fields fixed.  */
+#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
+
+/* An MD form instruction.  */
+#define MD(op, xop, rc) (OP (op) | (((xop) & 0x7) << 2) | ((rc) & 1))
+#define MD_MASK MD (0x3f, 0x7, 1)
+
+/* An MD_MASK with the MB field fixed.  */
+#define MDMB_MASK (MD_MASK | MB6_MASK)
+
+/* An MD_MASK with the SH field fixed.  */
+#define MDSH_MASK (MD_MASK | SH6_MASK)
+
+/* An MDS form instruction.  */
+#define MDS(op, xop, rc) (OP (op) | (((xop) & 0xf) << 1) | ((rc) & 1))
+#define MDS_MASK MDS (0x3f, 0xf, 1)
+
+/* An MDS_MASK with the MB field fixed.  */
+#define MDSMB_MASK (MDS_MASK | MB6_MASK)
+
+/* An SC form instruction.  */
+#define SC(op, sa, lk) (OP (op) | (((sa) & 1) << 1) | ((lk) & 1))
+#define SC_MASK (OP_MASK | (0x3ff << 16) | (1 << 1) | 1)
+
+/* An X form instruction.  */
+#define X(op, xop) (OP (op) | (((xop) & 0x3ff) << 1))
+
+/* An X form instruction with the RC bit specified.  */
+#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
+
+/* The mask for an X form instruction.  */
+#define X_MASK XRC (0x3f, 0x3ff, 1)
+
+/* An X_MASK with the RA field fixed.  */
+#define XRA_MASK (X_MASK | RA_MASK)
+
+/* An X_MASK with the RB field fixed.  */
+#define XRB_MASK (X_MASK | RB_MASK)
+
+/* An X_MASK with the RT field fixed.  */
+#define XRT_MASK (X_MASK | RT_MASK)
+
+/* An X_MASK with the RA and RB fields fixed.  */
+#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
+
+/* An X_MASK with the RT and RA fields fixed.  */
+#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
+
+/* An X form comparison instruction.  */
+#define XCMPL(op, xop, l) (X ((op), (xop)) | (((l) & 1) << 21))
+
+/* The mask for an X form comparison instruction.  */
+#define XCMP_MASK (X_MASK | (1 << 22))
+
+/* The mask for an X form comparison instruction with the L field
+   fixed.  */
+#define XCMPL_MASK (XCMP_MASK | (1 << 21))
+
+/* An X form trap instruction with the TO field specified.  */
+#define XTO(op, xop, to) (X ((op), (xop)) | (((to) & 0x1f) << 21))
+#define XTO_MASK (X_MASK | TO_MASK)
+
+/* An XFL form instruction.  */
+#define XFL(op, xop, rc) (OP (op) | (((xop) & 0x3ff) << 1) | ((rc) & 1))
+#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (1 << 25) | (1 << 16))
+
+/* An XL form instruction with the LK field set to 0.  */
+#define XL(op, xop) (OP (op) | (((xop) & 0x3ff) << 1))
+
+/* An XL form instruction which uses the LK field.  */
+#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
+
+/* The mask for an XL form instruction.  */
+#define XL_MASK XLLK (0x3f, 0x3ff, 1)
+
+/* An XL form instruction which explicitly sets the BO field.  */
+#define XLO(op, bo, xop, lk) \
+  (XLLK ((op), (xop), (lk)) | (((bo) & 0x1f) << 21))
+#define XLO_MASK (XL_MASK | BO_MASK)
+
+/* An XL form instruction which explicitly sets the y bit of the BO
+   field.  */
+#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | (((y) & 1) << 21))
+#define XLYLK_MASK (XL_MASK | Y_MASK)
+
+/* An XL form instruction which sets the BO field and the condition
+   bits of the BI field.  */
+#define XLOCB(op, bo, cb, xop, lk) \
+  (XLO ((op), (bo), (xop), (lk)) | (((cb) & 3) << 16))
+#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
+
+/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed.  */
+#define XLBB_MASK (XL_MASK | BB_MASK)
+#define XLYBB_MASK (XLYLK_MASK | BB_MASK)
+#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
+
+/* An XL_MASK with the BO and BB fields fixed.  */
+#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
+
+/* An XL_MASK with the BO, BI and BB fields fixed.  */
+#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK)
+
+/* An XO form instruction.  */
+#define XO(op, xop, oe, rc) \
+  (OP (op) | (((xop) & 0x1ff) << 1) | (((oe) & 1) << 10) | ((rc) & 1))
+#define XO_MASK XO (0x3f, 0x1ff, 1, 1)
+
+/* An XO_MASK with the RB field fixed.  */
+#define XORB_MASK (XO_MASK | RB_MASK)
+
+/* An XS form instruction.  */
+#define XS(op, xop, rc) (OP (op) | (((xop) & 0x1ff) << 2) | ((rc) & 1))
+#define XS_MASK XS (0x3f, 0x1ff, 1)
+
+/* A mask for the FXM version of an XFX form instruction.  */
+#define XFXFXM_MASK (X_MASK | (1 << 20) | (1 << 11))
+
+/* An XFX form instruction with the FXM field filled in.  */
+#define XFXM(op, xop, fxm) \
+  (X ((op), (xop)) | (((fxm) & 0xff) << 12))
+
+/* An XFX form instruction with the SPR field filled in.  */
+#define XSPR(op, xop, spr) \
+  (X ((op), (xop)) | (((spr) & 0x1f) << 16) | (((spr) & 0x3e0) << 6))
+#define XSPR_MASK (X_MASK | SPR_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRBAT field.  */
+#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRG field.  */
+#define XSPRG_MASK (XSPR_MASK &~ SPRG_MASK)
+
+/* The BO encodings used in extended conditional branch mnemonics.  */
+#define BODNZF	(0x0)
+#define BODNZFP	(0x1)
+#define BODZF	(0x2)
+#define BODZFP	(0x3)
+#define BOF	(0x4)
+#define BOFP	(0x5)
+#define BODNZT	(0x8)
+#define BODNZTP	(0x9)
+#define BODZT	(0xa)
+#define BODZTP	(0xb)
+#define BOT	(0xc)
+#define BOTP	(0xd)
+#define BODNZ	(0x10)
+#define BODNZP	(0x11)
+#define BODZ	(0x12)
+#define BODZP	(0x13)
+#define BOU	(0x14)
+
+/* The BI condition bit encodings used in extended conditional branch
+   mnemonics.  */
+#define CBLT	(0)
+#define CBGT	(1)
+#define CBEQ	(2)
+#define CBSO	(3)
+
+/* The TO encodings used in extended trap mnemonics.  */
+#define TOLGT	(0x1)
+#define TOLLT	(0x2)
+#define TOEQ	(0x4)
+#define TOLGE	(0x5)
+#define TOLNL	(0x5)
+#define TOLLE	(0x6)
+#define TOLNG	(0x6)
+#define TOGT	(0x8)
+#define TOGE	(0xc)
+#define TONL	(0xc)
+#define TOLT	(0x10)
+#define TOLE	(0x14)
+#define TONG	(0x14)
+#define TONE	(0x18)
+#define TOU	(0x1f)
+
+/* Smaller names for the flags so each entry in the opcodes table will
+   fit on a single line.  */
+#undef PPC
+#define PPC PPC_OPCODE_PPC
+#define POWER PPC_OPCODE_POWER
+#define POWER2 PPC_OPCODE_POWER2
+#define B32 PPC_OPCODE_32
+#define B64 PPC_OPCODE_64
+#define M601 PPC_OPCODE_601
+
+/* The opcode table.
+
+   The format of the opcode table is:
+
+   NAME	     OPCODE	MASK		FLAGS		{ OPERANDS }
+
+   NAME is the name of the instruction.
+   OPCODE is the instruction opcode.
+   MASK is the opcode mask; this is used to tell the disassembler
+     which bits in the actual opcode must match OPCODE.
+   FLAGS are flags indicated what processors support the instruction.
+   OPERANDS is the list of operands.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches, so this table is sorted to put more
+   specific instructions before more general instructions.  It is also
+   sorted by major opcode.  */
+
+const struct powerpc_opcode powerpc_opcodes[] = {
+{ "tdlgti",  OPTO(2,TOLGT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdllti",  OPTO(2,TOLLT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdlgei",  OPTO(2,TOLGE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdlnli",  OPTO(2,TOLNL), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdllei",  OPTO(2,TOLLE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdlngi",  OPTO(2,TOLNG), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdgti",   OPTO(2,TOGT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdgei",   OPTO(2,TOGE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdnli",   OPTO(2,TONL), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdlti",   OPTO(2,TOLT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdlei",   OPTO(2,TOLE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdngi",   OPTO(2,TONG), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdnei",   OPTO(2,TONE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
+{ "tdi",     OP(2),	OP_MASK,	PPC|B64,	{ TO, RA, SI } },
+
+{ "twlgti",  OPTO(3,TOLGT), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tlgti",   OPTO(3,TOLGT), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twllti",  OPTO(3,TOLLT), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tllti",   OPTO(3,TOLLT), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "tweqi",   OPTO(3,TOEQ), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "teqi",    OPTO(3,TOEQ), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twlgei",  OPTO(3,TOLGE), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tlgei",   OPTO(3,TOLGE), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twlnli",  OPTO(3,TOLNL), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tlnli",   OPTO(3,TOLNL), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twllei",  OPTO(3,TOLLE), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tllei",   OPTO(3,TOLLE), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twlngi",  OPTO(3,TOLNG), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tlngi",   OPTO(3,TOLNG), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twgti",   OPTO(3,TOGT), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tgti",    OPTO(3,TOGT), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twgei",   OPTO(3,TOGE), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tgei",    OPTO(3,TOGE), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twnli",   OPTO(3,TONL), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tnli",    OPTO(3,TONL), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twlti",   OPTO(3,TOLT), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tlti",    OPTO(3,TOLT), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twlei",   OPTO(3,TOLE), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tlei",    OPTO(3,TOLE), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twngi",   OPTO(3,TONG), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tngi",    OPTO(3,TONG), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twnei",   OPTO(3,TONE), OPTO_MASK,	PPC,		{ RA, SI } },
+{ "tnei",    OPTO(3,TONE), OPTO_MASK,	POWER,		{ RA, SI } },
+{ "twi",     OP(3),	OP_MASK,	PPC,		{ TO, RA, SI } },
+{ "ti",      OP(3),	OP_MASK,	POWER,		{ TO, RA, SI } },
+
+{ "mulli",   OP(7),	OP_MASK,	PPC,		{ RT, RA, SI } },
+{ "muli",    OP(7),	OP_MASK,	POWER,		{ RT, RA, SI } },
+
+{ "subfic",  OP(8),	OP_MASK,	PPC,		{ RT, RA, SI } },
+{ "sfi",     OP(8),	OP_MASK,	POWER,		{ RT, RA, SI } },
+
+{ "dozi",    OP(9),	OP_MASK,	POWER|M601,	{ RT, RA, SI } },
+
+{ "cmplwi",  OPL(10,0),	OPL_MASK,	PPC,		{ OBF, RA, UI } },
+{ "cmpldi",  OPL(10,1), OPL_MASK,	PPC|B64,	{ OBF, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	PPC,		{ BF, L, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	POWER,		{ BF, RA, UI } },
+
+{ "cmpwi",   OPL(11,0),	OPL_MASK,	PPC,		{ OBF, RA, SI } },
+{ "cmpdi",   OPL(11,1),	OPL_MASK,	PPC|B64,	{ OBF, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	PPC,		{ BF, L, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	POWER,		{ BF, RA, SI } },
+
+{ "addic",   OP(12),	OP_MASK,	PPC,		{ RT, RA, SI } },
+{ "ai",	     OP(12),	OP_MASK,	POWER,		{ RT, RA, SI } },
+{ "subic",   OP(12),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+
+{ "addic.",  OP(13),	OP_MASK,	PPC,		{ RT, RA, SI } },
+{ "ai.",     OP(13),	OP_MASK,	POWER,		{ RT, RA, SI } },
+{ "subic.",  OP(13),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+
+{ "li",	     OP(14),	DRA_MASK,	PPC,		{ RT, SI } },
+{ "lil",     OP(14),	DRA_MASK,	POWER,		{ RT, SI } },
+{ "addi",    OP(14),	OP_MASK,	PPC,		{ RT, RA, SI } },
+{ "cal",     OP(14),	OP_MASK,	POWER,		{ RT, D, RA } },
+{ "subi",    OP(14),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+{ "la",	     OP(14),	OP_MASK,	PPC,		{ RT, D, RA } },
+
+{ "lis",     OP(15),	DRA_MASK,	PPC,		{ RT, SISIGNOPT } },
+{ "liu",     OP(15),	DRA_MASK,	POWER,		{ RT, SISIGNOPT } },
+{ "addis",   OP(15),	OP_MASK,	PPC,		{ RT,RA,SISIGNOPT } },
+{ "cau",     OP(15),	OP_MASK,	POWER,		{ RT,RA,SISIGNOPT } },
+{ "subis",   OP(15),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+
+{ "bdnz-",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,	{ BDM } },
+{ "bdnz+",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,	{ BDP } },
+{ "bdnz",    BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,	{ BD } },
+{ "bdn",     BBO(16,BODNZ,0,0), BBOYBI_MASK, POWER,	{ BD } },
+{ "bdnzl-",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,	{ BDM } },
+{ "bdnzl+",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,	{ BDP } },
+{ "bdnzl",   BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,	{ BD } },
+{ "bdnl",    BBO(16,BODNZ,0,1), BBOYBI_MASK, POWER,	{ BD } },
+{ "bdnza-",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,	{ BDMA } },
+{ "bdnza+",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,	{ BDPA } },
+{ "bdnza",   BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,	{ BDA } },
+{ "bdna",    BBO(16,BODNZ,1,0), BBOYBI_MASK, POWER,	{ BDA } },
+{ "bdnzla-", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,	{ BDMA } },
+{ "bdnzla+", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,	{ BDPA } },
+{ "bdnzla",  BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,	{ BDA } },
+{ "bdnla",   BBO(16,BODNZ,1,1), BBOYBI_MASK, POWER,	{ BDA } },
+{ "bdz-",    BBO(16,BODZ,0,0), BBOYBI_MASK, PPC,	{ BDM } },
+{ "bdz+",    BBO(16,BODZ,0,0), BBOYBI_MASK, PPC,	{ BDP } },
+{ "bdz",     BBO(16,BODZ,0,0), BBOYBI_MASK, PPC|POWER,	{ BD } },
+{ "bdzl-",   BBO(16,BODZ,0,1), BBOYBI_MASK, PPC,	{ BDM } },
+{ "bdzl+",   BBO(16,BODZ,0,1), BBOYBI_MASK, PPC,	{ BDP } },
+{ "bdzl",    BBO(16,BODZ,0,1), BBOYBI_MASK, PPC|POWER,	{ BD } },
+{ "bdza-",   BBO(16,BODZ,1,0), BBOYBI_MASK, PPC,	{ BDMA } },
+{ "bdza+",   BBO(16,BODZ,1,0), BBOYBI_MASK, PPC,	{ BDPA } },
+{ "bdza",    BBO(16,BODZ,1,0), BBOYBI_MASK, PPC|POWER,	{ BDA } },
+{ "bdzla-",  BBO(16,BODZ,1,1), BBOYBI_MASK, PPC,	{ BDMA } },
+{ "bdzla+",  BBO(16,BODZ,1,1), BBOYBI_MASK, PPC,	{ BDPA } },
+{ "bdzla",   BBO(16,BODZ,1,1), BBOYBI_MASK, PPC|POWER,	{ BDA } },
+{ "blt-",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "blt+",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "blt",     BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bltl-",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bltl+",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bltl",    BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "blta-",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "blta+",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "blta",    BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bltla-",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bltla+",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bltla",   BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bgt-",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bgt+",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bgt",     BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgtl-",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bgtl+",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bgtl",    BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgta-",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bgta+",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bgta",    BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bgtla-",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bgtla+",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bgtla",   BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "beq-",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "beq+",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "beq",     BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "beql-",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "beql+",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "beql",    BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "beqa-",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "beqa+",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "beqa",    BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "beqla-",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "beqla+",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "beqla",   BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bso-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bso+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bso",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bsol-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bsol+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bsol",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bsoa-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bsoa+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bsoa",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bsola-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bsola+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bsola",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bun-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bun+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bun",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BD } },
+{ "bunl-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bunl+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bunl",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BD } },
+{ "buna-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "buna+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "buna",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDA } },
+{ "bunla-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bunla+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bunla",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDA } },
+{ "bge-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bge+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bge",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgel-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bgel+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bgel",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgea-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bgea+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bgea",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bgela-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bgela+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bgela",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnl-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bnl+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bnl",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnll-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bnll+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bnll",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnla-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnla+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnla",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnlla-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnlla+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnlla",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "ble-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "ble+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "ble",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "blel-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "blel+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "blel",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "blea-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "blea+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "blea",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "blela-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "blela+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "blela",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bng-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bng+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bng",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bngl-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bngl+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bngl",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnga-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnga+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnga",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bngla-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bngla+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bngla",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bne-",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bne+",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bne",     BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnel-",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bnel+",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bnel",    BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnea-",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnea+",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnea",    BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnela-",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnela+",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnela",   BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bns-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bns+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bns",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnsl-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bnsl+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bnsl",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnsa-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnsa+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnsa",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnsla-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnsla+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnsla",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnu-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bnu+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bnu",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BD } },
+{ "bnul-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
+{ "bnul+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
+{ "bnul",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BD } },
+{ "bnua-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnua+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnua",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDA } },
+{ "bnula-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
+{ "bnula+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
+{ "bnula",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDA } },
+{ "bdnzt-",  BBO(16,BODNZT,0,0), BBOY_MASK, PPC,	{ BI, BDM } },
+{ "bdnzt+",  BBO(16,BODNZT,0,0), BBOY_MASK, PPC,	{ BI, BDP } },
+{ "bdnzt",   BBO(16,BODNZT,0,0), BBOY_MASK, PPC,	{ BI, BD } },
+{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, PPC,	{ BI, BDM } },
+{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, PPC,	{ BI, BDP } },
+{ "bdnztl",  BBO(16,BODNZT,0,1), BBOY_MASK, PPC,	{ BI, BD } },
+{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, PPC,	{ BI, BDMA } },
+{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, PPC,	{ BI, BDPA } },
+{ "bdnzta",  BBO(16,BODNZT,1,0), BBOY_MASK, PPC,	{ BI, BDA } },
+{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, PPC,	{ BI, BDMA } },
+{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, PPC,	{ BI, BDPA } },
+{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPC,	{ BI, BDA } },
+{ "bdnzf-",  BBO(16,BODNZF,0,0), BBOY_MASK, PPC,	{ BI, BDM } },
+{ "bdnzf+",  BBO(16,BODNZF,0,0), BBOY_MASK, PPC,	{ BI, BDP } },
+{ "bdnzf",   BBO(16,BODNZF,0,0), BBOY_MASK, PPC,	{ BI, BD } },
+{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, PPC,	{ BI, BDM } },
+{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, PPC,	{ BI, BDP } },
+{ "bdnzfl",  BBO(16,BODNZF,0,1), BBOY_MASK, PPC,	{ BI, BD } },
+{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, PPC,	{ BI, BDMA } },
+{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, PPC,	{ BI, BDPA } },
+{ "bdnzfa",  BBO(16,BODNZF,1,0), BBOY_MASK, PPC,	{ BI, BDA } },
+{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, PPC,	{ BI, BDMA } },
+{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, PPC,	{ BI, BDPA } },
+{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPC,	{ BI, BDA } },
+{ "bt-",     BBO(16,BOT,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bt+",     BBO(16,BOT,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bt",	     BBO(16,BOT,0,0), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bbt",     BBO(16,BOT,0,0), BBOY_MASK, POWER,		{ BI, BD } },
+{ "btl-",    BBO(16,BOT,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "btl+",    BBO(16,BOT,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "btl",     BBO(16,BOT,0,1), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bbtl",    BBO(16,BOT,0,1), BBOY_MASK, POWER,		{ BI, BD } },
+{ "bta-",    BBO(16,BOT,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bta+",    BBO(16,BOT,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bta",     BBO(16,BOT,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bbta",    BBO(16,BOT,1,0), BBOY_MASK, POWER,		{ BI, BDA } },
+{ "btla-",   BBO(16,BOT,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "btla+",   BBO(16,BOT,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "btla",    BBO(16,BOT,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bbtla",   BBO(16,BOT,1,1), BBOY_MASK, POWER,		{ BI, BDA } },
+{ "bf-",     BBO(16,BOF,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bf+",     BBO(16,BOF,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bf",	     BBO(16,BOF,0,0), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bbf",     BBO(16,BOF,0,0), BBOY_MASK, POWER,		{ BI, BD } },
+{ "bfl-",    BBO(16,BOF,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bfl+",    BBO(16,BOF,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bfl",     BBO(16,BOF,0,1), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bbfl",    BBO(16,BOF,0,1), BBOY_MASK, POWER,		{ BI, BD } },
+{ "bfa-",    BBO(16,BOF,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bfa+",    BBO(16,BOF,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bfa",     BBO(16,BOF,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bbfa",    BBO(16,BOF,1,0), BBOY_MASK, POWER,		{ BI, BDA } },
+{ "bfla-",   BBO(16,BOF,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bfla+",   BBO(16,BOF,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bfla",    BBO(16,BOF,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bbfla",   BBO(16,BOF,1,1), BBOY_MASK, POWER,		{ BI, BDA } },
+{ "bdzt-",   BBO(16,BODZT,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bdzt+",   BBO(16,BODZT,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bdzt",    BBO(16,BODZT,0,0), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bdztl-",  BBO(16,BODZT,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bdztl+",  BBO(16,BODZT,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bdztl",   BBO(16,BODZT,0,1), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bdzta-",  BBO(16,BODZT,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bdzta+",  BBO(16,BODZT,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bdzta",   BBO(16,BODZT,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bdztla",  BBO(16,BODZT,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bdzf-",   BBO(16,BODZF,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bdzf+",   BBO(16,BODZF,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bdzf",    BBO(16,BODZF,0,0), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bdzfl-",  BBO(16,BODZF,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
+{ "bdzfl+",  BBO(16,BODZF,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
+{ "bdzfl",   BBO(16,BODZF,0,1), BBOY_MASK, PPC,		{ BI, BD } },
+{ "bdzfa-",  BBO(16,BODZF,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bdzfa+",  BBO(16,BODZF,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bdzfa",   BBO(16,BODZF,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
+{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
+{ "bdzfla",  BBO(16,BODZF,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
+{ "bc-",     B(16,0,0),	B_MASK,		PPC,		{ BOE, BI, BDM } },
+{ "bc+",     B(16,0,0),	B_MASK,		PPC,		{ BOE, BI, BDP } },
+{ "bc",	     B(16,0,0),	B_MASK,		PPC|POWER,	{ BO, BI, BD } },
+{ "bcl-",    B(16,0,1),	B_MASK,		PPC,		{ BOE, BI, BDM } },
+{ "bcl+",    B(16,0,1),	B_MASK,		PPC,		{ BOE, BI, BDP } },
+{ "bcl",     B(16,0,1),	B_MASK,		PPC|POWER,	{ BO, BI, BD } },
+{ "bca-",    B(16,1,0),	B_MASK,		PPC,		{ BOE, BI, BDMA } },
+{ "bca+",    B(16,1,0),	B_MASK,		PPC,		{ BOE, BI, BDPA } },
+{ "bca",     B(16,1,0),	B_MASK,		PPC|POWER,	{ BO, BI, BDA } },
+{ "bcla-",   B(16,1,1),	B_MASK,		PPC,		{ BOE, BI, BDMA } },
+{ "bcla+",   B(16,1,1),	B_MASK,		PPC,		{ BOE, BI, BDPA } },
+{ "bcla",    B(16,1,1),	B_MASK,		PPC|POWER,	{ BO, BI, BDA } },
+
+{ "sc",      SC(17,1,0), 0xffffffff,	PPC,		{ 0 } },
+{ "svc",     SC(17,0,0), SC_MASK,	POWER,		{ LEV, FL1, FL2 } },
+{ "svcl",    SC(17,0,1), SC_MASK,	POWER,		{ LEV, FL1, FL2 } },
+{ "svca",    SC(17,1,0), SC_MASK,	POWER,		{ SV } },
+{ "svcla",   SC(17,1,1), SC_MASK,	POWER,		{ SV } },
+
+{ "b",	     B(18,0,0),	B_MASK,		PPC|POWER,	{ LI } },
+{ "bl",      B(18,0,1),	B_MASK,		PPC|POWER,	{ LI } },
+{ "ba",      B(18,1,0),	B_MASK,		PPC|POWER,	{ LIA } },
+{ "bla",     B(18,1,1),	B_MASK,		PPC|POWER,	{ LIA } },
+
+{ "mcrf",    XL(19,0),	XLBB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } },
+
+{ "blr",     XLO(19,BOU,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "br",      XLO(19,BOU,16,0), XLBOBIBB_MASK, POWER,	{ 0 } },
+{ "blrl",    XLO(19,BOU,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "brl",     XLO(19,BOU,16,1), XLBOBIBB_MASK, POWER,	{ 0 } },
+{ "bdnzlr",  XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdzlr",   XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdzlr-",  XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdzlr+",  XLO(19,BODZP,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdzlrl",  XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
+{ "bltlr",   XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlr-",  XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltr",    XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bltlrl",  XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltrl",   XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bgtlr",   XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlr-",  XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtr",    XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bgtlrl",  XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtrl",   XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "beqlr",   XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlr-",  XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqr",    XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "beqlrl",  XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqrl",   XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bsolr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsor",    XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bsolrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsorl",   XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bunlr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bger",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bgelrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgerl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnllr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlr",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnllrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlrl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "blelr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bler",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "blelrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blerl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnglr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngr",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnglrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngrl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnelr",   XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelr-",  XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bner",    XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnelrl",  XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnerl",   XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnslr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsr",    XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnslrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsrl",   XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnulr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "btlr",    XLO(19,BOT,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "btlr-",   XLO(19,BOT,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "btlr+",   XLO(19,BOTP,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bbtr",    XLO(19,BOT,16,0), XLBOBB_MASK, POWER,	{ BI } },
+{ "btlrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "btlrl-",  XLO(19,BOT,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "btlrl+",  XLO(19,BOTP,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bbtrl",   XLO(19,BOT,16,1), XLBOBB_MASK, POWER,	{ BI } },
+{ "bflr",    XLO(19,BOF,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bflr-",   XLO(19,BOF,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bflr+",   XLO(19,BOFP,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bbfr",    XLO(19,BOF,16,0), XLBOBB_MASK, POWER,	{ BI } },
+{ "bflrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bflrl-",  XLO(19,BOF,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bflrl+",  XLO(19,BOFP,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bbfrl",   XLO(19,BOF,16,1), XLBOBB_MASK, POWER,	{ BI } },
+{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdztlr",  XLO(19,BODZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdzflr",  XLO(19,BODZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bclr",    XLLK(19,16,0), XLYBB_MASK,	PPC,		{ BO, BI } },
+{ "bclrl",   XLLK(19,16,1), XLYBB_MASK,	PPC,		{ BO, BI } },
+{ "bclr+",   XLYLK(19,16,1,0), XLYBB_MASK, PPC,		{ BOE, BI } },
+{ "bclrl+",  XLYLK(19,16,1,1), XLYBB_MASK, PPC,		{ BOE, BI } },
+{ "bclr-",   XLYLK(19,16,0,0), XLYBB_MASK, PPC,		{ BOE, BI } },
+{ "bclrl-",  XLYLK(19,16,0,1), XLYBB_MASK, PPC,		{ BOE, BI } },
+{ "bcr",     XLLK(19,16,0), XLBB_MASK,	POWER,		{ BO, BI } },
+{ "bcrl",    XLLK(19,16,1), XLBB_MASK,	POWER,		{ BO, BI } },
+
+{ "crnot",   XL(19,33), XL_MASK,	PPC,		{ BT, BA, BBA } },
+{ "crnor",   XL(19,33),	XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "rfi",     XL(19,50),	0xffffffff,	PPC|POWER,	{ 0 } },
+{ "rfci",    XL(19,51),	0xffffffff,	PPC,		{ 0 } },
+
+{ "rfsvc",   XL(19,82),	0xffffffff,	POWER,		{ 0 } },
+
+{ "crandc",  XL(19,129), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "isync",   XL(19,150), 0xffffffff,	PPC,		{ 0 } },
+{ "ics",     XL(19,150), 0xffffffff,	POWER,		{ 0 } },
+
+{ "crclr",   XL(19,193), XL_MASK,	PPC,		{ BT, BAT, BBA } },
+{ "crxor",   XL(19,193), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "crnand",  XL(19,225), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "crand",   XL(19,257), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "crset",   XL(19,289), XL_MASK,	PPC,		{ BT, BAT, BBA } },
+{ "creqv",   XL(19,289), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "crorc",   XL(19,417), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "crmove",  XL(19,449), XL_MASK,	PPC,		{ BT, BA, BBA } },
+{ "cror",    XL(19,449), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+
+{ "bctr",    XLO(19,BOU,528,0), XLBOBIBB_MASK, PPC|POWER, { 0 } },
+{ "bctrl",   XLO(19,BOU,528,1), XLBOBIBB_MASK, PPC|POWER, { 0 } },
+{ "bltctr",  XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctr",  XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctr",  XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctr",  XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctr",  XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectr",  XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctr",  XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectr",  XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctr",  XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectr",  XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctr",  XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctr",  XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "btctr",   XLO(19,BOT,528,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "btctr-",  XLO(19,BOT,528,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "btctr+",  XLO(19,BOTP,528,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "btctrl",  XLO(19,BOT,528,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bfctr",   XLO(19,BOF,528,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bfctr-",  XLO(19,BOF,528,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bfctr+",  XLO(19,BOFP,528,0), XLBOBB_MASK, PPC,	{ BI } },
+{ "bfctrl",  XLO(19,BOF,528,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, PPC,	{ BI } },
+{ "bcctr",   XLLK(19,528,0), XLYBB_MASK, PPC,		{ BO, BI } },
+{ "bcctr-",  XLYLK(19,528,0,0), XLYBB_MASK, PPC,	{ BOE, BI } },
+{ "bcctr+",  XLYLK(19,528,1,0), XLYBB_MASK, PPC,	{ BOE, BI } },
+{ "bcctrl",  XLLK(19,528,1), XLYBB_MASK, PPC,		{ BO, BI } },
+{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPC,	{ BOE, BI } },
+{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPC,	{ BOE, BI } },
+{ "bcc",     XLLK(19,528,0), XLBB_MASK,	POWER,		{ BO, BI } },
+{ "bccl",    XLLK(19,528,1), XLBB_MASK,	POWER,		{ BO, BI } },
+
+{ "rlwimi",  M(20,0),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi",   M(20,0),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+
+{ "rlwimi.", M(20,1),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi.",  M(20,1),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+
+{ "rotlwi",  MME(21,31,0), MMBME_MASK,	PPC,		{ RA, RS, SH } },
+{ "clrlwi",  MME(21,31,0), MSHME_MASK,	PPC,		{ RA, RS, MB } },
+{ "rlwinm",  M(21,0),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm",   M(21,0),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+{ "rotlwi.", MME(21,31,1), MMBME_MASK,	PPC,		{ RA,RS,SH } },
+{ "clrlwi.", MME(21,31,1), MSHME_MASK,	PPC,		{ RA, RS, MB } },
+{ "rlwinm.", M(21,1),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm.",  M(21,1),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+
+{ "rlmi",    M(22,0),	M_MASK,		POWER|M601,	{ RA,RS,RB,MBE,ME } },
+{ "rlmi.",   M(22,1),	M_MASK,		POWER|M601,	{ RA,RS,RB,MBE,ME } },
+
+{ "rotlw",   MME(23,31,0), MMBME_MASK,	PPC,		{ RA, RS, RB } },
+{ "rlwnm",   M(23,0),	M_MASK,		PPC,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm",    M(23,0),	M_MASK,		POWER,		{ RA,RS,RB,MBE,ME } },
+{ "rotlw.",  MME(23,31,1), MMBME_MASK,	PPC,		{ RA, RS, RB } },
+{ "rlwnm.",  M(23,1),	M_MASK,		PPC,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm.",   M(23,1),	M_MASK,		POWER,		{ RA,RS,RB,MBE,ME } },
+
+{ "nop",     OP(24),	0xffffffff,	PPC,		{ 0 } },
+{ "ori",     OP(24),	OP_MASK,	PPC,		{ RA, RS, UI } },
+{ "oril",    OP(24),	OP_MASK,	POWER,		{ RA, RS, UI } },
+
+{ "oris",    OP(25),	OP_MASK,	PPC,		{ RA, RS, UI } },
+{ "oriu",    OP(25),	OP_MASK,	POWER,		{ RA, RS, UI } },
+
+{ "xori",    OP(26),	OP_MASK,	PPC,		{ RA, RS, UI } },
+{ "xoril",   OP(26),	OP_MASK,	POWER,		{ RA, RS, UI } },
+
+{ "xoris",   OP(27),	OP_MASK,	PPC,		{ RA, RS, UI } },
+{ "xoriu",   OP(27),	OP_MASK,	POWER,		{ RA, RS, UI } },
+
+{ "andi.",   OP(28),	OP_MASK,	PPC,		{ RA, RS, UI } },
+{ "andil.",  OP(28),	OP_MASK,	POWER,		{ RA, RS, UI } },
+
+{ "andis.",  OP(29),	OP_MASK,	PPC,		{ RA, RS, UI } },
+{ "andiu.",  OP(29),	OP_MASK,	POWER,		{ RA, RS, UI } },
+
+{ "rotldi",  MD(30,0,0), MDMB_MASK,	PPC|B64,	{ RA, RS, SH6 } },
+{ "clrldi",  MD(30,0,0), MDSH_MASK,	PPC|B64,	{ RA, RS, MB6 } },
+{ "rldicl",  MD(30,0,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+{ "rotldi.", MD(30,0,1), MDMB_MASK,	PPC|B64,	{ RA, RS, SH6 } },
+{ "clrldi.", MD(30,0,1), MDSH_MASK,	PPC|B64,	{ RA, RS, MB6 } },
+{ "rldicl.", MD(30,0,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+
+{ "rldicr",  MD(30,1,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, ME6 } },
+{ "rldicr.", MD(30,1,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, ME6 } },
+
+{ "rldic",   MD(30,2,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+{ "rldic.",  MD(30,2,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+
+{ "rldimi",  MD(30,3,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+{ "rldimi.", MD(30,3,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+
+{ "rotld",   MDS(30,8,0), MDSMB_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "rldcl",   MDS(30,8,0), MDS_MASK,	PPC|B64,	{ RA, RS, RB, MB6 } },
+{ "rotld.",  MDS(30,8,1), MDSMB_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "rldcl.",  MDS(30,8,1), MDS_MASK,	PPC|B64,	{ RA, RS, RB, MB6 } },
+
+{ "rldcr",   MDS(30,9,0), MDS_MASK,	PPC|B64,	{ RA, RS, RB, ME6 } },
+{ "rldcr.",  MDS(30,9,1), MDS_MASK,	PPC|B64,	{ RA, RS, RB, ME6 } },
+
+{ "cmpw",    XCMPL(31,0,0), XCMPL_MASK, PPC,		{ OBF, RA, RB } },
+{ "cmpd",    XCMPL(31,0,1), XCMPL_MASK, PPC|B64,	{ OBF, RA, RB } },
+{ "cmp",     X(31,0),	XCMP_MASK,	PPC,		{ BF, L, RA, RB } },
+{ "cmp",     X(31,0),	XCMPL_MASK,	POWER,		{ BF, RA, RB } },
+
+{ "twlgt",   XTO(31,4,TOLGT), XTO_MASK, PPC,		{ RA, RB } },
+{ "tlgt",    XTO(31,4,TOLGT), XTO_MASK, POWER,		{ RA, RB } },
+{ "twllt",   XTO(31,4,TOLLT), XTO_MASK, PPC,		{ RA, RB } },
+{ "tllt",    XTO(31,4,TOLLT), XTO_MASK, POWER,		{ RA, RB } },
+{ "tweq",    XTO(31,4,TOEQ), XTO_MASK,	PPC,		{ RA, RB } },
+{ "teq",     XTO(31,4,TOEQ), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twlge",   XTO(31,4,TOLGE), XTO_MASK, PPC,		{ RA, RB } },
+{ "tlge",    XTO(31,4,TOLGE), XTO_MASK, POWER,		{ RA, RB } },
+{ "twlnl",   XTO(31,4,TOLNL), XTO_MASK, PPC,		{ RA, RB } },
+{ "tlnl",    XTO(31,4,TOLNL), XTO_MASK, POWER,		{ RA, RB } },
+{ "twlle",   XTO(31,4,TOLLE), XTO_MASK, PPC,		{ RA, RB } },
+{ "tlle",    XTO(31,4,TOLLE), XTO_MASK, POWER,		{ RA, RB } },
+{ "twlng",   XTO(31,4,TOLNG), XTO_MASK, PPC,		{ RA, RB } },
+{ "tlng",    XTO(31,4,TOLNG), XTO_MASK, POWER,		{ RA, RB } },
+{ "twgt",    XTO(31,4,TOGT), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tgt",     XTO(31,4,TOGT), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twge",    XTO(31,4,TOGE), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tge",     XTO(31,4,TOGE), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twnl",    XTO(31,4,TONL), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tnl",     XTO(31,4,TONL), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twlt",    XTO(31,4,TOLT), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tlt",     XTO(31,4,TOLT), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twle",    XTO(31,4,TOLE), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tle",     XTO(31,4,TOLE), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twng",    XTO(31,4,TONG), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tng",     XTO(31,4,TONG), XTO_MASK,	POWER,		{ RA, RB } },
+{ "twne",    XTO(31,4,TONE), XTO_MASK,	PPC,		{ RA, RB } },
+{ "tne",     XTO(31,4,TONE), XTO_MASK,	POWER,		{ RA, RB } },
+{ "trap",    XTO(31,4,TOU), 0xffffffff,	PPC,		{ 0 } },
+{ "tw",      X(31,4),	X_MASK,		PPC,		{ TO, RA, RB } },
+{ "t",       X(31,4),	X_MASK,		POWER,		{ TO, RA, RB } },
+
+{ "subfc",   XO(31,8,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sf",      XO(31,8,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subc",    XO(31,8,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfc.",  XO(31,8,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sf.",     XO(31,8,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subc.",   XO(31,8,0,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfco",  XO(31,8,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sfo",     XO(31,8,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subco",   XO(31,8,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfco.", XO(31,8,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sfo.",    XO(31,8,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subco.",  XO(31,8,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+
+{ "mulhdu",  XO(31,9,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mulhdu.", XO(31,9,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+
+{ "addc",    XO(31,10,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "a",       XO(31,10,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addc.",   XO(31,10,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "a.",      XO(31,10,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addco",   XO(31,10,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "ao",      XO(31,10,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addco.",  XO(31,10,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "ao.",     XO(31,10,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+
+{ "mulhwu",  XO(31,11,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulhwu.", XO(31,11,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mfcr",    X(31,19),	XRARB_MASK,	POWER|PPC,	{ RT } },
+
+{ "lwarx",   X(31,20),	X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "ldx",     X(31,21),	X_MASK,		PPC|B64,	{ RT, RA, RB } },
+
+{ "lwzx",    X(31,23),	X_MASK,		PPC,		{ RT, RA, RB } },
+{ "lx",      X(31,23),	X_MASK,		POWER,		{ RT, RA, RB } },
+
+{ "slw",     XRC(31,24,0), X_MASK,	PPC,		{ RA, RS, RB } },
+{ "sl",      XRC(31,24,0), X_MASK,	POWER,		{ RA, RS, RB } },
+{ "slw.",    XRC(31,24,1), X_MASK,	PPC,		{ RA, RS, RB } },
+{ "sl.",     XRC(31,24,1), X_MASK,	POWER,		{ RA, RS, RB } },
+
+{ "cntlzw",  XRC(31,26,0), XRB_MASK,	PPC,		{ RA, RS } },
+{ "cntlz",   XRC(31,26,0), XRB_MASK,	POWER,		{ RA, RS } },
+{ "cntlzw.", XRC(31,26,1), XRB_MASK,	PPC,		{ RA, RS } },
+{ "cntlz.",  XRC(31,26,1), XRB_MASK, 	POWER,		{ RA, RS } },
+
+{ "sld",     XRC(31,27,0), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "sld.",    XRC(31,27,1), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+
+{ "and",     XRC(31,28,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "and.",    XRC(31,28,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "maskg",   XRC(31,29,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "maskg.",  XRC(31,29,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "cmplw",   XCMPL(31,32,0), XCMPL_MASK, PPC,		{ OBF, RA, RB } },
+{ "cmpld",   XCMPL(31,32,1), XCMPL_MASK, PPC|B64,	{ OBF, RA, RB } },
+{ "cmpl",    X(31,32),	XCMP_MASK,	PPC,		{ BF, L, RA, RB } },
+{ "cmpl",    X(31,32),	XCMPL_MASK,	POWER,		{ BF, RA, RB } },
+
+{ "subf",    XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sub",     XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subf.",   XO(31,40,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sub.",    XO(31,40,0,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfo",   XO(31,40,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "subo",    XO(31,40,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
+{ "subfo.",  XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "subo.",   XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
+
+{ "ldux",    X(31,53),	X_MASK,		PPC|B64,	{ RT, RAL, RB } },
+
+{ "dcbst",   X(31,54),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lwzux",   X(31,55),	X_MASK,		PPC,		{ RT, RAL, RB } },
+{ "lux",     X(31,55),	X_MASK,		POWER,		{ RT, RA, RB } },
+
+{ "cntlzd",  XRC(31,58,0), XRB_MASK,	PPC|B64,	{ RA, RS } },
+{ "cntlzd.", XRC(31,58,1), XRB_MASK,	PPC|B64,	{ RA, RS } },
+
+{ "andc",    XRC(31,60,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "andc.",   XRC(31,60,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "tdlgt",   XTO(31,68,TOLGT), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdllt",   XTO(31,68,TOLLT), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdeq",    XTO(31,68,TOEQ), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdlge",   XTO(31,68,TOLGE), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdlnl",   XTO(31,68,TOLNL), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdlle",   XTO(31,68,TOLLE), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdlng",   XTO(31,68,TOLNG), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdgt",    XTO(31,68,TOGT), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdge",    XTO(31,68,TOGE), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdnl",    XTO(31,68,TONL), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdlt",    XTO(31,68,TOLT), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdle",    XTO(31,68,TOLE), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdng",    XTO(31,68,TONG), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "tdne",    XTO(31,68,TONE), XTO_MASK, PPC|B64,	{ RA, RB } },
+{ "td",	     X(31,68),	X_MASK,		PPC|B64,	{ TO, RA, RB } },
+
+{ "mulhd",   XO(31,73,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mulhd.",  XO(31,73,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+
+{ "mulhw",   XO(31,75,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulhw.",  XO(31,75,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mfmsr",   X(31,83),	XRARB_MASK,	PPC|POWER,	{ RT } },
+
+{ "ldarx",   X(31,84),	X_MASK,		PPC|B64,	{ RT, RA, RB } },
+
+{ "dcbf",    X(31,86),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lbzx",    X(31,87),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+
+{ "neg",     XO(31,104,0,0), XORB_MASK,	PPC|POWER,	{ RT, RA } },
+{ "neg.",    XO(31,104,0,1), XORB_MASK,	PPC|POWER,	{ RT, RA } },
+{ "nego",    XO(31,104,1,0), XORB_MASK,	PPC|POWER,	{ RT, RA } },
+{ "nego.",   XO(31,104,1,1), XORB_MASK,	PPC|POWER,	{ RT, RA } },
+
+{ "mul",     XO(31,107,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "mul.",    XO(31,107,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "mulo",    XO(31,107,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "mulo.",   XO(31,107,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+
+{ "clf",     X(31,118), XRB_MASK,	POWER,		{ RT, RA } },
+
+{ "lbzux",   X(31,119),	X_MASK,		PPC|POWER,	{ RT, RAL, RB } },
+
+{ "not",     XRC(31,124,0), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
+{ "nor",     XRC(31,124,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "not.",    XRC(31,124,1), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
+{ "nor.",    XRC(31,124,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "subfe",   XO(31,136,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sfe",     XO(31,136,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subfe.",  XO(31,136,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sfe.",    XO(31,136,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subfeo",  XO(31,136,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sfeo",    XO(31,136,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subfeo.", XO(31,136,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "sfeo.",   XO(31,136,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+
+{ "adde",    XO(31,138,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "ae",      XO(31,138,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "adde.",   XO(31,138,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "ae.",     XO(31,138,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addeo",   XO(31,138,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "aeo",     XO(31,138,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addeo.",  XO(31,138,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "aeo.",    XO(31,138,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+
+{ "mtcr",    XFXM(31,144,0xff), XFXFXM_MASK|FXM_MASK, PPC|POWER, { RS }},
+{ "mtcrf",   X(31,144),	XFXFXM_MASK,	PPC|POWER,	{ FXM, RS } },
+
+{ "mtmsr",   X(31,146),	XRARB_MASK,	PPC|POWER,	{ RS } },
+{ "mtmsrd",  X(31,178),	XRARB_MASK,	PPC|POWER,	{ RS } },
+
+{ "stdx",    X(31,149), X_MASK,		PPC|B64,	{ RS, RA, RB } },
+
+{ "stwcx.",  XRC(31,150,1), X_MASK,	PPC,		{ RS, RA, RB } },
+
+{ "stwx",    X(31,151), X_MASK,		PPC,		{ RS, RA, RB } },
+{ "stx",     X(31,151), X_MASK,		POWER,		{ RS, RA, RB } },
+
+{ "slq",     XRC(31,152,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "slq.",    XRC(31,152,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "sle",     XRC(31,153,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sle.",    XRC(31,153,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "stdux",   X(31,181),	X_MASK,		PPC|B64,	{ RS, RAS, RB } },
+
+{ "stwux",   X(31,183),	X_MASK,		PPC,		{ RS, RAS, RB } },
+{ "stux",    X(31,183),	X_MASK,		POWER,		{ RS, RA, RB } },
+
+{ "sliq",    XRC(31,184,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "sliq.",   XRC(31,184,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+
+{ "subfze",  XO(31,200,0,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfze",    XO(31,200,0,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "subfze.", XO(31,200,0,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfze.",   XO(31,200,0,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfzeo",   XO(31,200,1,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfzeo.",  XO(31,200,1,1), XORB_MASK, POWER,		{ RT, RA } },
+
+{ "addze",   XO(31,202,0,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "aze",     XO(31,202,0,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "addze.",  XO(31,202,0,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "aze.",    XO(31,202,0,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "addzeo",  XO(31,202,1,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "azeo",    XO(31,202,1,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "azeo.",   XO(31,202,1,1), XORB_MASK, POWER,		{ RT, RA } },
+
+{ "mtsr",    X(31,210),	XRB_MASK|(1<<20), PPC|POWER|B32, { SR, RS } },
+
+{ "stdcx.",  XRC(31,214,1), X_MASK,	PPC|B64,	{ RS, RA, RB } },
+
+{ "stbx",    X(31,215),	X_MASK,		PPC|POWER,	{ RS, RA, RB } },
+
+{ "sllq",    XRC(31,216,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sllq.",   XRC(31,216,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "sleq",    XRC(31,217,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sleq.",   XRC(31,217,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "subfme",  XO(31,232,0,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfme",    XO(31,232,0,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "subfme.", XO(31,232,0,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfme.",   XO(31,232,0,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfmeo",   XO(31,232,1,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "sfmeo.",  XO(31,232,1,1), XORB_MASK, POWER,		{ RT, RA } },
+
+{ "mulld",   XO(31,233,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mulld.",  XO(31,233,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mulldo",  XO(31,233,1,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mulldo.", XO(31,233,1,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+
+{ "addme",   XO(31,234,0,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "ame",     XO(31,234,0,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "addme.",  XO(31,234,0,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "ame.",    XO(31,234,0,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "addmeo",  XO(31,234,1,0), XORB_MASK, PPC,		{ RT, RA } },
+{ "ameo",    XO(31,234,1,0), XORB_MASK, POWER,		{ RT, RA } },
+{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPC,		{ RT, RA } },
+{ "ameo.",   XO(31,234,1,1), XORB_MASK, POWER,		{ RT, RA } },
+
+{ "mullw",   XO(31,235,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "muls",    XO(31,235,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "mullw.",  XO(31,235,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "muls.",   XO(31,235,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "mullwo",  XO(31,235,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulso",   XO(31,235,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "mullwo.", XO(31,235,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "mulso.",  XO(31,235,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+
+{ "mtsrin",  X(31,242),	XRA_MASK,	PPC|B32,	{ RS, RB } },
+{ "mtsri",   X(31,242),	XRA_MASK,	POWER|B32,	{ RS, RB } },
+
+{ "dcbtst",  X(31,246),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "stbux",   X(31,247),	X_MASK,		PPC|POWER,	{ RS, RAS, RB } },
+
+{ "slliq",   XRC(31,248,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "slliq.",  XRC(31,248,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+
+{ "doz",     XO(31,264,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "doz.",    XO(31,264,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "dozo",    XO(31,264,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "dozo.",   XO(31,264,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+
+{ "add",     XO(31,266,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "cax",     XO(31,266,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "add.",    XO(31,266,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "cax.",    XO(31,266,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addo",    XO(31,266,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "caxo",    XO(31,266,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addo.",   XO(31,266,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "caxo.",   XO(31,266,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+
+{ "lscbx",   XRC(31,277,0), X_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "lscbx.",  XRC(31,277,1), X_MASK,	POWER|M601,	{ RT, RA, RB } },
+
+{ "dcbt",    X(31,278),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lhzx",    X(31,279),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+
+{ "icbt",    X(31,262),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "eqv",     XRC(31,284,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "eqv.",    XRC(31,284,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "tlbie",   X(31,306),	XRTRA_MASK,	PPC,		{ RB } },
+{ "tlbi",    X(31,306),	XRTRA_MASK,	POWER,		{ RB } },
+
+{ "eciwx",   X(31,310), X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "lhzux",   X(31,311),	X_MASK,		PPC|POWER,	{ RT, RAL, RB } },
+
+{ "xor",     XRC(31,316,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "xor.",    XRC(31,316,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "mfdcr",   X(31,323),	X_MASK,		PPC,		{ RT, SPR } },
+
+{ "div",     XO(31,331,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "div.",    XO(31,331,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "divo",    XO(31,331,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "divo.",   XO(31,331,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+
+{ "mfmq",    XSPR(31,339,0), XSPR_MASK,	POWER|M601,	{ RT } },
+{ "mfxer",   XSPR(31,339,1), XSPR_MASK,	PPC|POWER,	{ RT } },
+{ "mfrtcu",  XSPR(31,339,4), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfrtcl",  XSPR(31,339,5), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfdec",   XSPR(31,339,6), XSPR_MASK, POWER|M601,	{ RT } },
+{ "mflr",    XSPR(31,339,8), XSPR_MASK,	PPC|POWER,	{ RT } },
+{ "mfctr",   XSPR(31,339,9), XSPR_MASK,	PPC|POWER,	{ RT } },
+{ "mftid",   XSPR(31,339,17), XSPR_MASK, POWER,		{ RT } },
+{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfdar",   XSPR(31,339,19), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfdec",   XSPR(31,339,22), XSPR_MASK, PPC,		{ RT } },
+{ "mfsdr0",  XSPR(31,339,24), XSPR_MASK, POWER,		{ RT } },
+{ "mfsdr1",  XSPR(31,339,25), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfsrr0",  XSPR(31,339,26), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfsrr1",  XSPR(31,339,27), XSPR_MASK, PPC|POWER,	{ RT } },
+{ "mfsprg",  XSPR(31,339,272), XSPRG_MASK, PPC,		{ RT, SPRG } },
+{ "mfasr",   XSPR(31,339,280), XSPR_MASK, PPC|B64,	{ RT } },
+{ "mfear",   XSPR(31,339,282), XSPR_MASK, PPC,		{ RT } },
+{ "mfpvr",   XSPR(31,339,287), XSPR_MASK, PPC,		{ RT } },
+{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfspr",   X(31,339),	X_MASK,		PPC|POWER,	{ RT, SPR } },
+
+{ "lwax",    X(31,341),	X_MASK,		PPC|B64,	{ RT, RA, RB } },
+
+{ "lhax",    X(31,343),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+
+{ "dccci",   X(31,454),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "abs",     XO(31,360,0,0), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "abs.",    XO(31,360,0,1), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "abso",    XO(31,360,1,0), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "abso.",   XO(31,360,1,1), XORB_MASK, POWER|M601,	{ RT, RA } },
+
+{ "divs",    XO(31,363,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "divs.",   XO(31,363,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "divso",   XO(31,363,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "divso.",  XO(31,363,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+
+{ "tlbia",   X(31,370),	0xffffffff,	PPC,		{ 0 } },
+
+{ "mftbu",   XSPR(31,371,269), XSPR_MASK, PPC,		{ RT } },
+{ "mftb",    X(31,371),	X_MASK,		PPC,		{ RT, TBR } },
+
+{ "lwaux",   X(31,373),	X_MASK,		PPC|B64,	{ RT, RAL, RB } },
+
+{ "lhaux",   X(31,375),	X_MASK,		PPC|POWER,	{ RT, RAL, RB } },
+
+{ "sthx",    X(31,407),	X_MASK,		PPC|POWER,	{ RS, RA, RB } },
+
+{ "lfqx",    X(31,791),	X_MASK,		POWER2,		{ FRT, RA, RB } },
+
+{ "lfqux",   X(31,823),	X_MASK,		POWER2,		{ FRT, RA, RB } },
+
+{ "stfqx",   X(31,919),	X_MASK,		POWER2,		{ FRS, RA, RB } },
+
+{ "stfqux",  X(31,951),	X_MASK,		POWER2,		{ FRS, RA, RB } },
+
+{ "orc",     XRC(31,412,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "orc.",    XRC(31,412,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "sradi",   XS(31,413,0), XS_MASK,	PPC|B64,	{ RA, RS, SH6 } },
+{ "sradi.",  XS(31,413,1), XS_MASK,	PPC|B64,	{ RA, RS, SH6 } },
+
+{ "slbie",   X(31,434),	XRTRA_MASK,	PPC|B64,	{ RB } },
+
+{ "ecowx",   X(31,438),	X_MASK,		PPC,		{ RT, RA, RB } },
+
+{ "sthux",   X(31,439),	X_MASK,		PPC|POWER,	{ RS, RAS, RB } },
+
+{ "mr",	     XRC(31,444,0), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
+{ "or",      XRC(31,444,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "mr.",     XRC(31,444,1), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
+{ "or.",     XRC(31,444,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "mtdcr",   X(31,451),	X_MASK,		PPC,		{ SPR, RS } },
+
+{ "divdu",   XO(31,457,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "divdu.",  XO(31,457,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "divduo",  XO(31,457,1,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "divduo.", XO(31,457,1,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+
+{ "divwu",   XO(31,459,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwu.",  XO(31,459,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwuo",  XO(31,459,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwuo.", XO(31,459,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "mtmq",    XSPR(31,467,0), XSPR_MASK,	POWER|M601,	{ RS } },
+{ "mtxer",   XSPR(31,467,1), XSPR_MASK,	PPC|POWER,	{ RS } },
+{ "mtlr",    XSPR(31,467,8), XSPR_MASK,	PPC|POWER,	{ RS } },
+{ "mtctr",   XSPR(31,467,9), XSPR_MASK,	PPC|POWER,	{ RS } },
+{ "mttid",   XSPR(31,467,17), XSPR_MASK, POWER,		{ RS } },
+{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtdar",   XSPR(31,467,19), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtrtcu",  XSPR(31,467,20), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtrtcl",  XSPR(31,467,21), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtdec",   XSPR(31,467,22), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtsdr0",  XSPR(31,467,24), XSPR_MASK, POWER,		{ RS } },
+{ "mtsdr1",  XSPR(31,467,25), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtsrr0",  XSPR(31,467,26), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtsrr1",  XSPR(31,467,27), XSPR_MASK, PPC|POWER,	{ RS } },
+{ "mtsprg",  XSPR(31,467,272), XSPRG_MASK, PPC,		{ SPRG, RS } },
+{ "mtasr",   XSPR(31,467,280), XSPR_MASK, PPC|B64,	{ RS } },
+{ "mtear",   XSPR(31,467,282), XSPR_MASK, PPC,		{ RS } },
+{ "mttbl",   XSPR(31,467,284), XSPR_MASK, PPC,		{ RS } },
+{ "mttbu",   XSPR(31,467,285), XSPR_MASK, PPC,		{ RS } },
+{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtspr",   X(31,467),	X_MASK,		PPC|POWER,	{ SPR, RS } },
+
+{ "dcbi",    X(31,470),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "nand",    XRC(31,476,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "nand.",   XRC(31,476,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+
+{ "nabs",    XO(31,488,0,0), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "nabs.",   XO(31,488,0,1), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "nabso",   XO(31,488,1,0), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "nabso.",  XO(31,488,1,1), XORB_MASK, POWER|M601,	{ RT, RA } },
+
+{ "divd",    XO(31,489,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "divd.",   XO(31,489,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "divdo",   XO(31,489,1,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "divdo.",  XO(31,489,1,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+
+{ "divw",    XO(31,491,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divw.",   XO(31,491,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwo",   XO(31,491,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
+{ "divwo.",  XO(31,491,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
+
+{ "slbia",   X(31,498),	0xffffffff,	PPC|B64,	{ 0 } },
+
+{ "cli",     X(31,502), XRB_MASK,	POWER,		{ RT, RA } },
+
+{ "mcrxr",   X(31,512),	XRARB_MASK|(3<<21), PPC|POWER,	{ BF } },
+
+{ "clcs",    X(31,531), XRB_MASK,	POWER|M601,	{ RT, RA } },
+
+{ "lswx",    X(31,533),	X_MASK,		PPC,		{ RT, RA, RB } },
+{ "lsx",     X(31,533),	X_MASK,		POWER,		{ RT, RA, RB } },
+
+{ "lwbrx",   X(31,534),	X_MASK,		PPC,		{ RT, RA, RB } },
+{ "lbrx",    X(31,534),	X_MASK,		POWER,		{ RT, RA, RB } },
+
+{ "lfsx",    X(31,535),	X_MASK,		PPC|POWER,	{ FRT, RA, RB } },
+
+{ "srw",     XRC(31,536,0), X_MASK,	PPC,		{ RA, RS, RB } },
+{ "sr",      XRC(31,536,0), X_MASK,	POWER,		{ RA, RS, RB } },
+{ "srw.",    XRC(31,536,1), X_MASK,	PPC,		{ RA, RS, RB } },
+{ "sr.",     XRC(31,536,1), X_MASK,	POWER,		{ RA, RS, RB } },
+
+{ "rrib",    XRC(31,537,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "rrib.",   XRC(31,537,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "srd",     XRC(31,539,0), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "srd.",    XRC(31,539,1), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+
+{ "maskir",  XRC(31,541,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "maskir.", XRC(31,541,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "tlbsync", X(31,566),	0xffffffff,	PPC,		{ 0 } },
+
+{ "lfsux",   X(31,567),	X_MASK,		PPC|POWER,	{ FRT, RAS, RB } },
+
+{ "mfsr",    X(31,595),	XRB_MASK|(1<<20), PPC|POWER|B32, { RT, SR } },
+
+{ "lswi",    X(31,597),	X_MASK,		PPC,		{ RT, RA, NB } },
+{ "lsi",     X(31,597),	X_MASK,		POWER,		{ RT, RA, NB } },
+
+{ "sync",    X(31,598), 0xffffffff,	PPC,		{ 0 } },
+{ "dcs",     X(31,598), 0xffffffff,	POWER,		{ 0 } },
+
+{ "lfdx",    X(31,599), X_MASK,		PPC|POWER,	{ FRT, RA, RB } },
+
+{ "mfsri",   X(31,627), X_MASK,		POWER,		{ RT, RA, RB } },
+
+{ "dclst",   X(31,630), XRB_MASK,	POWER,		{ RS, RA } },
+
+{ "lfdux",   X(31,631), X_MASK,		PPC|POWER,	{ FRT, RAS, RB } },
+
+{ "mfsrin",  X(31,659), XRA_MASK,	PPC|B32,	{ RT, RB } },
+
+{ "stswx",   X(31,661), X_MASK,		PPC,		{ RS, RA, RB } },
+{ "stsx",    X(31,661), X_MASK,		POWER,		{ RS, RA, RB } },
+
+{ "stwbrx",  X(31,662), X_MASK,		PPC,		{ RS, RA, RB } },
+{ "stbrx",   X(31,662), X_MASK,		POWER,		{ RS, RA, RB } },
+
+{ "stfsx",   X(31,663), X_MASK,		PPC|POWER,	{ FRS, RA, RB } },
+
+{ "srq",     XRC(31,664,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "srq.",    XRC(31,664,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "sre",     XRC(31,665,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sre.",    XRC(31,665,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "stfsux",  X(31,695),	X_MASK,		PPC|POWER,	{ FRS, RAS, RB } },
+
+{ "sriq",    XRC(31,696,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "sriq.",   XRC(31,696,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+
+{ "stswi",   X(31,725),	X_MASK,		PPC,		{ RS, RA, NB } },
+{ "stsi",    X(31,725),	X_MASK,		POWER,		{ RS, RA, NB } },
+
+{ "stfdx",   X(31,727),	X_MASK,		PPC|POWER,	{ FRS, RA, RB } },
+
+{ "srlq",    XRC(31,728,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "srlq.",   XRC(31,728,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "sreq",    XRC(31,729,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sreq.",   XRC(31,729,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "stfdux",  X(31,759),	X_MASK,		PPC|POWER,	{ FRS, RAS, RB } },
+
+{ "srliq",   XRC(31,760,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "srliq.",  XRC(31,760,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+
+{ "lhbrx",   X(31,790),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+
+{ "sraw",    XRC(31,792,0), X_MASK,	PPC,		{ RA, RS, RB } },
+{ "sra",     XRC(31,792,0), X_MASK,	POWER,		{ RA, RS, RB } },
+{ "sraw.",   XRC(31,792,1), X_MASK,	PPC,		{ RA, RS, RB } },
+{ "sra.",    XRC(31,792,1), X_MASK,	POWER,		{ RA, RS, RB } },
+
+{ "srad",    XRC(31,794,0), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "srad.",   XRC(31,794,1), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+
+{ "rac",     X(31,818),	X_MASK,		POWER,		{ RT, RA, RB } },
+
+{ "srawi",   XRC(31,824,0), X_MASK,	PPC,		{ RA, RS, SH } },
+{ "srai",    XRC(31,824,0), X_MASK,	POWER,		{ RA, RS, SH } },
+{ "srawi.",  XRC(31,824,1), X_MASK,	PPC,		{ RA, RS, SH } },
+{ "srai.",   XRC(31,824,1), X_MASK,	POWER,		{ RA, RS, SH } },
+
+{ "eieio",   X(31,854),	0xffffffff,	PPC,		{ 0 } },
+
+{ "sthbrx",  X(31,918),	X_MASK,		PPC|POWER,	{ RS, RA, RB } },
+
+{ "sraq",    XRC(31,920,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sraq.",   XRC(31,920,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "srea",    XRC(31,921,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "srea.",   XRC(31,921,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+
+{ "extsh",   XRC(31,922,0), XRB_MASK,	PPC,		{ RA, RS } },
+{ "exts",    XRC(31,922,0), XRB_MASK,	POWER,		{ RA, RS } },
+{ "extsh.",  XRC(31,922,1), XRB_MASK,	PPC,		{ RA, RS } },
+{ "exts.",   XRC(31,922,1), XRB_MASK,	POWER,		{ RA, RS } },
+
+{ "sraiq",   XRC(31,952,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "sraiq.",  XRC(31,952,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+
+{ "extsb",   XRC(31,954,0), XRB_MASK,	PPC,		{ RA, RS} },
+{ "extsb.",  XRC(31,954,1), XRB_MASK,	PPC,		{ RA, RS} },
+
+{ "iccci",   X(31,966),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "icbi",    X(31,982),	XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "stfiwx",  X(31,983),	X_MASK,		PPC,		{ FRS, RA, RB } },
+
+{ "extsw",   XRC(31,986,0), XRB_MASK,	PPC,		{ RA, RS } },
+{ "extsw.",  XRC(31,986,1), XRB_MASK,	PPC,		{ RA, RS } },
+
+{ "dcbz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
+{ "dclz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
+
+{ "lwz",     OP(32),	OP_MASK,	PPC,		{ RT, D, RA } },
+{ "l",	     OP(32),	OP_MASK,	POWER,		{ RT, D, RA } },
+
+{ "lwzu",    OP(33),	OP_MASK,	PPC,		{ RT, D, RAL } },
+{ "lu",      OP(33),	OP_MASK,	POWER,		{ RT, D, RA } },
+
+{ "lbz",     OP(34),	OP_MASK,	PPC|POWER,	{ RT, D, RA } },
+
+{ "lbzu",    OP(35),	OP_MASK,	PPC|POWER,	{ RT, D, RAL } },
+
+{ "stw",     OP(36),	OP_MASK,	PPC,		{ RS, D, RA } },
+{ "st",      OP(36),	OP_MASK,	POWER,		{ RS, D, RA } },
+
+{ "stwu",    OP(37),	OP_MASK,	PPC,		{ RS, D, RAS } },
+{ "stu",     OP(37),	OP_MASK,	POWER,		{ RS, D, RA } },
+
+{ "stb",     OP(38),	OP_MASK,	PPC|POWER,	{ RS, D, RA } },
+
+{ "stbu",    OP(39),	OP_MASK,	PPC|POWER,	{ RS, D, RAS } },
+
+{ "lhz",     OP(40),	OP_MASK,	PPC|POWER,	{ RT, D, RA } },
+
+{ "lhzu",    OP(41),	OP_MASK,	PPC|POWER,	{ RT, D, RAL } },
+
+{ "lha",     OP(42),	OP_MASK,	PPC|POWER,	{ RT, D, RA } },
+
+{ "lhau",    OP(43),	OP_MASK,	PPC|POWER,	{ RT, D, RAL } },
+
+{ "sth",     OP(44),	OP_MASK,	PPC|POWER,	{ RS, D, RA } },
+
+{ "sthu",    OP(45),	OP_MASK,	PPC|POWER,	{ RS, D, RAS } },
+
+{ "lmw",     OP(46),	OP_MASK,	PPC,		{ RT, D, RAM } },
+{ "lm",      OP(46),	OP_MASK,	POWER,		{ RT, D, RA } },
+
+{ "stmw",    OP(47),	OP_MASK,	PPC,		{ RS, D, RA } },
+{ "stm",     OP(47),	OP_MASK,	POWER,		{ RS, D, RA } },
+
+{ "lfs",     OP(48),	OP_MASK,	PPC|POWER,	{ FRT, D, RA } },
+
+{ "lfsu",    OP(49),	OP_MASK,	PPC|POWER,	{ FRT, D, RAS } },
+
+{ "lfd",     OP(50),	OP_MASK,	PPC|POWER,	{ FRT, D, RA } },
+
+{ "lfdu",    OP(51),	OP_MASK,	PPC|POWER,	{ FRT, D, RAS } },
+
+{ "stfs",    OP(52),	OP_MASK,	PPC|POWER,	{ FRS, D, RA } },
+
+{ "stfsu",   OP(53),	OP_MASK,	PPC|POWER,	{ FRS, D, RAS } },
+
+{ "stfd",    OP(54),	OP_MASK,	PPC|POWER,	{ FRS, D, RA } },
+
+{ "stfdu",   OP(55),	OP_MASK,	PPC|POWER,	{ FRS, D, RAS } },
+
+{ "lfq",     OP(56),	OP_MASK,	POWER2,		{ FRT, D, RA } },
+
+{ "lfqu",    OP(57),	OP_MASK,	POWER2,		{ FRT, D, RA } },
+
+{ "ld",      DSO(58,0),	DS_MASK,	PPC|B64,	{ RT, DS, RA } },
+
+{ "ldu",     DSO(58,1), DS_MASK,	PPC|B64,	{ RT, DS, RAL } },
+
+{ "lwa",     DSO(58,2), DS_MASK,	PPC|B64,	{ RT, DS, RA } },
+
+{ "fdivs",   A(59,18,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fdivs.",  A(59,18,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fsubs",   A(59,20,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fsubs.",  A(59,20,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fadds",   A(59,21,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fadds.",  A(59,21,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+
+{ "fsqrts",  A(59,22,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fsqrts.", A(59,22,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fres",    A(59,24,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fres.",   A(59,24,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fmuls",   A(59,25,0), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+{ "fmuls.",  A(59,25,1), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+
+{ "fmsubs",  A(59,28,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fmsubs.", A(59,28,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmadds",  A(59,29,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fmadds.", A(59,29,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmsubs", A(59,30,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsubs.",A(59,30,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmadds", A(59,31,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadds.",A(59,31,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "stfq",    OP(60),	OP_MASK,	POWER2,		{ FRS, D, RA } },
+
+{ "stfqu",   OP(61),	OP_MASK,	POWER2,		{ FRS, D, RA } },
+
+{ "std",     DSO(62,0),	DS_MASK,	PPC|B64,	{ RS, DS, RA } },
+
+{ "stdu",    DSO(62,1),	DS_MASK,	PPC|B64,	{ RS, DS, RAS } },
+
+{ "fcmpu",   X(63,0),	X_MASK|(3<<21),	PPC|POWER,	{ BF, FRA, FRB } },
+
+{ "frsp",    XRC(63,12,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "frsp.",   XRC(63,12,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+
+{ "fctiw",   XRC(63,14,0), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fcir",    XRC(63,14,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
+{ "fctiw.",  XRC(63,14,1), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fcir.",   XRC(63,14,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
+
+{ "fctiwz",  XRC(63,15,0), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fcirz",   XRC(63,15,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
+{ "fctiwz.", XRC(63,15,1), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fcirz.",  XRC(63,15,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
+
+{ "fdiv",    A(63,18,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fd",      A(63,18,0), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+{ "fdiv.",   A(63,18,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fd.",     A(63,18,1), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+
+{ "fsub",    A(63,20,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fs",      A(63,20,0), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+{ "fsub.",   A(63,20,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fs.",     A(63,20,1), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+
+{ "fadd",    A(63,21,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fa",      A(63,21,0), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+{ "fadd.",   A(63,21,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
+{ "fa.",     A(63,21,1), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+
+{ "fsqrt",   A(63,22,0), AFRAFRC_MASK,	PPC|POWER2,	{ FRT, FRB } },
+{ "fsqrt.",  A(63,22,1), AFRAFRC_MASK,	PPC|POWER2,	{ FRT, FRB } },
+
+{ "fsel",    A(63,23,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fsel.",   A(63,23,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmul",    A(63,25,0), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+{ "fm",      A(63,25,0), AFRB_MASK,	POWER,		{ FRT, FRA, FRC } },
+{ "fmul.",   A(63,25,1), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
+{ "fm.",     A(63,25,1), AFRB_MASK,	POWER,		{ FRT, FRA, FRC } },
+
+{ "frsqrte", A(63,26,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "frsqrte.",A(63,26,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+
+{ "fmsub",   A(63,28,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fms",     A(63,28,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fmsub.",  A(63,28,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fms.",    A(63,28,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+
+{ "fmadd",   A(63,29,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fma",     A(63,29,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fmadd.",  A(63,29,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fma.",    A(63,29,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmsub",  A(63,30,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnms",    A(63,30,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsub.", A(63,30,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnms.",   A(63,30,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+
+{ "fnmadd",  A(63,31,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnma",    A(63,31,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadd.", A(63,31,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
+{ "fnma.",   A(63,31,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+
+{ "fcmpo",   X(63,30),	X_MASK|(3<<21),	PPC|POWER,	{ BF, FRA, FRB } },
+
+{ "mtfsb1",  XRC(63,38,0), XRARB_MASK,	PPC|POWER,	{ BT } },
+{ "mtfsb1.", XRC(63,38,1), XRARB_MASK,	PPC|POWER,	{ BT } },
+
+{ "fneg",    XRC(63,40,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "fneg.",   XRC(63,40,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+
+{ "mcrfs",   X(63,64),	XRB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } },
+
+{ "mtfsb0",  XRC(63,70,0), XRARB_MASK,	PPC|POWER,	{ BT } },
+{ "mtfsb0.", XRC(63,70,1), XRARB_MASK,	PPC|POWER,	{ BT } },
+
+{ "fmr",     XRC(63,72,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "fmr.",    XRC(63,72,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+
+{ "mtfsfi",  XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } },
+{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } },
+
+{ "fnabs",   XRC(63,136,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "fnabs.",  XRC(63,136,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+
+{ "fabs",    XRC(63,264,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "fabs.",   XRC(63,264,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+
+{ "mffs",    XRC(63,583,0), XRARB_MASK,	PPC|POWER,	{ FRT } },
+{ "mffs.",   XRC(63,583,1), XRARB_MASK,	PPC|POWER,	{ FRT } },
+
+{ "mtfsf",   XFL(63,711,0), XFL_MASK,	PPC|POWER,	{ FLM, FRB } },
+{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	PPC|POWER,	{ FLM, FRB } },
+
+{ "fctid",   XRC(63,814,0), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+{ "fctid.",  XRC(63,814,1), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+
+{ "fctidz",  XRC(63,815,0), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+{ "fctidz.", XRC(63,815,1), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+
+{ "fcfid",   XRC(63,846,0), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+{ "fcfid.",  XRC(63,846,1), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+
+};
+
+const int powerpc_num_opcodes =
+  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+
+/* The macro table.  This is only used by the assembler.  */
+
+const struct powerpc_macro powerpc_macros[] = {
+{ "extldi",  4,   PPC|B64,	"rldicr %0,%1,%3,(%2)-1" },
+{ "extldi.", 4,   PPC|B64,	"rldicr. %0,%1,%3,(%2)-1" },
+{ "extrdi",  4,   PPC|B64,	"rldicl %0,%1,(%2)+(%3),64-(%2)" },
+{ "extrdi.", 4,   PPC|B64,	"rldicl. %0,%1,(%2)+(%3),64-(%2)" },
+{ "insrdi",  4,   PPC|B64,	"rldimi %0,%1,64-((%2)+(%3)),%3" },
+{ "insrdi.", 4,   PPC|B64,	"rldimi. %0,%1,64-((%2)+(%3)),%3" },
+{ "rotrdi",  3,   PPC|B64,	"rldicl %0,%1,64-(%2),0" },
+{ "rotrdi.", 3,   PPC|B64,	"rldicl. %0,%1,64-(%2),0" },
+{ "sldi",    3,   PPC|B64,	"rldicr %0,%1,%2,63-(%2)" },
+{ "sldi.",   3,   PPC|B64,	"rldicr. %0,%1,%2,63-(%2)" },
+{ "srdi",    3,   PPC|B64,	"rldicl %0,%1,64-(%2),%2" },
+{ "srdi.",   3,   PPC|B64,	"rldicl. %0,%1,64-(%2),%2" },
+{ "clrrdi",  3,   PPC|B64,	"rldicr %0,%1,0,63-(%2)" },
+{ "clrrdi.", 3,   PPC|B64,	"rldicr. %0,%1,0,63-(%2)" },
+{ "clrlsldi",4,   PPC|B64,	"rldic %0,%1,%3,(%2)-(%3)" },
+{ "clrlsldi.",4,  PPC|B64,	"rldic. %0,%1,%3,(%2)-(%3)" },
+
+{ "extlwi",  4,   PPC,		"rlwinm %0,%1,%3,0,(%2)-1" },
+{ "extlwi.", 4,   PPC,		"rlwinm. %0,%1,%3,0,(%2)-1" },
+{ "extrwi",  4,   PPC,		"rlwinm %0,%1,(%2)+(%3),32-(%2),31" },
+{ "extrwi.", 4,   PPC,		"rlwinm. %0,%1,(%2)+(%3),32-(%2),31" },
+{ "inslwi",  4,   PPC,		"rlwimi %0,%1,32-(%3),%3,(%2)+(%3)-1" },
+{ "inslwi.", 4,   PPC,		"rlwimi. %0,%1,32-(%3),%3,(%2)+(%3)-1" },
+{ "insrwi",  4,   PPC,		"rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" },
+{ "insrwi.", 4,   PPC,		"rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"},
+{ "rotrwi",  3,   PPC,		"rlwinm %0,%1,32-(%2),0,31" },
+{ "rotrwi.", 3,   PPC,		"rlwinm. %0,%1,32-(%2),0,31" },
+{ "slwi",    3,   PPC,		"rlwinm %0,%1,%2,0,31-(%2)" },
+{ "sli",     3,   POWER,	"rlinm %0,%1,%2,0,31-(%2)" },
+{ "slwi.",   3,   PPC,		"rlwinm. %0,%1,%2,0,31-(%2)" },
+{ "sli.",    3,   POWER,	"rlinm. %0,%1,%2,0,31-(%2)" },
+{ "srwi",    3,   PPC,		"rlwinm %0,%1,32-(%2),%2,31" },
+{ "sri",     3,   POWER,	"rlinm %0,%1,32-(%2),%2,31" },
+{ "srwi.",   3,   PPC,		"rlwinm. %0,%1,32-(%2),%2,31" },
+{ "sri.",    3,   POWER,	"rlinm. %0,%1,32-(%2),%2,31" },
+{ "clrrwi",  3,   PPC,		"rlwinm %0,%1,0,0,31-(%2)" },
+{ "clrrwi.", 3,   PPC,		"rlwinm. %0,%1,0,0,31-(%2)" },
+{ "clrlslwi",4,   PPC,		"rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" },
+{ "clrlslwi.",4,  PPC,		"rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
+
+};
+
+const int powerpc_num_macros =
+  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/ppc.h linux-2.4.19-pre5/arch/ppc64/xmon/ppc.h
--- linux-2.4.19-pre4/arch/ppc64/xmon/ppc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/ppc.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,240 @@
+/* ppc.h -- Header file for PowerPC opcode table
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef PPC_H
+#define PPC_H
+
+/* The opcode table is an array of struct powerpc_opcode.  */
+
+struct powerpc_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+
+  /* The opcode itself.  Those bits which will be filled in with
+     operands are zeroes.  */
+  unsigned long opcode;
+
+  /* The opcode mask.  This is used by the disassembler.  This is a
+     mask containing ones indicating those bits which must match the
+     opcode field, and zeroes indicating those bits which need not
+     match (and are presumably filled in by operands).  */
+  unsigned long mask;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The defined values
+     are listed below.  */
+  unsigned long flags;
+
+  /* An array of operand codes.  Each code is an index into the
+     operand table.  They appear in the order which the operands must
+     appear in assembly code, and are terminated by a zero.  */
+  unsigned char operands[8];
+};
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+extern const struct powerpc_opcode powerpc_opcodes[];
+extern const int powerpc_num_opcodes;
+
+/* Values defined for the flags field of a struct powerpc_opcode.  */
+
+/* Opcode is defined for the PowerPC architecture.  */
+#define PPC_OPCODE_PPC (01)
+
+/* Opcode is defined for the POWER (RS/6000) architecture.  */
+#define PPC_OPCODE_POWER (02)
+
+/* Opcode is defined for the POWER2 (Rios 2) architecture.  */
+#define PPC_OPCODE_POWER2 (04)
+
+/* Opcode is only defined on 32 bit architectures.  */
+#define PPC_OPCODE_32 (010)
+
+/* Opcode is only defined on 64 bit architectures.  */
+#define PPC_OPCODE_64 (020)
+
+/* Opcode is supported by the Motorola PowerPC 601 processor.  The 601
+   is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions,
+   but it also supports many additional POWER instructions.  */
+#define PPC_OPCODE_601 (040)
+
+/* A macro to extract the major opcode from an instruction.  */
+#define PPC_OP(i) (((i) >> 26) & 0x3f)
+
+/* The operands table is an array of struct powerpc_operand.  */
+
+struct powerpc_operand
+{
+  /* The number of bits in the operand.  */
+  int bits;
+
+  /* How far the operand is left shifted in the instruction.  */
+  int shift;
+
+  /* Insertion function.  This is used by the assembler.  To insert an
+     operand value into an instruction, check this field.
+
+     If it is NULL, execute
+         i |= (op & ((1 << o->bits) - 1)) << o->shift;
+     (i is the instruction which we are filling in, o is a pointer to
+     this structure, and op is the opcode value; this assumes twos
+     complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction and the operand value.  It will return the new value
+     of the instruction.  If the ERRMSG argument is not NULL, then if
+     the operand value is illegal, *ERRMSG will be set to a warning
+     string (the operand will be inserted in any case).  If the
+     operand value is legal, *ERRMSG will be unchanged (most operands
+     can accept any value).  */
+  unsigned long (*insert) PARAMS ((unsigned long instruction, long op,
+				   const char **errmsg));
+
+  /* Extraction function.  This is used by the disassembler.  To
+     extract this operand type from an instruction, check this field.
+
+     If it is NULL, compute
+         op = ((i) >> o->shift) & ((1 << o->bits) - 1);
+	 if ((o->flags & PPC_OPERAND_SIGNED) != 0
+	     && (op & (1 << (o->bits - 1))) != 0)
+	   op -= 1 << o->bits;
+     (i is the instruction, o is a pointer to this structure, and op
+     is the result; this assumes twos complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction value.  It will return the value of the operand.  If
+     the INVALID argument is not NULL, *INVALID will be set to
+     non-zero if this operand type can not actually be extracted from
+     this operand (i.e., the instruction does not match).  If the
+     operand is valid, *INVALID will not be changed.  */
+  long (*extract) PARAMS ((unsigned long instruction, int *invalid));
+
+  /* One bit syntax flags.  */
+  unsigned long flags;
+};
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the powerpc_opcodes table.  */
+
+extern const struct powerpc_operand powerpc_operands[];
+
+/* Values defined for the flags field of a struct powerpc_operand.  */
+
+/* This operand takes signed values.  */
+#define PPC_OPERAND_SIGNED (01)
+
+/* This operand takes signed values, but also accepts a full positive
+   range of values when running in 32 bit mode.  That is, if bits is
+   16, it takes any value from -0x8000 to 0xffff.  In 64 bit mode,
+   this flag is ignored.  */
+#define PPC_OPERAND_SIGNOPT (02)
+
+/* This operand does not actually exist in the assembler input.  This
+   is used to support extended mnemonics such as mr, for which two
+   operands fields are identical.  The assembler should call the
+   insert function with any op value.  The disassembler should call
+   the extract function, ignore the return value, and check the value
+   placed in the valid argument.  */
+#define PPC_OPERAND_FAKE (04)
+
+/* The next operand should be wrapped in parentheses rather than
+   separated from this one by a comma.  This is used for the load and
+   store instructions which want their operands to look like
+       reg,displacement(reg)
+   */
+#define PPC_OPERAND_PARENS (010)
+
+/* This operand may use the symbolic names for the CR fields, which
+   are
+       lt  0	gt  1	eq  2	so  3	un  3
+       cr0 0	cr1 1	cr2 2	cr3 3
+       cr4 4	cr5 5	cr6 6	cr7 7
+   These may be combined arithmetically, as in cr2*4+gt.  These are
+   only supported on the PowerPC, not the POWER.  */
+#define PPC_OPERAND_CR (020)
+
+/* This operand names a register.  The disassembler uses this to print
+   register names with a leading 'r'.  */
+#define PPC_OPERAND_GPR (040)
+
+/* This operand names a floating point register.  The disassembler
+   prints these with a leading 'f'.  */
+#define PPC_OPERAND_FPR (0100)
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_RELATIVE (0200)
+
+/* This operand is an absolute branch address.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_ABSOLUTE (0400)
+
+/* This operand is optional, and is zero if omitted.  This is used for
+   the optional BF and L fields in the comparison instructions.  The
+   assembler must count the number of operands remaining on the line,
+   and the number of operands remaining for the opcode, and decide
+   whether this operand is present or not.  The disassembler should
+   print this operand out only if it is not zero.  */
+#define PPC_OPERAND_OPTIONAL (01000)
+
+/* This flag is only used with PPC_OPERAND_OPTIONAL.  If this operand
+   is omitted, then for the next operand use this operand value plus
+   1, ignoring the next operand field for the opcode.  This wretched
+   hack is needed because the Power rotate instructions can take
+   either 4 or 5 operands.  The disassembler should print this operand
+   out regardless of the PPC_OPERAND_OPTIONAL field.  */
+#define PPC_OPERAND_NEXT (02000)
+
+/* This operand should be regarded as a negative number for the
+   purposes of overflow checking (i.e., the normal most negative
+   number is disallowed and one more than the normal most positive
+   number is allowed).  This flag will only be set for a signed
+   operand.  */
+#define PPC_OPERAND_NEGATIVE (04000)
+
+/* The POWER and PowerPC assemblers use a few macros.  We keep them
+   with the operands table for simplicity.  The macro table is an
+   array of struct powerpc_macro.  */
+
+struct powerpc_macro
+{
+  /* The macro name.  */
+  const char *name;
+
+  /* The number of operands the macro takes.  */
+  unsigned int operands;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The values are the
+     same as those for the struct powerpc_opcode flags field.  */
+  unsigned long flags;
+
+  /* A format string to turn the macro into a normal instruction.
+     Each %N in the string is replaced with operand number N (zero
+     based).  */
+  const char *format;
+};
+
+extern const struct powerpc_macro powerpc_macros[];
+extern const int powerpc_num_macros;
+
+#endif /* PPC_H */
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/privinst.h linux-2.4.19-pre5/arch/ppc64/xmon/privinst.h
--- linux-2.4.19-pre4/arch/ppc64/xmon/privinst.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/privinst.h	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+
+#define GETREG(reg)		\
+    static inline unsigned long get_ ## reg (void)	\
+	{ unsigned long ret; asm volatile ("mf" #reg " %0" : "=r" (ret) :); return ret; }
+
+#define SETREG(reg)		\
+    static inline void set_ ## reg (unsigned long val)	\
+	{ asm volatile ("mt" #reg " %0" : : "r" (val)); }
+
+GETREG(msr)
+SETREG(msrd)
+GETREG(cr)
+
+#define GSETSPR(n, name)	\
+    static inline long get_ ## name (void) \
+	{ long ret; asm volatile ("mfspr %0," #n : "=r" (ret) : ); return ret; } \
+    static inline void set_ ## name (long val) \
+	{ asm volatile ("mtspr " #n ",%0" : : "r" (val)); }
+
+GSETSPR(0, mq)
+GSETSPR(1, xer)
+GSETSPR(4, rtcu)
+GSETSPR(5, rtcl)
+GSETSPR(8, lr)
+GSETSPR(9, ctr)
+GSETSPR(18, dsisr)
+GSETSPR(19, dar)
+GSETSPR(22, dec)
+GSETSPR(25, sdr1)
+GSETSPR(26, srr0)
+GSETSPR(27, srr1)
+GSETSPR(272, sprg0)
+GSETSPR(273, sprg1)
+GSETSPR(274, sprg2)
+GSETSPR(275, sprg3)
+GSETSPR(282, ear)
+GSETSPR(287, pvr)
+GSETSPR(528, bat0u)
+GSETSPR(529, bat0l)
+GSETSPR(530, bat1u)
+GSETSPR(531, bat1l)
+GSETSPR(532, bat2u)
+GSETSPR(533, bat2l)
+GSETSPR(534, bat3u)
+GSETSPR(535, bat3l)
+GSETSPR(1008, hid0)
+GSETSPR(1009, hid1)
+GSETSPR(1010, iabr)
+GSETSPR(1013, dabr)
+GSETSPR(1023, pir)
+
+static inline int get_sr(int n)
+{
+	int ret;
+
+#if 0
+	// DRENG does not assemble 
+	asm (" mfsrin %0,%1" : "=r" (ret) : "r" (n << 28));
+#endif
+	return ret;
+}
+
+static inline void set_sr(int n, int val)
+{
+#if 0
+	// DRENG does not assemble 
+	asm ("mtsrin %0,%1" : : "r" (val), "r" (n << 28));
+#endif
+}
+
+static inline void store_inst(void *p)
+{
+	asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
+}
+
+static inline void cflush(void *p)
+{
+	asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
+}
+
+static inline void cinval(void *p)
+{
+	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/setjmp.c linux-2.4.19-pre5/arch/ppc64/xmon/setjmp.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/setjmp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/setjmp.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ * NB this file must be compiled with -O2.
+ */
+
+int
+xmon_setjmp(long *buf)  /* NOTE: assert(sizeof(buf) > 184) */
+{
+	/* XXX should save fp regs as well */
+	asm volatile (
+	"mflr 0; std 0,0(%0)\n\
+	 std	1,8(%0)\n\
+	 std	2,16(%0)\n\
+	 mfcr 0; std 0,24(%0)\n\
+	 std	13,32(%0)\n\
+	 std	14,40(%0)\n\
+	 std	15,48(%0)\n\
+	 std	16,56(%0)\n\
+	 std	17,64(%0)\n\
+	 std	18,72(%0)\n\
+	 std	19,80(%0)\n\
+	 std	20,88(%0)\n\
+	 std	21,96(%0)\n\
+	 std	22,104(%0)\n\
+	 std	23,112(%0)\n\
+	 std	24,120(%0)\n\
+	 std	25,128(%0)\n\
+	 std	26,136(%0)\n\
+	 std	27,144(%0)\n\
+	 std	28,152(%0)\n\
+	 std	29,160(%0)\n\
+	 std	30,168(%0)\n\
+	 std	31,176(%0)\n\
+	 " : : "r" (buf));
+    return 0;
+}
+
+void
+xmon_longjmp(long *buf, int val)
+{
+	if (val == 0)
+		val = 1;
+	asm volatile (
+	"ld	13,32(%0)\n\
+	 ld	14,40(%0)\n\
+	 ld	15,48(%0)\n\
+	 ld	16,56(%0)\n\
+	 ld	17,64(%0)\n\
+	 ld	18,72(%0)\n\
+	 ld	19,80(%0)\n\
+	 ld	20,88(%0)\n\
+	 ld	21,96(%0)\n\
+	 ld	22,104(%0)\n\
+	 ld	23,112(%0)\n\
+	 ld	24,120(%0)\n\
+	 ld	25,128(%0)\n\
+	 ld	26,136(%0)\n\
+	 ld	27,144(%0)\n\
+	 ld	28,152(%0)\n\
+	 ld	29,160(%0)\n\
+	 ld	30,168(%0)\n\
+	 ld	31,176(%0)\n\
+	 ld	0,24(%0)\n\
+	 mtcrf	0x38,0\n\
+	 ld	0,0(%0)\n\
+	 ld	1,8(%0)\n\
+	 ld	2,16(%0)\n\
+	 mtlr	0\n\
+	 mr	3,%1\n\
+	 " : : "r" (buf), "r" (val));
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/start.c linux-2.4.19-pre5/arch/ppc64/xmon/start.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/start.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/start.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/string.h>
+#include <asm/semaphore.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/kernel.h>
+#include <linux/sysrq.h>
+#include <asm/prom.h>
+#include <asm/processor.h>
+
+/* Transition to udbg isn't quite done yet...but very close. */
+#define USE_UDBG
+#ifdef USE_UDBG
+#include <asm/udbg.h>
+#endif
+
+#ifndef USE_UDBG
+static volatile unsigned char *sccc, *sccd;
+#endif
+unsigned long TXRDY, RXRDY;
+extern void xmon_printf(const char *fmt, ...);
+static int xmon_expect(const char *str, unsigned int timeout);
+
+#ifndef USE_UDBG
+static int console = 0;
+#endif
+static int via_modem = 0;
+/* static int xmon_use_sccb = 0;  --Unused */
+
+#define TB_SPEED	25000000
+
+extern void *comport1;
+static inline unsigned int readtb(void)
+{
+	unsigned int ret;
+
+	asm volatile("mftb %0" : "=r" (ret) :);
+	return ret;
+}
+
+#ifndef USE_UDBG
+void buf_access(void)
+{
+	sccd[3] &= ~0x80;	/* reset DLAB */
+}
+#endif
+
+extern int adb_init(void);
+
+static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) 
+{
+  xmon(pt_regs);
+}
+static struct sysrq_key_op sysrq_xmon_op = 
+{
+	handler:	sysrq_handle_xmon,
+	help_msg:	"xmon",
+	action_msg:	"Entering xmon\n",
+};
+
+void
+xmon_map_scc(void)
+{
+	/* This maybe isn't the best place to register sysrq 'x' */
+	__sysrq_put_key_op('x', &sysrq_xmon_op);
+#ifndef USE_UDBG
+	/* should already be mapped by the kernel boot */
+	sccd = (volatile unsigned char *) (((unsigned long)comport1));
+	sccc = (volatile unsigned char *) (((unsigned long)comport1)+5);
+	TXRDY = 0x20;
+	RXRDY = 1;
+#endif
+}
+
+static int scc_initialized = 0;
+
+void xmon_init_scc(void);
+extern void pmu_poll(void);
+
+int
+xmon_write(void *handle, void *ptr, int nb)
+{
+#ifdef USE_UDBG
+	return udbg_write(ptr, nb);
+#else
+	char *p = ptr;
+	int i, c, ct;
+
+	if (!scc_initialized)
+		xmon_init_scc();
+	ct = 0;
+	for (i = 0; i < nb; ++i) {
+		while ((*sccc & TXRDY) == 0) {
+		}
+		c = p[i];
+		if (c == '\n' && !ct) {
+			c = '\r';
+			ct = 1;
+			--i;
+		} else {
+			if (console)
+				printk("%c", c);
+			ct = 0;
+		}
+		buf_access();
+		*sccd = c;
+	}
+	return i;
+#endif
+}
+
+int xmon_wants_key;
+int xmon_adb_keycode;
+
+int
+xmon_read(void *handle, void *ptr, int nb)
+{
+#ifdef USE_UDBG
+	return udbg_read(ptr, nb);
+#else
+	char *p = ptr;
+	int i, c;
+
+	if (!scc_initialized)
+		xmon_init_scc();
+	for (i = 0; i < nb; ++i) {
+		do {
+			while ((*sccc & RXRDY) == 0)
+				;
+			buf_access();
+			c = *sccd;
+		} while (c == 0x11 || c == 0x13);
+		*p++ = c;
+	}
+	return i;
+#endif
+}
+
+int
+xmon_read_poll(void)
+{
+#ifdef USE_UDBG
+	return udbg_getc_poll();
+#else
+	if ((*sccc & RXRDY) == 0) {
+		return -1;
+	}
+	buf_access();
+	return *sccd;
+#endif
+}
+ 
+void
+xmon_init_scc()
+{
+#ifndef USE_UDBG
+	sccd[3] = 0x83; eieio();	/* LCR = 8N1 + DLAB */
+	sccd[0] = 12; eieio();		/* DLL = 9600 baud */
+	sccd[1] = 0; eieio();
+	sccd[2] = 0; eieio();		/* FCR = 0 */
+	sccd[3] = 3; eieio();		/* LCR = 8N1 */
+	sccd[1] = 0; eieio();		/* IER = 0 */
+#endif
+
+	scc_initialized = 1;
+	if (via_modem) {
+		for (;;) {
+			xmon_write(0, "ATE1V1\r", 7);
+			if (xmon_expect("OK", 5)) {
+				xmon_write(0, "ATA\r", 4);
+				if (xmon_expect("CONNECT", 40))
+					break;
+			}
+			xmon_write(0, "+++", 3);
+			xmon_expect("OK", 3);
+		}
+	}
+}
+
+void *xmon_stdin;
+void *xmon_stdout;
+void *xmon_stderr;
+
+void
+xmon_init(void)
+{
+}
+
+int
+xmon_putc(int c, void *f)
+{
+	char ch = c;
+
+	if (c == '\n')
+		xmon_putc('\r', f);
+	return xmon_write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+xmon_putchar(int c)
+{
+	return xmon_putc(c, xmon_stdout);
+}
+
+int
+xmon_fputs(char *str, void *f)
+{
+	int n = strlen(str);
+
+	return xmon_write(f, str, n) == n? 0: -1;
+}
+
+int
+xmon_readchar(void)
+{
+	char ch;
+
+	for (;;) {
+		switch (xmon_read(xmon_stdin, &ch, 1)) {
+		case 1:
+			return ch;
+		case -1:
+			xmon_printf("read(stdin) returned -1\r\n", 0, 0);
+			return -1;
+		}
+	}
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int xmon_expect(const char *str, unsigned int timeout)
+{
+	int c;
+	unsigned int t0;
+
+	timeout *= TB_SPEED;
+	t0 = readtb();
+	do {
+		lineptr = line;
+		for (;;) {
+			c = xmon_read_poll();
+			if (c == -1) {
+				if (readtb() - t0 > timeout)
+					return 0;
+				continue;
+			}
+			if (c == '\n')
+				break;
+			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
+				*lineptr++ = c;
+		}
+		*lineptr = 0;
+	} while (strstr(line, str) == NULL);
+	return 1;
+}
+
+int
+xmon_getchar(void)
+{
+	int c;
+
+	if (lineleft == 0) {
+		lineptr = line;
+		for (;;) {
+			c = xmon_readchar();
+			if (c == -1 || c == 4)
+				break;
+			if (c == '\r' || c == '\n') {
+				*lineptr++ = '\n';
+				xmon_putchar('\n');
+				break;
+			}
+			switch (c) {
+			case 0177:
+			case '\b':
+				if (lineptr > line) {
+					xmon_putchar('\b');
+					xmon_putchar(' ');
+					xmon_putchar('\b');
+					--lineptr;
+				}
+				break;
+			case 'U' & 0x1F:
+				while (lineptr > line) {
+					xmon_putchar('\b');
+					xmon_putchar(' ');
+					xmon_putchar('\b');
+					--lineptr;
+				}
+				break;
+			default:
+				if (lineptr >= &line[sizeof(line) - 1])
+					xmon_putchar('\a');
+				else {
+					xmon_putchar(c);
+					*lineptr++ = c;
+				}
+			}
+		}
+		lineleft = lineptr - line;
+		lineptr = line;
+	}
+	if (lineleft == 0)
+		return -1;
+	--lineleft;
+	return *lineptr++;
+}
+
+char *
+xmon_fgets(char *str, int nb, void *f)
+{
+	char *p;
+	int c;
+
+	for (p = str; p < str + nb - 1; ) {
+		c = xmon_getchar();
+		if (c == -1) {
+			if (p == str)
+				return 0;
+			break;
+		}
+		*p++ = c;
+		if (c == '\n')
+			break;
+	}
+	*p = 0;
+	return str;
+}
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/subr_prf.c linux-2.4.19-pre5/arch/ppc64/xmon/subr_prf.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/subr_prf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/subr_prf.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,55 @@
+/*
+ * Written by Cort Dougan to replace the version originally used
+ * by Paul Mackerras, which came from NetBSD and thus had copyright
+ * conflicts with Linux.
+ *
+ * This file makes liberal use of the standard linux utility
+ * routines to reduce the size of the binary.  We assume we can
+ * trust some parts of Linux inside the debugger.
+ *   -- Cort (cort@cs.nmt.edu)
+ *
+ * Copyright (C) 1999 Cort Dougan.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include "nonstdio.h"
+
+extern int xmon_write(void *, void *, int);
+
+void
+xmon_vfprintf(void *f, const char *fmt, va_list ap)
+{
+	static char xmon_buf[2048];
+	int n;
+
+	n = vsprintf(xmon_buf, fmt, ap);
+	xmon_write(f, xmon_buf, n);
+}
+
+void
+xmon_printf(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	xmon_vfprintf(stdout, fmt, ap);
+	va_end(ap);
+}
+
+void
+xmon_fprintf(void *f, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	xmon_vfprintf(f, fmt, ap);
+	va_end(ap);
+}
+
diff -urN linux-2.4.19-pre4/arch/ppc64/xmon/xmon.c linux-2.4.19-pre5/arch/ppc64/xmon/xmon.c
--- linux-2.4.19-pre4/arch/ppc64/xmon/xmon.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/arch/ppc64/xmon/xmon.c	Fri Mar 29 14:49:24 2002
@@ -0,0 +1,2945 @@
+/*
+ * Routines providing a simple monitor for use on the PowerMac.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <asm/ptrace.h>
+#include <asm/string.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/Naca.h>
+#include <asm/Paca.h>
+#include "nonstdio.h"
+#include "privinst.h"
+#include <linux/mm.h>
+
+#include <asm/ppcdebug.h>
+
+#include <asm/Paca.h>
+
+#define scanhex	xmon_scanhex
+#define skipbl	xmon_skipbl
+
+#ifdef CONFIG_SMP
+static unsigned long cpus_in_xmon = 0;
+static unsigned long got_xmon = 0;
+static volatile int take_xmon = -1;
+#endif /* CONFIG_SMP */
+
+static unsigned long adrs;
+static int size = 1;
+static unsigned long ndump = 64;
+static unsigned long nidump = 16;
+static unsigned long ncsum = 4096;
+static int termch;
+
+static u_int bus_error_jmp[100];
+#define setjmp xmon_setjmp
+#define longjmp xmon_longjmp
+
+#define memlist_entry list_entry
+#define memlist_next(x) ((x)->next)
+#define memlist_prev(x) ((x)->prev)
+
+
+/* Max number of stack frames we are willing to produce on a backtrace. */
+#define MAXFRAMECOUNT 50
+
+/* Breakpoint stuff */
+struct bpt {
+	unsigned long address;
+	unsigned instr;
+	unsigned long count;
+	unsigned char enabled;
+	char funcname[64];	/* function name for humans */
+};
+
+#define NBPTS	16
+static struct bpt bpts[NBPTS];
+static struct bpt dabr;
+static struct bpt iabr;
+static unsigned bpinstr = 0x7fe00008;	/* trap */
+
+/* Prototypes */
+extern void (*debugger_fault_handler)(struct pt_regs *);
+static int cmds(struct pt_regs *);
+static int mread(unsigned long, void *, int);
+static int mwrite(unsigned long, void *, int);
+static void handle_fault(struct pt_regs *);
+static void byterev(unsigned char *, int);
+static void memex(void);
+static int bsesc(void);
+static void dump(void);
+static void prdump(unsigned long, long);
+#ifdef __MWERKS__
+static void prndump(unsigned, int);
+static int nvreadb(unsigned);
+#endif
+static int ppc_inst_dump(unsigned long, long);
+void print_address(unsigned long);
+static int getsp(void);
+static void dump_hash_table(void);
+static void backtrace(struct pt_regs *);
+static void excprint(struct pt_regs *);
+static void prregs(struct pt_regs *);
+static void memops(int);
+static void memlocate(void);
+static void memzcan(void);
+static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
+int skipbl(void);
+int scanhex(unsigned long *valp);
+static void scannl(void);
+static int hexdigit(int);
+void getstring(char *, int);
+static void flush_input(void);
+static int inchar(void);
+static void take_input(char *);
+/* static void openforth(void); */
+static unsigned long read_spr(int);
+static void write_spr(int, unsigned long);
+static void super_regs(void);
+static void print_sysmap(void);
+static void remove_bpts(void);
+static void insert_bpts(void);
+static struct bpt *at_breakpoint(unsigned long pc);
+static void bpt_cmds(void);
+static void cacheflush(void);
+#ifdef CONFIG_SMP
+static void cpu_cmd(void);
+#endif /* CONFIG_SMP */
+static void csum(void);
+static void mem_translate(void);
+static void mem_check(void);
+static void mem_find_real(void);
+static void mem_find_vsid(void);
+static void mem_check_full_group(void);
+static void mem_check_pagetable_vsids (void);
+
+static void mem_map_check_slab(void);
+static void mem_map_lock_pages(void);
+static void mem_map_check_hash(void);
+static void mem_check_dup_rpn (void);
+static void show_task(struct task_struct * p);
+static void xmon_show_state(void);
+static void debug_trace(void);
+
+extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
+extern void printf(const char *fmt, ...);
+extern void xmon_vfprintf(void *f, const char *fmt, va_list ap);
+extern int xmon_putc(int c, void *f);
+extern int putchar(int ch);
+extern int xmon_read_poll(void);
+extern int setjmp(u_int *);
+extern void longjmp(u_int *, int);
+extern unsigned long _ASR;
+extern struct Naca *naca;
+
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);	/* from htab.c */
+
+#define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
+
+static char *help_string = "\
+Commands:\n\
+  b	show breakpoints\n\
+  bd	set data breakpoint\n\
+  bi	set instruction breakpoint\n\
+  bc	clear breakpoint\n\
+  d	dump bytes\n\
+  di	dump instructions\n\
+  df	dump float values\n\
+  dd	dump double values\n\
+  e	print exception information\n\
+  f	flush cache\n\
+  h	dump hash table\n\
+  m	examine/change memory\n\
+  mm	move a block of memory\n\
+  ms	set a block of memory\n\
+  md	compare two blocks of memory\n\
+  ml	locate a block of memory\n\
+  mz	zero a block of memory\n\
+  mx	translation information for an effective address\n\
+  mi	show information about memory allocation\n\
+  M	print System.map\n\
+  p 	show the task list\n\
+  r	print registers\n\
+  s	single step\n\
+  S	print special registers\n\
+  t	print backtrace\n\
+  T	Enable/Disable PPCDBG flags\n\
+  x	exit monitor\n\
+  z	reboot\n\
+";
+
+static int xmon_trace[NR_CPUS];
+#define SSTEP	1		/* stepping because of 's' command */
+#define BRSTEP	2		/* stepping over breakpoint */
+
+/*
+ * Stuff for reading and writing memory safely
+ */
+extern inline void sync(void)
+{
+	asm volatile("sync; isync");
+}
+
+extern inline void __delay(unsigned int loops)
+{
+	if (loops != 0)
+		__asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
+				     "r" (loops) : "ctr");
+}
+
+/* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs).
+ A PPC stack frame looks like this:
+
+ High Address
+    Back Chain
+    FP reg save area
+    GP reg save area
+    Local var space
+    Parameter save area		(SP+48)
+    TOC save area		(SP+40)
+    link editor doubleword	(SP+32)
+    compiler doubleword		(SP+24)
+    LR save			(SP+16)
+    CR save			(SP+8)
+    Back Chain			(SP+0)
+
+ Note that the LR (ret addr) may not be saved in the current frame if
+ no functions have been called from the current function.
+ */
+
+/*
+ A traceback table typically follows each function.
+ The find_tb_table() func will fill in this struct.  Note that the struct
+ is not an exact match with the encoded table defined by the ABI.  It is
+ defined here more for programming convenience.
+ */
+struct tbtable {
+	unsigned long	flags;		/* flags: */
+#define TBTAB_FLAGSGLOBALLINK	(1L<<47)
+#define TBTAB_FLAGSISEPROL	(1L<<46)
+#define TBTAB_FLAGSHASTBOFF	(1L<<45)
+#define TBTAB_FLAGSINTPROC	(1L<<44)
+#define TBTAB_FLAGSHASCTL	(1L<<43)
+#define TBTAB_FLAGSTOCLESS	(1L<<42)
+#define TBTAB_FLAGSFPPRESENT	(1L<<41)
+#define TBTAB_FLAGSNAMEPRESENT	(1L<<38)
+#define TBTAB_FLAGSUSESALLOCA	(1L<<37)
+#define TBTAB_FLAGSSAVESCR	(1L<<33)
+#define TBTAB_FLAGSSAVESLR	(1L<<32)
+#define TBTAB_FLAGSSTORESBC	(1L<<31)
+#define TBTAB_FLAGSFIXUP	(1L<<30)
+#define TBTAB_FLAGSPARMSONSTK	(1L<<0)
+	unsigned char	fp_saved;	/* num fp regs saved f(32-n)..f31 */
+	unsigned char	gpr_saved;	/* num gpr's saved */
+	unsigned char	fixedparms;	/* num fixed point parms */
+	unsigned char	floatparms;	/* num float parms */
+	unsigned char	parminfo[32];	/* types of args.  null terminated */
+#define TBTAB_PARMFIXED 1
+#define TBTAB_PARMSFLOAT 2
+#define TBTAB_PARMDFLOAT 3
+	unsigned int	tb_offset;	/* offset from start of func */
+	unsigned long	funcstart;	/* addr of start of function */
+	char		name[64];	/* name of function (null terminated)*/
+};
+static int find_tb_table(unsigned long codeaddr, struct tbtable *tab);
+
+void
+xmon(struct pt_regs *excp)
+{
+	struct pt_regs regs;
+	int cmd;
+	unsigned long msr;
+
+	if (excp == NULL) {
+		/* Ok, grab regs as they are now.
+		 This won't do a particularily good job because the
+		 prologue has already been executed.
+		 ToDo: We could reach back into the callers save
+		 area to do a better job of representing the
+		 caller's state.
+		 */
+		asm volatile ("std	0,0(%0)\n\
+			std	1,8(%0)\n\
+			std	2,16(%0)\n\
+			std	3,24(%0)\n\
+			std	4,32(%0)\n\
+			std	5,40(%0)\n\
+			std	6,48(%0)\n\
+			std	7,56(%0)\n\
+			std	8,64(%0)\n\
+			std	9,72(%0)\n\
+			std	10,80(%0)\n\
+			std	11,88(%0)\n\
+			std	12,96(%0)\n\
+			std	13,104(%0)\n\
+			std	14,112(%0)\n\
+			std	15,120(%0)\n\
+			std	16,128(%0)\n\
+			std	17,136(%0)\n\
+			std	18,144(%0)\n\
+			std	19,152(%0)\n\
+			std	20,160(%0)\n\
+			std	21,168(%0)\n\
+			std	22,176(%0)\n\
+			std	23,184(%0)\n\
+			std	24,192(%0)\n\
+			std	25,200(%0)\n\
+			std	26,208(%0)\n\
+			std	27,216(%0)\n\
+			std	28,224(%0)\n\
+			std	29,232(%0)\n\
+			std	30,240(%0)\n\
+			std	31,248(%0)" : : "b" (&regs));
+		printf("xmon called\n");
+		/* Fetch the link reg for this stack frame.
+		 NOTE: the prev printf fills in the lr. */
+		regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
+		regs.msr = get_msr();
+		regs.ctr = get_ctr();
+		regs.xer = get_xer();
+		regs.ccr = get_cr();
+		regs.trap = 0;
+		excp = &regs;
+	}
+
+	msr = get_msr();
+	set_msrd(msr & ~MSR_EE);	/* disable interrupts */
+	excprint(excp);
+#ifdef CONFIG_SMP
+	if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
+		for (;;)
+			;
+	while (test_and_set_bit(0, &got_xmon)) {
+		if (take_xmon == smp_processor_id()) {
+			take_xmon = -1;
+			break;
+		}
+	}
+	/*
+	 * XXX: breakpoints are removed while any cpu is in xmon
+	 */
+#endif /* CONFIG_SMP */
+	remove_bpts();
+	cmd = cmds(excp);
+	if (cmd == 's') {
+		xmon_trace[smp_processor_id()] = SSTEP;
+		excp->msr |= 0x400;
+	} else if (at_breakpoint(excp->nip)) {
+		xmon_trace[smp_processor_id()] = BRSTEP;
+		excp->msr |= 0x400;
+	} else {
+		xmon_trace[smp_processor_id()] = 0;
+		insert_bpts();
+	}
+#ifdef CONFIG_SMP
+	clear_bit(0, &got_xmon);
+	clear_bit(smp_processor_id(), &cpus_in_xmon);
+#endif /* CONFIG_SMP */
+	set_msrd(msr);		/* restore interrupt enable */
+}
+
+/* Code can call this to get a backtrace and continue. */
+void
+xmon_backtrace(const char *fmt, ...)
+{
+	va_list ap;
+	struct pt_regs regs;
+
+
+	/* Ok, grab regs as they are now.
+	 This won't do a particularily good job because the
+	 prologue has already been executed.
+	 ToDo: We could reach back into the callers save
+	 area to do a better job of representing the
+	 caller's state.
+	 */
+	asm volatile ("std	0,0(%0)\n\
+	    std	1,8(%0)\n\
+	    std	2,16(%0)\n\
+	    std	3,24(%0)\n\
+	    std	4,32(%0)\n\
+	    std	5,40(%0)\n\
+	    std	6,48(%0)\n\
+	    std	7,56(%0)\n\
+	    std	8,64(%0)\n\
+	    std	9,72(%0)\n\
+	    std	10,80(%0)\n\
+	    std	11,88(%0)\n\
+	    std	12,96(%0)\n\
+	    std	13,104(%0)\n\
+	    std	14,112(%0)\n\
+	    std	15,120(%0)\n\
+	    std	16,128(%0)\n\
+	    std	17,136(%0)\n\
+	    std	18,144(%0)\n\
+	    std	19,152(%0)\n\
+	    std	20,160(%0)\n\
+	    std	21,168(%0)\n\
+	    std	22,176(%0)\n\
+	    std	23,184(%0)\n\
+	    std	24,192(%0)\n\
+	    std	25,200(%0)\n\
+	    std	26,208(%0)\n\
+	    std	27,216(%0)\n\
+	    std	28,224(%0)\n\
+	    std	29,232(%0)\n\
+	    std	30,240(%0)\n\
+	    std	31,248(%0)" : : "b" (&regs));
+	/* Fetch the link reg for this stack frame.
+	 NOTE: the prev printf fills in the lr. */
+	regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
+	regs.msr = get_msr();
+	regs.ctr = get_ctr();
+	regs.xer = get_xer();
+	regs.ccr = get_cr();
+	regs.trap = 0;
+
+	va_start(ap, fmt);
+	xmon_vfprintf(stdout, fmt, ap);
+	xmon_putc('\n', stdout);
+	va_end(ap);
+	take_input("\n");
+	backtrace(&regs);
+}
+
+/* Call this to poll for ^C during busy operations.
+ * Returns true if the user has hit ^C.
+ */
+int
+xmon_interrupted(void)
+{
+	int ret = xmon_read_poll();
+	if (ret == 3) {
+		printf("\n^C interrupted.\n");
+		return 1;
+	}
+	return 0;
+}
+
+
+void
+xmon_irq(int irq, void *d, struct pt_regs *regs)
+{
+	unsigned long flags;
+	__save_flags(flags);
+	__cli();
+	printf("Keyboard interrupt\n");
+	xmon(regs);
+	__restore_flags(flags);
+}
+
+int
+xmon_bpt(struct pt_regs *regs)
+{
+	struct bpt *bp;
+
+	bp = at_breakpoint(regs->nip);
+	if (!bp)
+		return 0;
+	if (bp->count) {
+		--bp->count;
+		remove_bpts();
+		excprint(regs);
+		xmon_trace[smp_processor_id()] = BRSTEP;
+		regs->msr |= 0x400;
+	} else {
+		printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
+		xmon(regs);
+	}
+	return 1;
+}
+
+int
+xmon_sstep(struct pt_regs *regs)
+{
+	if (!xmon_trace[smp_processor_id()])
+		return 0;
+	if (xmon_trace[smp_processor_id()] == BRSTEP) {
+		xmon_trace[smp_processor_id()] = 0;
+		insert_bpts();
+	} else {
+		xmon(regs);
+	}
+	return 1;
+}
+
+int
+xmon_dabr_match(struct pt_regs *regs)
+{
+	if (dabr.enabled && dabr.count) {
+		--dabr.count;
+		remove_bpts();
+		excprint(regs);
+		xmon_trace[smp_processor_id()] = BRSTEP;
+		regs->msr |= 0x400;
+	} else {
+		dabr.instr = regs->nip;
+		xmon(regs);
+	}
+	return 1;
+}
+
+int
+xmon_iabr_match(struct pt_regs *regs)
+{
+	if (iabr.enabled && iabr.count) {
+		--iabr.count;
+		remove_bpts();
+		excprint(regs);
+		xmon_trace[smp_processor_id()] = BRSTEP;
+		regs->msr |= 0x400;
+	} else {
+		xmon(regs);
+	}
+	return 1;
+}
+
+static struct bpt *
+at_breakpoint(unsigned long pc)
+{
+	int i;
+	struct bpt *bp;
+
+	if (dabr.enabled && pc == dabr.instr)
+		return &dabr;
+	if (iabr.enabled && pc == iabr.address)
+		return &iabr;
+	bp = bpts;
+	for (i = 0; i < NBPTS; ++i, ++bp)
+		if (bp->enabled && pc == bp->address)
+			return bp;
+	return 0;
+}
+
+static void
+insert_bpts()
+{
+	int i;
+	struct bpt *bp;
+
+	if (_machine != _MACH_pSeries)
+		return;
+	bp = bpts;
+	for (i = 0; i < NBPTS; ++i, ++bp) {
+		if (!bp->enabled)
+			continue;
+		if (mread(bp->address, &bp->instr, 4) != 4
+		    || mwrite(bp->address, &bpinstr, 4) != 4) {
+			printf("Couldn't insert breakpoint at %x, disabling\n",
+			       bp->address);
+			bp->enabled = 0;
+		} else {
+			store_inst((void *)bp->address);
+		}
+	}
+
+	if (!__is_processor(PV_POWER4)) {
+		if (dabr.enabled)
+			set_dabr(dabr.address);
+		if (iabr.enabled)
+			set_iabr(iabr.address);
+	}
+}
+
+static void
+remove_bpts()
+{
+	int i;
+	struct bpt *bp;
+	unsigned instr;
+
+	if (_machine != _MACH_pSeries)
+		return;
+	if (!__is_processor(PV_POWER4)) {
+		set_dabr(0);
+		set_iabr(0);
+	}
+
+	bp = bpts;
+	for (i = 0; i < NBPTS; ++i, ++bp) {
+		if (!bp->enabled)
+			continue;
+		if (mread(bp->address, &instr, 4) == 4
+		    && instr == bpinstr
+		    && mwrite(bp->address, &bp->instr, 4) != 4)
+			printf("Couldn't remove breakpoint at %x\n",
+			       bp->address);
+		else
+			store_inst((void *)bp->address);
+	}
+}
+
+static char *last_cmd;
+
+/* Command interpreting routine */
+static int
+cmds(struct pt_regs *excp)
+{
+	int cmd;
+
+	last_cmd = NULL;
+	for(;;) {
+#ifdef CONFIG_SMP
+		printf("%d:", smp_processor_id());
+#endif /* CONFIG_SMP */
+		printf("mon> ");
+		fflush(stdout);
+		flush_input();
+		termch = 0;
+		cmd = skipbl();
+		if( cmd == '\n' ) {
+			if (last_cmd == NULL)
+				continue;
+			take_input(last_cmd);
+			last_cmd = NULL;
+			cmd = inchar();
+		}
+		switch (cmd) {
+		case 'z':
+			machine_restart(NULL);
+			break;
+		case 'm':
+			cmd = inchar();
+			switch (cmd) {
+			case 'm':
+			case 's':
+			case 'd':
+				memops(cmd);
+				break;
+			case 'l':
+				memlocate();
+				break;
+			case 'z':
+				memzcan();
+				break;
+			case 'x':
+				mem_translate();
+				break;
+			case 'c':
+				mem_check();
+				break;
+			case 'g':
+				mem_check_full_group();
+				break;
+			case 'j':
+				mem_map_check_slab();
+				break;
+			case 'h':
+				mem_map_check_hash();
+				break;
+			case 'f':
+				mem_find_real();
+				break;
+			case 'e':
+				mem_find_vsid();
+				break;
+			case 'r':
+				mem_check_dup_rpn();
+				break;           
+			case 'i':
+				show_mem();
+				break;
+			case 'o':
+				mem_check_pagetable_vsids ();
+				break;
+			case 'q':
+				mem_map_lock_pages() ;
+				break;
+			default:
+				termch = cmd;
+				memex();
+			}
+			break;
+		case 'd':
+			dump();
+			break;
+		case 'r':
+			if (excp != NULL)
+				prregs(excp);	/* print regs */
+			break;
+		case 'e':
+			if (excp == NULL)
+				printf("No exception information\n");
+			else
+				excprint(excp);
+			break;
+		case 'M':
+			print_sysmap();
+			break;
+		case 'S':
+			super_regs();
+			break;
+		case 't':
+			backtrace(excp);
+			break;
+		case 'f':
+			cacheflush();
+			break;
+		case 'h':
+			dump_hash_table();
+			break;
+		case 's':
+		case 'x':
+		case EOF:
+			return cmd;
+		case '?':
+			printf(help_string);
+			break;
+		case 'p':
+			xmon_show_state();
+			break;
+		case 'b':
+			bpt_cmds();
+			break;
+		case 'C':
+			csum();
+			break;
+#ifdef CONFIG_SMP
+		case 'c':
+			cpu_cmd();
+			break;
+#endif /* CONFIG_SMP */
+		case 'T':
+			debug_trace();
+			break;
+		default:
+			printf("Unrecognized command: ");
+		        do {
+				if( ' ' < cmd && cmd <= '~' )
+					putchar(cmd);
+				else
+					printf("\\x%x", cmd);
+				cmd = inchar();
+		        } while (cmd != '\n'); 
+			printf(" (type ? for help)\n");
+			break;
+		}
+	}
+}
+
+#ifdef CONFIG_SMP
+static void cpu_cmd(void)
+{
+	unsigned long cpu;
+	int timeout;
+	int cmd;
+
+	cmd = inchar();
+	if (cmd == 'i') {
+		printf("stopping all cpus\n");
+		/* interrupt other cpu(s) */
+		cpu = MSG_ALL_BUT_SELF;
+		smp_send_xmon_break(cpu);
+		return;
+	}
+	termch = cmd;
+	if (!scanhex(&cpu)) {
+		/* print cpus waiting or in xmon */
+		printf("cpus stopped:");
+		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+			if (test_bit(cpu, &cpus_in_xmon)) {
+				printf(" %d", cpu);
+				if (cpu == smp_processor_id())
+					printf("*", cpu);
+			}
+		}
+		printf("\n");
+		return;
+	}
+	/* try to switch to cpu specified */
+	take_xmon = cpu;
+	timeout = 10000000;
+	while (take_xmon >= 0) {
+		if (--timeout == 0) {
+			/* yes there's a race here */
+			take_xmon = -1;
+			printf("cpu %u didn't take control\n", cpu);
+			return;
+		}
+	}
+	/* now have to wait to be given control back */
+	while (test_and_set_bit(0, &got_xmon)) {
+		if (take_xmon == smp_processor_id()) {
+			take_xmon = -1;
+			break;
+		}
+	}
+}
+#endif /* CONFIG_SMP */
+
+static unsigned short fcstab[256] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+static void
+csum(void)
+{
+	unsigned int i;
+	unsigned short fcs;
+	unsigned char v;
+
+	if (!scanhex(&adrs))
+		return;
+	if (!scanhex(&ncsum))
+		return;
+	fcs = 0xffff;
+	for (i = 0; i < ncsum; ++i) {
+		if (mread(adrs+i, &v, 1) == 0) {
+			printf("csum stopped at %x\n", adrs+i);
+			break;
+		}
+		fcs = FCS(fcs, v);
+	}
+	printf("%x\n", fcs);
+}
+
+static char *breakpoint_help_string = 
+    "Breakpoint command usage:\n"
+    "b                show breakpoints\n"
+    "b <addr> [cnt]   set breakpoint at given instr addr\n"
+    "bc               clear all breakpoints\n"
+    "bc <n/addr>      clear breakpoint number n or at addr\n"
+    "bi <addr> [cnt]  set hardware instr breakpoint (broken?)\n"
+    "bd <addr> [cnt]  set hardware data breakpoint (broken?)\n"
+    "";
+
+static void
+bpt_cmds(void)
+{
+	int cmd;
+	unsigned long a;
+	int mode, i;
+	struct bpt *bp;
+	struct tbtable tab;
+
+	cmd = inchar();
+	switch (cmd) {
+	case 'd':	/* bd - hardware data breakpoint */
+		if (__is_processor(PV_POWER4)) {
+			printf("Not implemented on POWER4\n");
+			break;
+		}
+		mode = 7;
+		cmd = inchar();
+		if (cmd == 'r')
+			mode = 5;
+		else if (cmd == 'w')
+			mode = 6;
+		else
+			termch = cmd;
+		dabr.address = 0;
+		dabr.count = 0;
+		dabr.enabled = scanhex(&dabr.address);
+		scanhex(&dabr.count);
+		if (dabr.enabled)
+			dabr.address = (dabr.address & ~7) | mode;
+		break;
+	case 'i':	/* bi - hardware instr breakpoint */
+		if (__is_processor(PV_POWER4)) {
+			printf("Not implemented on POWER4\n");
+			break;
+		}
+		iabr.address = 0;
+		iabr.count = 0;
+		iabr.enabled = scanhex(&iabr.address);
+		if (iabr.enabled)
+			iabr.address |= 3;
+		scanhex(&iabr.count);
+		break;
+	case 'c':
+		if (!scanhex(&a)) {
+			/* clear all breakpoints */
+			for (i = 0; i < NBPTS; ++i)
+				bpts[i].enabled = 0;
+			iabr.enabled = 0;
+			dabr.enabled = 0;
+			printf("All breakpoints cleared\n");
+		} else {
+			if (a <= NBPTS && a >= 1) {
+				/* assume a breakpoint number */
+				--a;	/* bp nums are 1 based */
+				bp = &bpts[a];
+			} else {
+				/* assume a breakpoint address */
+				bp = at_breakpoint(a);
+			}
+			if (bp == 0) {
+				printf("No breakpoint at %x\n", a);
+			} else {
+				printf("Cleared breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
+				bp->enabled = 0;
+			}
+		}
+		break;
+	case '?':
+	        printf(breakpoint_help_string);
+	        break;
+	default:
+		termch = cmd;
+	        cmd = skipbl();
+		if (cmd == '?') {
+			printf(breakpoint_help_string);
+			break;
+		}
+		termch = cmd;
+		if (!scanhex(&a)) {
+			/* print all breakpoints */
+			int bpnum;
+
+			printf("   type            address    count\n");
+			if (dabr.enabled) {
+				printf("   data   %.16lx %8x [", dabr.address & ~7,
+				       dabr.count);
+				if (dabr.address & 1)
+					printf("r");
+				if (dabr.address & 2)
+					printf("w");
+				printf("]\n");
+			}
+			if (iabr.enabled)
+				printf("   inst   %.16lx %8x\n", iabr.address & ~3,
+				       iabr.count);
+			for (bp = bpts, bpnum = 1; bp < &bpts[NBPTS]; ++bp, ++bpnum)
+				if (bp->enabled)
+					printf("%2x trap   %.16lx %8x  %s\n", bpnum, bp->address, bp->count, bp->funcname);
+			break;
+		}
+		bp = at_breakpoint(a);
+		if (bp == 0) {
+			for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
+				if (!bp->enabled)
+					break;
+			if (bp >= &bpts[NBPTS]) {
+				printf("Sorry, no free breakpoints.  Please clear one first.\n");
+				break;
+			}
+		}
+		bp->enabled = 1;
+		bp->address = a;
+		bp->count = 0;
+		scanhex(&bp->count);
+		/* Find the function name just once. */
+		bp->funcname[0] = '\0';
+		if (find_tb_table(bp->address, &tab) && tab.name[0]) {
+			/* Got a nice name for it. */
+			int delta = bp->address - tab.funcstart;
+			sprintf(bp->funcname, "%s+0x%x", tab.name, delta);
+		}
+		printf("Set breakpoint %2x trap   %.16lx %8x  %s\n", (bp-bpts)+1, bp->address, bp->count, bp->funcname);
+		break;
+	}
+}
+
+/* Very cheap human name for vector lookup. */
+static
+const char *getvecname(unsigned long vec)
+{
+	char *ret;
+	switch (vec) {
+	case 0x100:	ret = "(System Reset)"; break; 
+	case 0x200:	ret = "(Machine Check)"; break; 
+	case 0x300:	ret = "(Data Access)"; break; 
+	case 0x400:	ret = "(Instruction Access)"; break; 
+	case 0x500:	ret = "(Hardware Interrupt)"; break; 
+	case 0x600:	ret = "(Alignment)"; break; 
+	case 0x700:	ret = "(Program Check)"; break; 
+	case 0x800:	ret = "(FPU Unavailable)"; break; 
+	case 0x900:	ret = "(Decrementer)"; break; 
+	case 0xc00:	ret = "(System Call)"; break; 
+	case 0xd00:	ret = "(Single Step)"; break; 
+	case 0xf00:	ret = "(Performance Monitor)"; break; 
+	default: ret = "";
+	}
+	return ret;
+}
+
+static void
+backtrace(struct pt_regs *excp)
+{
+	unsigned long sp;
+	unsigned long lr;
+	unsigned long stack[3];
+	struct pt_regs regs;
+	struct tbtable tab;
+	int framecount;
+	char *funcname;
+	/* declare these as raw ptrs so we don't get func descriptors */
+	extern void *ret_from_except, *ret_from_syscall_1;
+
+	if (excp != NULL) {
+	        lr = excp->link;
+		sp = excp->gpr[1];
+	} else {
+	        /* Use care not to call any function before this point
+		 so the saved lr has a chance of being good. */
+	        asm volatile ("mflr %0" : "=r" (lr) :);
+		sp = getsp();
+	}
+	scanhex(&sp);
+	scannl();
+	for (framecount = 0;
+	     sp != 0 && framecount < MAXFRAMECOUNT;
+	     sp = stack[0], framecount++) {
+		if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
+			break;
+#if 0
+		if (lr != 0) {
+		    stack[2] = lr;	/* fake out the first saved lr.  It may not be saved yet. */
+		    lr = 0;
+		}
+#endif
+		printf("%.16lx  %.16lx", sp, stack[2]);
+		/* TAI -- for now only the ones cast to unsigned long will match.
+		 * Need to test the rest...
+		 */
+		if ((stack[2] == (unsigned long)ret_from_except &&
+		            (funcname = "ret_from_except"))
+		    || (stack[2] == (unsigned long)ret_from_syscall_1 &&
+		            (funcname = "ret_from_syscall_1"))
+#if 0
+		    || stack[2] == (unsigned) &ret_from_syscall_2
+		    || stack[2] == (unsigned) &do_bottom_half_ret
+		    || stack[2] == (unsigned) &do_signal_ret
+#endif
+		    ) {
+			printf("  %s\n", funcname);
+			if (mread(sp+112, &regs, sizeof(regs)) != sizeof(regs))
+				break;
+			printf("exception: %lx %s regs %lx\n", regs.trap, getvecname(regs.trap), sp+112);
+			printf("                  %.16lx", regs.nip);
+			if ((regs.nip & 0xffffffff00000000UL) &&
+			    find_tb_table(regs.nip, &tab)) {
+				int delta = regs.nip-tab.funcstart;
+				if (delta < 0)
+					printf("  <unknown code>");
+				else
+					printf("  %s+0x%x", tab.name, delta);
+			}
+			printf("\n");
+                        if (regs.gpr[1] < sp) {
+                            printf("<Stack drops into 32-bit userspace %.16lx>\n", regs.gpr[1]);
+                            break;
+			}
+
+			sp = regs.gpr[1];
+			if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
+				break;
+		} else {
+			if (stack[2] && find_tb_table(stack[2], &tab)) {
+				int delta = stack[2]-tab.funcstart;
+				if (delta < 0)
+					printf("  <unknown code>");
+				else
+					printf("  %s+0x%x", tab.name, delta);
+			}
+			printf("\n");
+		}
+		if (stack[0] && stack[0] <= sp) {
+			if ((stack[0] & 0xffffffff00000000UL) == 0)
+				printf("<Stack drops into 32-bit userspace %.16lx>\n", stack[0]);
+			else
+				printf("<Corrupt stack.  Next backchain is %.16lx>\n", stack[0]);
+			break;
+		}
+	}
+	if (framecount >= MAXFRAMECOUNT)
+		printf("<Punt. Too many stack frames>\n");
+}
+
+int
+getsp()
+{
+	int x;
+
+	asm("mr %0,1" : "=r" (x) :);
+	return x;
+}
+
+spinlock_t exception_print_lock = SPIN_LOCK_UNLOCKED;
+
+void
+excprint(struct pt_regs *fp)
+{
+	struct task_struct *c;
+	struct tbtable tab;
+	unsigned long flags;
+
+	spin_lock_irqsave(&exception_print_lock, flags);
+
+#ifdef CONFIG_SMP
+	printf("cpu %d: ", smp_processor_id());
+#endif /* CONFIG_SMP */
+
+	printf("Vector: %lx %s at  [%lx]\n", fp->trap, getvecname(fp->trap), fp);
+	printf("    pc: %lx", fp->nip);
+	if (find_tb_table(fp->nip, &tab) && tab.name[0]) {
+		/* Got a nice name for it */
+		int delta = fp->nip - tab.funcstart;
+		printf(" (%s+0x%x)", tab.name, delta);
+	}
+	printf("\n");
+	printf("    lr: %lx", fp->link);
+	if (find_tb_table(fp->link, &tab) && tab.name[0]) {
+		/* Got a nice name for it */
+		int delta = fp->link - tab.funcstart;
+		printf(" (%s+0x%x)", tab.name, delta);
+	}
+	printf("\n");
+	printf("    sp: %lx\n", fp->gpr[1]);
+	printf("   msr: %lx\n", fp->msr);
+
+	if (fp->trap == 0x300 || fp->trap == 0x600) {
+		printf("   dar: %lx\n", fp->dar);
+		printf(" dsisr: %lx\n", fp->dsisr);
+	}
+
+	/* XXX: need to copy current or we die.  Why? */
+	c = current;
+	printf("  current = 0x%lx\n", c);
+	printf("  paca    = 0x%lx\n", get_paca());
+	if (c) {
+		printf("  current = %lx, pid = %ld, comm = %s\n",
+		       c, c->pid, c->comm);
+	}
+
+	spin_unlock_irqrestore(&exception_print_lock, flags);
+}
+
+void
+prregs(struct pt_regs *fp)
+{
+	int n;
+	unsigned long base;
+
+	if (scanhex((void *)&base))
+		fp = (struct pt_regs *) base;
+	for (n = 0; n < 16; ++n)
+		printf("R%.2ld = %.16lx   R%.2ld = %.16lx\n", n, fp->gpr[n],
+		       n+16, fp->gpr[n+16]);
+	printf("pc  = %.16lx   msr = %.16lx\nlr  = %.16lx   cr  = %.16lx\n",
+	       fp->nip, fp->msr, fp->link, fp->ccr);
+	printf("ctr = %.16lx   xer = %.16lx   trap = %8lx\n",
+	       fp->ctr, fp->xer, fp->trap);
+}
+
+void
+cacheflush(void)
+{
+	int cmd;
+	unsigned long nflush;
+
+	cmd = inchar();
+	if (cmd != 'i')
+		termch = cmd;
+	scanhex((void *)&adrs);
+	if (termch != '\n')
+		termch = 0;
+	nflush = 1;
+	scanhex(&nflush);
+	nflush = (nflush + 31) / 32;
+	if (cmd != 'i') {
+		for (; nflush > 0; --nflush, adrs += 0x20)
+			cflush((void *) adrs);
+	} else {
+		for (; nflush > 0; --nflush, adrs += 0x20)
+			cinval((void *) adrs);
+	}
+}
+
+unsigned long
+read_spr(int n)
+{
+	unsigned int instrs[2];
+	unsigned long (*code)(void);
+	unsigned long opd[3];
+
+	instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
+	instrs[1] = 0x4e800020;
+	opd[0] = instrs;
+	opd[1] = 0;
+	opd[2] = 0;
+	store_inst(instrs);
+	store_inst(instrs+1);
+	code = (unsigned long (*)(void)) opd;
+
+	return code();
+}
+
+void
+write_spr(int n, unsigned long val)
+{
+	unsigned int instrs[2];
+	unsigned long (*code)(unsigned long);
+	unsigned long opd[3];
+
+	instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
+	instrs[1] = 0x4e800020;
+	opd[0] = instrs;
+	opd[1] = 0;
+	opd[2] = 0;
+	store_inst(instrs);
+	store_inst(instrs+1);
+	code = (unsigned long (*)(unsigned long)) opd;
+
+	code(val);
+}
+
+static unsigned long regno;
+extern char exc_prolog;
+extern char dec_exc;
+
+void
+print_sysmap(void)
+{
+	extern char *sysmap;
+	if ( sysmap )
+		printf("System.map: \n%s", sysmap);
+}
+
+void
+super_regs()
+{
+	int i, cmd;
+	unsigned long val;
+	struct Paca*  ptrPaca = NULL;
+	struct ItLpPaca*  ptrLpPaca = NULL;
+	struct ItLpRegSave*  ptrLpRegSave = NULL;
+
+	cmd = skipbl();
+	if (cmd == '\n') {
+	        unsigned long sp, toc;
+		asm("mr %0,1" : "=r" (sp) :);
+		asm("mr %0,2" : "=r" (toc) :);
+
+		printf("msr  = %.16lx  sprg0= %.16lx\n", get_msr(), get_sprg0());
+		printf("pvr  = %.16lx  sprg1= %.16lx\n", get_pvr(), get_sprg1()); 
+		printf("dec  = %.16lx  sprg2= %.16lx\n", get_dec(), get_sprg2());
+		printf("sp   = %.16lx  sprg3= %.16lx\n", sp, get_sprg3());
+		printf("toc  = %.16lx  dar  = %.16lx\n", toc, get_dar());
+		printf("srr0 = %.16lx  srr1 = %.16lx\n", get_srr0(), get_srr1());
+		printf("asr  = %.16lx\n", mfasr());
+		for (i = 0; i < 8; ++i)
+			printf("sr%.2ld = %.16lx  sr%.2ld = %.16lx\n", i, get_sr(i), i+8, get_sr(i+8));
+
+		// Dump out relevant Paca data areas.
+		printf("Paca: \n");
+		ptrPaca = (struct Paca*)get_sprg3();
+    
+		printf("  Local Processor Control Area (LpPaca): \n");
+		ptrLpPaca = ptrPaca->xLpPacaPtr;
+		printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n", ptrLpPaca->xSavedSrr0, ptrLpPaca->xSavedSrr1);
+		printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n", ptrLpPaca->xSavedGpr3, ptrLpPaca->xSavedGpr4);
+		printf("    Saved Gpr5=%.16lx \n", ptrLpPaca->xSavedGpr5);
+    
+		printf("  Local Processor Register Save Area (LpRegSave): \n");
+		ptrLpRegSave = ptrPaca->xLpRegSavePtr;
+		printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n", ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
+		printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n", ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
+		printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n", ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
+    
+		return;
+	}
+
+	scanhex(&regno);
+	switch (cmd) {
+	case 'w':
+		val = read_spr(regno);
+		scanhex(&val);
+		write_spr(regno, val);
+		/* fall through */
+	case 'r':
+		printf("spr %lx = %lx\n", regno, read_spr(regno));
+		break;
+	case 's':
+		val = get_sr(regno);
+		scanhex(&val);
+		set_sr(regno, val);
+		break;
+	case 'm':
+		val = get_msr();
+		scanhex(&val);
+		set_msrd(val);
+		break;
+	}
+	scannl();
+}
+
+#if 0
+static void
+openforth()
+{
+	int c;
+	char *p;
+	char cmd[1024];
+	int args[5];
+	extern int (*prom_entry)(int *);
+
+	p = cmd;
+	c = skipbl();
+	while (c != '\n') {
+		*p++ = c;
+		c = inchar();
+	}
+	*p = 0;
+	args[0] = (int) "interpret";
+	args[1] = 1;
+	args[2] = 1;
+	args[3] = (int) cmd;
+	(*prom_entry)(args);
+	printf("\n");
+	if (args[4] != 0)
+		printf("error %x\n", args[4]);
+}
+#endif
+
+#ifndef CONFIG_PPC64BRIDGE
+static void
+dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
+{
+	extern void *Hash;
+	extern unsigned long Hash_size;
+	unsigned *htab = Hash;
+	unsigned hsize = Hash_size;
+	unsigned v, hmask, va, last_va;
+	int found, last_found, i;
+	unsigned *hg, w1, last_w2, last_va0;
+
+	last_found = 0;
+	hmask = hsize / 64 - 1;
+	va = start;
+	start = (start >> 12) & 0xffff;
+	end = (end >> 12) & 0xffff;
+	for (v = start; v < end; ++v) {
+		found = 0;
+		hg = htab + (((v ^ seg) & hmask) * 16);
+		w1 = 0x80000000 | (seg << 7) | (v >> 10);
+		for (i = 0; i < 8; ++i, hg += 2) {
+			if (*hg == w1) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			w1 ^= 0x40;
+			hg = htab + ((~(v ^ seg) & hmask) * 16);
+			for (i = 0; i < 8; ++i, hg += 2) {
+				if (*hg == w1) {
+					found = 1;
+					break;
+				}
+			}
+		}
+		if (!(last_found && found && (hg[1] & ~0x180) == last_w2 + 4096)) {
+			if (last_found) {
+				if (last_va != last_va0)
+					printf(" ... %x", last_va);
+				printf("\n");
+			}
+			if (found) {
+				printf("%x to %x", va, hg[1]);
+				last_va0 = va;
+			}
+			last_found = found;
+		}
+		if (found) {
+			last_w2 = hg[1] & ~0x180;
+			last_va = va;
+		}
+		va += 4096;
+	}
+	if (last_found)
+		printf(" ... %x\n", last_va);
+}
+
+#else /* CONFIG_PPC64BRIDGE */
+static void
+dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
+{
+	extern void *Hash;
+	extern unsigned long Hash_size;
+	unsigned *htab = Hash;
+	unsigned hsize = Hash_size;
+	unsigned v, hmask, va, last_va;
+	int found, last_found, i;
+	unsigned *hg, w1, last_w2, last_va0;
+
+	last_found = 0;
+	hmask = hsize / 128 - 1;
+	va = start;
+	start = (start >> 12) & 0xffff;
+	end = (end >> 12) & 0xffff;
+	for (v = start; v < end; ++v) {
+		found = 0;
+		hg = htab + (((v ^ seg) & hmask) * 32);
+		w1 = 1 | (seg << 12) | ((v & 0xf800) >> 4);
+		for (i = 0; i < 8; ++i, hg += 4) {
+			if (hg[1] == w1) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			w1 ^= 2;
+			hg = htab + ((~(v ^ seg) & hmask) * 32);
+			for (i = 0; i < 8; ++i, hg += 4) {
+				if (hg[1] == w1) {
+					found = 1;
+					break;
+				}
+			}
+		}
+		if (!(last_found && found && (hg[3] & ~0x180) == last_w2 + 4096)) {
+			if (last_found) {
+				if (last_va != last_va0)
+					printf(" ... %x", last_va);
+				printf("\n");
+			}
+			if (found) {
+				printf("%x to %x", va, hg[3]);
+				last_va0 = va;
+			}
+			last_found = found;
+		}
+		if (found) {
+			last_w2 = hg[3] & ~0x180;
+			last_va = va;
+		}
+		va += 4096;
+	}
+	if (last_found)
+		printf(" ... %x\n", last_va);
+}
+#endif /* CONFIG_PPC64BRIDGE */
+
+static unsigned long hash_ctx;
+static unsigned long hash_start;
+static unsigned long hash_end;
+
+static void
+dump_hash_table()
+{
+	int seg;
+	unsigned seg_start, seg_end;
+
+	hash_ctx = 0;
+	hash_start = 0;
+	hash_end = 0xfffff000;
+	scanhex(&hash_ctx);
+	scanhex(&hash_start);
+	scanhex(&hash_end);
+	printf("Mappings for context %x\n", hash_ctx);
+	seg_start = hash_start;
+	for (seg = hash_start >> 28; seg <= hash_end >> 28; ++seg) {
+		seg_end = (seg << 28) | 0x0ffff000;
+		if (seg_end > hash_end)
+			seg_end = hash_end;
+		dump_hash_table_seg((hash_ctx << 4) + seg, seg_start, seg_end);
+		seg_start = seg_end + 0x1000;
+	}
+}
+
+int
+mread(unsigned long adrs, void *buf, int size)
+{
+	volatile int n;
+	char *p, *q;
+
+	n = 0;
+	if( setjmp(bus_error_jmp) == 0 ){
+		debugger_fault_handler = handle_fault;
+		sync();
+		p = (char *) adrs;
+		q = (char *) buf;
+		switch (size) {
+		case 2: *(short *)q = *(short *)p;	break;
+		case 4: *(int *)q = *(int *)p;		break;
+		default:
+			for( ; n < size; ++n ) {
+				*q++ = *p++;
+				sync();
+			}
+		}
+		sync();
+		/* wait a little while to see if we get a machine check */
+		__delay(200);
+		n = size;
+	}
+	debugger_fault_handler = 0;
+	return n;
+}
+
+int
+mwrite(unsigned long adrs, void *buf, int size)
+{
+	volatile int n;
+	char *p, *q;
+
+	n = 0;
+	if( setjmp(bus_error_jmp) == 0 ){
+		debugger_fault_handler = handle_fault;
+		sync();
+		p = (char *) adrs;
+		q = (char *) buf;
+		switch (size) {
+		case 2: *(short *)p = *(short *)q;	break;
+		case 4: *(int *)p = *(int *)q;		break;
+		default:
+			for( ; n < size; ++n ) {
+				*p++ = *q++;
+				sync();
+			}
+		}
+		sync();
+		/* wait a little while to see if we get a machine check */
+		__delay(200);
+		n = size;
+	} else {
+		printf("*** Error writing address %x\n", adrs + n);
+	}
+	debugger_fault_handler = 0;
+	return n;
+}
+
+static int fault_type;
+static char *fault_chars[] = { "--", "**", "##" };
+
+static void
+handle_fault(struct pt_regs *regs)
+{
+	fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
+	longjmp(bus_error_jmp, 1);
+}
+
+#define SWAP(a, b, t)	((t) = (a), (a) = (b), (b) = (t))
+
+void
+byterev(unsigned char *val, int size)
+{
+	int t;
+	
+	switch (size) {
+	case 2:
+		SWAP(val[0], val[1], t);
+		break;
+	case 4:
+		SWAP(val[0], val[3], t);
+		SWAP(val[1], val[2], t);
+		break;
+	case 8: /* is there really any use for this? */
+		SWAP(val[0], val[7], t);
+		SWAP(val[1], val[6], t);
+		SWAP(val[2], val[5], t);
+		SWAP(val[3], val[4], t);
+		break;
+	}
+}
+
+static int brev;
+static int mnoread;
+
+static char *memex_help_string = 
+    "Memory examine command usage:\n"
+    "m [addr] [flags] examine/change memory\n"
+    "  addr is optional.  will start where left off.\n"
+    "  flags may include chars from this set:\n"
+    "    b   modify by bytes (default)\n"
+    "    w   modify by words (2 byte)\n"
+    "    l   modify by longs (4 byte)\n"
+    "    d   modify by doubleword (8 byte)\n"
+    "    r   toggle reverse byte order mode\n"
+    "    n   do not read memory (for i/o spaces)\n"
+    "    .   ok to read (default)\n"
+    "NOTE: flags are saved as defaults\n"
+    "";
+
+static char *memex_subcmd_help_string = 
+    "Memory examine subcommands:\n"
+    "  hexval   write this val to current location\n"
+    "  'string' write chars from string to this location\n"
+    "  '        increment address\n"
+    "  ^        decrement address\n"
+    "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
+    "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
+    "  `        clear no-read flag\n"
+    "  ;        stay at this addr\n"
+    "  v        change to byte mode\n"
+    "  w        change to word (2 byte) mode\n"
+    "  l        change to long (4 byte) mode\n"
+    "  u        change to doubleword (8 byte) mode\n"
+    "  m addr   change current addr\n"
+    "  n        toggle no-read flag\n"
+    "  r        toggle byte reverse flag\n"
+    "  < count  back up count bytes\n"
+    "  > count  skip forward count bytes\n"
+    "  x        exit this mode\n"
+    "";
+
+void
+memex()
+{
+	int cmd, inc, i, nslash;
+	unsigned long n;
+	unsigned char val[16];
+
+	scanhex((void *)&adrs);
+	cmd = skipbl();
+	if (cmd == '?') {
+		printf(memex_help_string);
+		return;
+	} else {
+		termch = cmd;
+	}
+	last_cmd = "m\n";
+	while ((cmd = skipbl()) != '\n') {
+		switch( cmd ){
+		case 'b':	size = 1;	break;
+		case 'w':	size = 2;	break;
+		case 'l':	size = 4;	break;
+		case 'd':	size = 8;	break;
+		case 'r': 	brev = !brev;	break;
+		case 'n':	mnoread = 1;	break;
+		case '.':	mnoread = 0;	break;
+		}
+	}
+	if( size <= 0 )
+		size = 1;
+	else if( size > 8 )
+		size = 8;
+	for(;;){
+		if (!mnoread)
+			n = mread(adrs, val, size);
+		printf("%.16x%c", adrs, brev? 'r': ' ');
+		if (!mnoread) {
+			if (brev)
+				byterev(val, size);
+			putchar(' ');
+			for (i = 0; i < n; ++i)
+				printf("%.2x", val[i]);
+			for (; i < size; ++i)
+				printf("%s", fault_chars[fault_type]);
+		}
+		putchar(' ');
+		inc = size;
+		nslash = 0;
+		for(;;){
+			if( scanhex(&n) ){
+				for (i = 0; i < size; ++i)
+					val[i] = n >> (i * 8);
+				if (!brev)
+					byterev(val, size);
+				mwrite(adrs, val, size);
+				inc = size;
+			}
+			cmd = skipbl();
+			if (cmd == '\n')
+				break;
+			inc = 0;
+			switch (cmd) {
+			case '\'':
+				for(;;){
+					n = inchar();
+					if( n == '\\' )
+						n = bsesc();
+					else if( n == '\'' )
+						break;
+					for (i = 0; i < size; ++i)
+						val[i] = n >> (i * 8);
+					if (!brev)
+						byterev(val, size);
+					mwrite(adrs, val, size);
+					adrs += size;
+				}
+				adrs -= size;
+				inc = size;
+				break;
+			case ',':
+				adrs += size;
+				break;
+			case '.':
+				mnoread = 0;
+				break;
+			case ';':
+				break;
+			case 'x':
+			case EOF:
+				scannl();
+				return;
+			case 'b':
+			case 'v':
+				size = 1;
+				break;
+			case 'w':
+				size = 2;
+				break;
+			case 'l':
+				size = 4;
+				break;
+			case 'u':
+				size = 8;
+				break;
+			case '^':
+				adrs -= size;
+				break;
+				break;
+			case '/':
+				if (nslash > 0)
+					adrs -= 1 << nslash;
+				else
+					nslash = 0;
+				nslash += 4;
+				adrs += 1 << nslash;
+				break;
+			case '\\':
+				if (nslash < 0)
+					adrs += 1 << -nslash;
+				else
+					nslash = 0;
+				nslash -= 4;
+				adrs -= 1 << -nslash;
+				break;
+			case 'm':
+				scanhex((void *)&adrs);
+				break;
+			case 'n':
+				mnoread = 1;
+				break;
+			case 'r':
+				brev = !brev;
+				break;
+			case '<':
+				n = size;
+				scanhex(&n);
+				adrs -= n;
+				break;
+			case '>':
+				n = size;
+				scanhex(&n);
+				adrs += n;
+				break;
+			case '?':
+				printf(memex_subcmd_help_string);
+				break;
+			}
+		}
+		adrs += inc;
+	}
+}
+
+int
+bsesc()
+{
+	int c;
+
+	c = inchar();
+	switch( c ){
+	case 'n':	c = '\n';	break;
+	case 'r':	c = '\r';	break;
+	case 'b':	c = '\b';	break;
+	case 't':	c = '\t';	break;
+	}
+	return c;
+}
+
+#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'f') \
+			 || ('A' <= (c) && (c) <= 'F'))
+void
+dump()
+{
+	int c;
+
+	c = inchar();
+	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
+		termch = c;
+	scanhex((void *)&adrs);
+	if( termch != '\n')
+		termch = 0;
+	if( c == 'i' ){
+		scanhex(&nidump);
+		if( nidump == 0 )
+			nidump = 16;
+		adrs += ppc_inst_dump(adrs, nidump);
+		last_cmd = "di\n";
+	} else {
+		scanhex(&ndump);
+		if( ndump == 0 )
+			ndump = 64;
+		prdump(adrs, ndump);
+		adrs += ndump;
+		last_cmd = "d\n";
+	}
+}
+
+void
+prdump(unsigned long adrs, long ndump)
+{
+	long n, m, c, r, nr;
+	unsigned char temp[16];
+
+	for( n = ndump; n > 0; ){
+		printf("%.16lx", adrs);
+		putchar(' ');
+		r = n < 16? n: 16;
+		nr = mread(adrs, temp, r);
+		adrs += nr;
+		for( m = 0; m < r; ++m ){
+		        if ((m & 7) == 0 && m > 0)
+			    putchar(' ');
+			if( m < nr )
+				printf("%.2x", temp[m]);
+			else
+				printf("%s", fault_chars[fault_type]);
+		}
+		for(; m < 16; ++m )
+			printf("   ");
+		printf("  |");
+		for( m = 0; m < r; ++m ){
+			if( m < nr ){
+				c = temp[m];
+				putchar(' ' <= c && c <= '~'? c: '.');
+			} else
+				putchar(' ');
+		}
+		n -= r;
+		for(; m < 16; ++m )
+			putchar(' ');
+		printf("|\n");
+		if( nr < r )
+			break;
+	}
+}
+
+int
+ppc_inst_dump(unsigned long adr, long count)
+{
+	int nr, dotted;
+	unsigned long first_adr;
+	unsigned long inst, last_inst;
+	unsigned char val[4];
+
+	dotted = 0;
+	for (first_adr = adr; count > 0; --count, adr += 4){
+		nr = mread(adr, val, 4);
+		if( nr == 0 ){
+			const char *x = fault_chars[fault_type];
+			printf("%.16lx  %s%s%s%s\n", adr, x, x, x, x);
+			break;
+		}
+		inst = GETWORD(val);
+		if (adr > first_adr && inst == last_inst) {
+			if (!dotted) {
+				printf(" ...\n");
+				dotted = 1;
+			}
+			continue;
+		}
+		dotted = 0;
+		last_inst = inst;
+		printf("%.16lx  ", adr);
+		printf("%.8x\t", inst);
+		print_insn_big_powerpc(stdout, inst, adr);	/* always returns 4 */
+		printf("\n");
+	}
+	return adr - first_adr;
+}
+
+void
+print_address(unsigned long addr)
+{
+	printf("0x%lx", addr);
+}
+
+/*
+ * Memory operations - move, set, print differences
+ */
+static unsigned long mdest;		/* destination address */
+static unsigned long msrc;		/* source address */
+static unsigned long mval;		/* byte value to set memory to */
+static unsigned long mcount;		/* # bytes to affect */
+static unsigned long mdiffs;		/* max # differences to print */
+
+void
+memops(int cmd)
+{
+	scanhex((void *)&mdest);
+	if( termch != '\n' )
+		termch = 0;
+	scanhex((void *)(cmd == 's'? &mval: &msrc));
+	if( termch != '\n' )
+		termch = 0;
+	scanhex((void *)&mcount);
+	switch( cmd ){
+	case 'm':
+		memmove((void *)mdest, (void *)msrc, mcount);
+		break;
+	case 's':
+		memset((void *)mdest, mval, mcount);
+		break;
+	case 'd':
+		if( termch != '\n' )
+			termch = 0;
+		scanhex((void *)&mdiffs);
+		memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
+		break;
+	}
+}
+
+void
+memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
+{
+	unsigned n, prt;
+
+	prt = 0;
+	for( n = nb; n > 0; --n )
+		if( *p1++ != *p2++ )
+			if( ++prt <= maxpr )
+				printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
+					p1[-1], p2 - 1, p2[-1]);
+	if( prt > maxpr )
+		printf("Total of %d differences\n", prt);
+}
+
+static unsigned mend;
+static unsigned mask;
+
+void
+memlocate()
+{
+	unsigned a, n;
+	unsigned char val[4];
+
+	last_cmd = "ml";
+	scanhex((void *)&mdest);
+	if (termch != '\n') {
+		termch = 0;
+		scanhex((void *)&mend);
+		if (termch != '\n') {
+			termch = 0;
+			scanhex((void *)&mval);
+			mask = ~0;
+			if (termch != '\n') termch = 0;
+			scanhex((void *)&mask);
+		}
+	}
+	n = 0;
+	for (a = mdest; a < mend; a += 4) {
+		if (mread(a, val, 4) == 4
+			&& ((GETWORD(val) ^ mval) & mask) == 0) {
+			printf("%.16x:  %.16x\n", a, GETWORD(val));
+			if (++n >= 10)
+				break;
+		}
+	}
+}
+
+static unsigned long mskip = 0x1000;
+static unsigned long mlim = 0xffffffff;
+
+void
+memzcan()
+{
+	unsigned char v;
+	unsigned a;
+	int ok, ook;
+
+	scanhex(&mdest);
+	if (termch != '\n') termch = 0;
+	scanhex(&mskip);
+	if (termch != '\n') termch = 0;
+	scanhex(&mlim);
+	ook = 0;
+	for (a = mdest; a < mlim; a += mskip) {
+		ok = mread(a, &v, 1);
+		if (ok && !ook) {
+			printf("%.8x .. ", a);
+			fflush(stdout);
+		} else if (!ok && ook)
+			printf("%.8x\n", a - mskip);
+		ook = ok;
+		if (a + mskip < a)
+			break;
+	}
+	if (ook)
+		printf("%.8x\n", a - mskip);
+}
+
+/* Input scanning routines */
+int
+skipbl()
+{
+	int c;
+
+	if( termch != 0 ){
+		c = termch;
+		termch = 0;
+	} else
+		c = inchar();
+	while( c == ' ' || c == '\t' )
+		c = inchar();
+	return c;
+}
+
+int
+scanhex(vp)
+unsigned long *vp;
+{
+	int c, d;
+	unsigned long v;
+
+	c = skipbl();
+	d = hexdigit(c);
+	if( d == EOF ){
+		termch = c;
+		return 0;
+	}
+	v = 0;
+	do {
+		v = (v << 4) + d;
+		c = inchar();
+		d = hexdigit(c);
+	} while( d != EOF );
+	termch = c;
+	*vp = v;
+	return 1;
+}
+
+void
+scannl()
+{
+	int c;
+
+	c = termch;
+	termch = 0;
+	while( c != '\n' )
+		c = inchar();
+}
+
+int
+hexdigit(int c)
+{
+	if( '0' <= c && c <= '9' )
+		return c - '0';
+	if( 'A' <= c && c <= 'F' )
+		return c - ('A' - 10);
+	if( 'a' <= c && c <= 'f' )
+		return c - ('a' - 10);
+	return EOF;
+}
+
+void
+getstring(char *s, int size)
+{
+	int c;
+
+	c = skipbl();
+	do {
+		if( size > 1 ){
+			*s++ = c;
+			--size;
+		}
+		c = inchar();
+	} while( c != ' ' && c != '\t' && c != '\n' );
+	termch = c;
+	*s = 0;
+}
+
+static char line[256];
+static char *lineptr;
+
+void
+flush_input()
+{
+	lineptr = NULL;
+}
+
+int
+inchar()
+{
+	if (lineptr == NULL || *lineptr == 0) {
+		if (fgets(line, sizeof(line), stdin) == NULL) {
+			lineptr = NULL;
+			return EOF;
+		}
+		lineptr = line;
+	}
+	return *lineptr++;
+}
+
+void
+take_input(str)
+char *str;
+{
+	lineptr = str;
+}
+
+
+/* Starting at codeaddr scan forward for a tbtable and fill in the
+ given table.  Return non-zero if successful at doing something.
+ */
+static int
+find_tb_table(unsigned long codeaddr, struct tbtable *tab)
+{
+	unsigned long codeaddr_max;
+	unsigned long tbtab_start;
+	int nr;
+	int instr;
+	int num_parms;
+
+	if (tab == NULL)
+		return 0;
+	memset(tab, 0, sizeof(tab));
+
+	/* Scan instructions starting at codeaddr for 128k max */
+	for (codeaddr_max = codeaddr + 128*1024*4;
+	     codeaddr < codeaddr_max;
+	     codeaddr += 4) {
+		nr = mread(codeaddr, &instr, 4);
+		if (nr != 4)
+			return 0;	/* Bad read.  Give up promptly. */
+		if (instr == 0) {
+			/* table should follow. */
+			int version;
+			unsigned long flags;
+			tbtab_start = codeaddr;	/* save it to compute func start addr */
+			codeaddr += 4;
+			nr = mread(codeaddr, &flags, 8);
+			if (nr != 8)
+				return 0;	/* Bad read or no tb table. */
+			tab->flags = flags;
+			version = (flags >> 56) & 0xff;
+			if (version != 0)
+				continue;	/* No tb table here. */
+			/* Now, like the version, some of the flags are values
+			 that are more conveniently extracted... */
+			tab->fp_saved = (flags >> 24) & 0x3f;
+			tab->gpr_saved = (flags >> 16) & 0x3f;
+			tab->fixedparms = (flags >> 8) & 0xff;
+			tab->floatparms = (flags >> 1) & 0x7f;
+			codeaddr += 8;
+			num_parms = tab->fixedparms + tab->floatparms;
+			if (num_parms) {
+				unsigned int parminfo;
+				int parm;
+				if (num_parms > 32)
+					return 1;	/* incomplete */
+				nr = mread(codeaddr, &parminfo, 4);
+				if (nr != 4)
+					return 1;	/* incomplete */
+				/* decode parminfo...32 bits.
+				 A zero means fixed.  A one means float and the
+				 following bit determines single (0) or double (1).
+				 */
+				for (parm = 0; parm < num_parms; parm++) {
+					if (parminfo & 0x80000000) {
+						parminfo <<= 1;
+						if (parminfo & 0x80000000)
+							tab->parminfo[parm] = TBTAB_PARMDFLOAT;
+						else
+							tab->parminfo[parm] = TBTAB_PARMSFLOAT;
+					} else {
+						tab->parminfo[parm] = TBTAB_PARMFIXED;
+					}
+					parminfo <<= 1;
+				}
+				codeaddr += 4;
+			}
+			if (flags & TBTAB_FLAGSHASTBOFF) {
+				nr = mread(codeaddr, &tab->tb_offset, 4);
+				if (nr != 4)
+					return 1;	/* incomplete */
+				if (tab->tb_offset > 0) {
+					tab->funcstart = tbtab_start - tab->tb_offset;
+				}
+				codeaddr += 4;
+			}
+			/* hand_mask appears to be always be omitted. */
+			if (flags & TBTAB_FLAGSHASCTL) {
+				/* Assume this will never happen for C or asm */
+				return 1;	/* incomplete */
+			}
+			if (flags & TBTAB_FLAGSNAMEPRESENT) {
+				short namlen;
+				nr = mread(codeaddr, &namlen, 2);
+				if (nr != 2)
+					return 1;	/* incomplete */
+				if (namlen >= sizeof(tab->name))
+					namlen = sizeof(tab->name)-1;
+				codeaddr += 2;
+				nr = mread(codeaddr, tab->name, namlen);
+				tab->name[namlen] = '\0';
+				codeaddr += namlen;
+			}
+			return 1;
+		}
+	}
+	return 0;	/* hit max...sorry. */
+}
+
+void
+mem_translate()
+{
+	int c;
+	unsigned long ea, va, vsid, vpn, page, hpteg_slot_primary, hpteg_slot_secondary, primary_hash, i, *steg, esid, stabl;
+	HPTE *  hpte;
+	struct mm_struct * mm;
+	pte_t  *ptep = NULL;
+	void * pgdir;
+ 
+	c = inchar();
+	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
+		termch = c;
+	scanhex((void *)&ea);
+  
+	if ((ea >= KRANGE_START) && (ea <= (KRANGE_START + (1UL<<60)))) {
+		ptep = 0;
+		vsid = get_kernel_vsid(ea);
+		va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+	} else {
+		// if in vmalloc range, use the vmalloc page directory
+		if ( ( ea >= VMALLOC_START ) && ( ea <= VMALLOC_END ) ) {
+			mm = &init_mm;
+			vsid = get_kernel_vsid( ea );
+		}
+		// if in ioremap range, use the ioremap page directory
+		else if ( ( ea >= IMALLOC_START ) && ( ea <= IMALLOC_END ) ) {
+			mm = &ioremap_mm;
+			vsid = get_kernel_vsid( ea );
+		}
+		// if in user range, use the current task's page directory
+		else if ( ( ea >= USER_START ) && ( ea <= USER_END ) ) {
+			mm = current->mm;
+			vsid = get_vsid(mm->context, ea );
+		}
+		pgdir = mm->pgd;
+		va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+		ptep = find_linux_pte( pgdir, ea );
+	}
+
+	vpn = ((vsid << 28) | (((ea) & 0xFFFF000))) >> 12;
+	page = vpn & 0xffff;
+	esid = (ea >> 28)  & 0xFFFFFFFFF;
+
+  // Search the primary group for an available slot
+	primary_hash = ( vsid & 0x7fffffffff ) ^ page;
+	hpteg_slot_primary = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+	hpteg_slot_secondary = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
+
+	printf("ea             : %.16lx\n", ea);
+	printf("esid           : %.16lx\n", esid);
+	printf("vsid           : %.16lx\n", vsid);
+
+	printf("\nSoftware Page Table\n-------------------\n");
+	printf("ptep           : %.16lx\n", ((unsigned long *)ptep));
+	if(ptep) {
+		printf("*ptep          : %.16lx\n", *((unsigned long *)ptep));
+	}
+
+	hpte  = htab_data.htab  + hpteg_slot_primary;
+	printf("\nHardware Page Table\n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("slot primary   : %.16lx\n", hpteg_slot_primary);
+	printf("slot secondary : %.16lx\n", hpteg_slot_secondary);
+	printf("\nPrimary Group\n");
+	for (i=0; i<8; ++i) {
+		if ( hpte->dw0.dw0.v != 0 ) {
+			printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1);
+			printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
+			       (hpte->dw0.dw0.avpn)>>5, 
+			       (hpte->dw0.dw0.avpn) & 0x1f,
+			       (hpte->dw0.dw0.h));
+			printf("          rpn: %.13lx \n", (hpte->dw1.dw1.rpn));
+			printf("           pp: %.1lx \n", 
+			       ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp));
+			printf("        wimgn: %.2lx  reference: %.1lx  change: %.1lx\n", 
+			       ((hpte->dw1.dw1.w)<<4)|
+			       ((hpte->dw1.dw1.i)<<3)|
+			       ((hpte->dw1.dw1.m)<<2)|
+			       ((hpte->dw1.dw1.g)<<1)|
+			       ((hpte->dw1.dw1.n)<<0),
+			       hpte->dw1.dw1.r, hpte->dw1.dw1.c);
+		}
+		hpte++;
+	}
+
+	printf("\nSecondary Group\n");
+	// Search the secondary group
+	hpte  = htab_data.htab  + hpteg_slot_secondary;
+	for (i=0; i<8; ++i) {
+		if(hpte->dw0.dw0.v) {
+			printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1);
+			printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
+			       (hpte->dw0.dw0.avpn)>>5, 
+			       (hpte->dw0.dw0.avpn) & 0x1f,
+			       (hpte->dw0.dw0.h));
+			printf("          rpn: %.13lx \n", (hpte->dw1.dw1.rpn));
+			printf("           pp: %.1lx \n", 
+			       ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp));
+			printf("        wimgn: %.2lx  reference: %.1lx  change: %.1lx\n", 
+			       ((hpte->dw1.dw1.w)<<4)|
+			       ((hpte->dw1.dw1.i)<<3)|
+			       ((hpte->dw1.dw1.m)<<2)|
+			       ((hpte->dw1.dw1.g)<<1)|
+			       ((hpte->dw1.dw1.n)<<0),
+			       hpte->dw1.dw1.r, hpte->dw1.dw1.c);
+		}
+		hpte++;
+	}
+
+	printf("\nHardware Segment Table\n-----------------------\n");
+	stabl = (unsigned long)(KERNELBASE+(_ASR&0xFFFFFFFFFFFFFFFE));
+	steg = (unsigned long *)((stabl) | ((esid & 0x1f) << 7));
+
+	printf("stab base      : %.16lx\n", stabl);
+	printf("slot           : %.16lx\n", steg);
+
+	for (i=0; i<8; ++i) {
+		printf("%d: (ste) %.16lx %.16lx\n", i,
+		       *((unsigned long *)(steg+i*2)),*((unsigned long *)(steg+i*2+1)) );
+	}
+}
+
+void mem_check()
+{
+	unsigned long htab_size_bytes;
+	unsigned long htab_end;
+	unsigned long last_rpn;
+	HPTE *hpte1, *hpte2;
+
+	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
+	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
+	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
+	last_rpn = 0xfffff;
+
+	printf("\nHardware Page Table Check\n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("htab size      : %.16lx\n", htab_size_bytes);
+
+#if 1
+	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
+		if ( hpte1->dw0.dw0.v != 0 ) {
+			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
+				for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
+					if ( hpte2->dw0.dw0.v != 0 ) {
+						if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
+							printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
+							printf("   hpte1: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
+							       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
+							printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
+							       hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
+						}
+					}
+				}
+			} else {
+				printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
+				printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
+				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
+			}
+		}
+	}
+#endif
+	printf("\nDone -------------------\n");
+}
+
+void mem_find_real()
+{
+	unsigned long htab_size_bytes;
+	unsigned long htab_end;
+	unsigned long last_rpn;
+	HPTE *hpte1;
+	unsigned long pa, rpn;
+	int c;
+
+	c = inchar();
+	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
+		termch = c;
+	scanhex((void *)&pa);
+	rpn = pa >> 12;
+  
+	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
+	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
+	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
+	last_rpn = 0xfffff;
+
+	printf("\nMem Find RPN\n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("htab size      : %.16lx\n", htab_size_bytes);
+
+	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
+		if ( hpte1->dw0.dw0.v != 0 ) {
+			if ( hpte1->dw1.dw1.rpn == rpn ) {
+				printf(" Found rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
+				printf("      hpte: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
+				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
+			}
+		}
+	}
+	printf("\nDone -------------------\n");
+}
+
+void mem_find_vsid()
+{
+	unsigned long htab_size_bytes;
+	unsigned long htab_end;
+	HPTE *hpte1;
+	unsigned long vsid;
+	int c;
+
+	c = inchar();
+	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
+		termch = c;
+	scanhex((void *)&vsid);
+  
+	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
+	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
+
+	printf("\nMem Find VSID\n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("htab size      : %.16lx\n", htab_size_bytes);
+
+	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
+		if ( hpte1->dw0.dw0.v != 0 ) {
+			if ( ((hpte1->dw0.dw0.avpn)>>5) == vsid ) {
+				printf(" Found vsid: %.16lx \n", ((hpte1->dw0.dw0.avpn) >> 5));
+				printf("       hpte: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
+				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
+			}
+		}
+	}
+	printf("\nDone -------------------\n");
+}
+
+void mem_map_check_slab()
+{
+	int i, slab_count;
+
+	i = max_mapnr;
+	slab_count = 0;
+	
+	while (i-- > 0)  {
+		if (PageSlab(mem_map+i)){
+			printf(" slab entry - mem_map entry =%p  \n", mem_map+i);
+			slab_count ++;
+		}
+	}
+
+	printf(" count of pages for slab = %d \n", slab_count);
+}
+
+void mem_map_lock_pages()
+{
+	int i, lock_count;
+
+	i = max_mapnr;
+	lock_count = 0;
+	
+	while (i-- > 0)  {
+		if (PageLocked(mem_map+i)){
+			printf(" locked entry - mem_map entry =%p  \n", mem_map+i);
+			lock_count ++;
+		}
+	}
+
+	printf(" count of locked pages = %d \n", lock_count); 
+}
+
+
+
+void mem_map_check_hash()
+{
+	int i = max_mapnr;
+	
+	while (i-- > 0)  {
+		/* skip the reserved */
+		if (!PageReserved(mem_map+i)) {
+			if (((mem_map+i)->next_hash) != NULL) {
+				if ( REGION_ID((mem_map+i)->next_hash) != KERNEL_REGION_ID ) {
+					printf(" mem_map check hash - non c0 entry - "
+					       "address/value = %p %lx\n", mem_map+i,(mem_map+i)->next_hash);
+				} 
+				if ((unsigned long)((mem_map+i)->next_hash) ==  KERNELBASE){
+					printf(" mem_map check hash - 0x%lx  entry = %p \n",
+					       KERNELBASE, mem_map+i);
+				} 
+			}
+		} else {
+			if (page_count(mem_map+i) < 0) {
+				printf(" reserved page with negative count- entry = %lx \n", mem_map+i);
+			}
+		}
+	}
+	printf(" mem_map check hash completed \n");
+}
+
+void mem_check_dup_rpn ()
+{
+	unsigned long htab_size_bytes;
+	unsigned long htab_end;
+	unsigned long last_rpn;
+	HPTE *hpte1, *hpte2;
+	int dup_count;
+	struct task_struct *p;
+	unsigned long kernel_vsid_c0,kernel_vsid_c1,kernel_vsid_c2,kernel_vsid_c3;
+	unsigned long kernel_vsid_c4,kernel_vsid_c5,kernel_vsid_d,kernel_vsid_e;
+	unsigned long kernel_vsid_f;
+	unsigned long vsid0,vsid1,vsidB,vsid2;
+
+	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
+	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
+	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
+	last_rpn = 0xfffff;
+
+	printf("\nHardware Page Table Check\n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("htab size      : %.16lx\n", htab_size_bytes);
+
+
+	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
+		if ( hpte1->dw0.dw0.v != 0 ) {
+			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
+				dup_count = 0;
+				for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
+					if ( hpte2->dw0.dw0.v != 0 ) {
+						if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
+							dup_count++;
+						}
+					}
+				}
+				if(dup_count > 5) {
+					printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
+					printf("    mem map array entry %p count = %d \n",
+					       (mem_map+(hpte1->dw1.dw1.rpn)), (mem_map+(hpte1->dw1.dw1.rpn))->count);
+					for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
+						if ( hpte2->dw0.dw0.v != 0 ) {
+							if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
+								printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
+								       hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
+							}
+						}
+					}
+				}
+			} else {
+				printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
+				printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
+				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
+			}
+		}
+		if (xmon_interrupted())
+			return;
+	}                                                                     
+
+
+
+	// print the kernel vsids
+	kernel_vsid_c0 =  get_kernel_vsid(0xC000000000000000);
+	kernel_vsid_c1 =  get_kernel_vsid(0xC000000010000000);
+	kernel_vsid_c2 =  get_kernel_vsid(0xC000000020000000);
+	kernel_vsid_c3 =  get_kernel_vsid(0xC000000030000000);
+	kernel_vsid_c4 =  get_kernel_vsid(0xC000000040000000);
+	kernel_vsid_c5 =  get_kernel_vsid(0xC000000050000000);
+	kernel_vsid_d  =  get_kernel_vsid(0xD000000000000000);
+	kernel_vsid_e  =  get_kernel_vsid(0xE000000000000000);
+	kernel_vsid_f  =  get_kernel_vsid(0xF000000000000000);
+
+	printf(" kernel vsid -  seg c0  = %lx\n",  kernel_vsid_c0 );
+	printf(" kernel vsid -  seg c1  = %lx\n",  kernel_vsid_c1 );
+	printf(" kernel vsid -  seg c2  = %lx\n",  kernel_vsid_c2 );
+	printf(" kernel vsid -  seg c3  = %lx\n",  kernel_vsid_c3 );
+	printf(" kernel vsid -  seg c4  = %lx\n",  kernel_vsid_c4 );
+	printf(" kernel vsid -  seg c5  = %lx\n",  kernel_vsid_c5 );
+	printf(" kernel vsid -  seg d   = %lx\n",  kernel_vsid_d );
+	printf(" kernel vsid -  seg e   = %lx\n",  kernel_vsid_e );
+	printf(" kernel vsid -  seg f   = %lx\n",  kernel_vsid_f );
+
+
+  // print a list of valid vsids for the tasks
+	read_lock(&tasklist_lock);
+	for_each_task(p)
+		if(p->mm) {
+			struct mm_struct *mm = p->mm; 
+			printf(" task = %p  mm =  %lx  pgd   %lx\n", 
+			       p, mm, mm->pgd);
+			vsid0 = get_vsid( mm->context, 0 );
+			vsid1 = get_vsid( mm->context, 0x10000000 );
+			vsid2 = get_vsid( mm->context, 0x20000000 );
+			vsidB = get_vsid( mm->context, 0xB0000000 );
+			printf("            context = %lx  vsid seg 0  = %lx\n",  mm->context, vsid0 );
+			printf("                           vsid seg 1  = %lx\n",  vsid1 );
+			printf("                           vsid seg 2  = %lx\n",  vsid2 );
+			printf("                           vsid seg 2  = %lx\n",  vsidB );
+	  
+			printf("\n");
+		};
+	read_unlock(&tasklist_lock);
+
+	printf("\nDone -------------------\n");
+}
+
+
+
+void mem_check_pagetable_vsids ()
+{
+	unsigned long htab_size_bytes;
+	unsigned long htab_end;
+	unsigned long last_rpn;
+	struct task_struct *p;
+	unsigned long valid_table_count,invalid_table_count,bogus_rpn_count;
+	int found;
+	unsigned long user_address_table_count,kernel_page_table_count;
+	unsigned long pt_vsid;
+	HPTE *hpte1;
+
+
+	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
+	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
+	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
+	last_rpn = 0xfffff;
+
+	printf("\nHardware Page Table Check\n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("htab size      : %.16lx\n", htab_size_bytes);
+
+	valid_table_count = 0;
+	invalid_table_count = 0;
+	bogus_rpn_count = 0;
+	user_address_table_count = 0;
+	kernel_page_table_count = 0;
+	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
+		if ( hpte1->dw0.dw0.v != 0 ) {
+			valid_table_count++;
+			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
+				pt_vsid =  (hpte1->dw0.dw0.avpn) >> 5;
+				if ((pt_vsid == get_kernel_vsid(0xC000000000000000)) |
+				    (pt_vsid == get_kernel_vsid(0xC000000010000000)) |
+				    (pt_vsid == get_kernel_vsid(0xC000000020000000)) |
+				    (pt_vsid == get_kernel_vsid(0xC000000030000000)) |
+				    (pt_vsid == get_kernel_vsid(0xC000000040000000)) |
+				    (pt_vsid == get_kernel_vsid(0xC000000050000000)) |
+				    (pt_vsid == get_kernel_vsid(0xD000000000000000)) |
+				    (pt_vsid == get_kernel_vsid(0xE000000000000000)) |
+				    (pt_vsid == get_kernel_vsid(0xF000000000000000)) ) {
+					kernel_page_table_count ++;
+				} else {
+					read_lock(&tasklist_lock);
+					found = 0;
+					for_each_task(p) {
+						if(p->mm && (found == 0)) {
+							struct mm_struct *mm = p->mm; 
+	     
+							if ((pt_vsid == get_vsid( mm->context, 0 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x10000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x20000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x30000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x40000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x50000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x60000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x70000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x80000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0x90000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0xA0000000 )) |
+							    (pt_vsid == get_vsid( mm->context, 0xB0000000 ))) {
+								user_address_table_count ++;
+								found = 1;
+							}
+						}
+					}
+					read_unlock(&tasklist_lock);
+					if (found == 0)
+					{
+						printf(" vsid not found vsid = %lx, hpte = %p  \n", 
+						       pt_vsid,hpte1);
+						printf("    rpn in entry = %lx \n", hpte1->dw1.dw1.rpn);
+						printf("    mem map address = %lx  \n", mem_map + (hpte1->dw1.dw1.rpn));
+           
+					} else //  found
+					{
+					}
+
+				}  // good rpn
+       
+			} else {
+				bogus_rpn_count ++;
+			}
+		} else {
+			invalid_table_count++;
+		}
+	}                                                                     
+
+
+	printf(" page table valid counts - valid entries = %lx  invalid entries =  %lx \n",
+	       valid_table_count, invalid_table_count);
+
+	printf("  bogus rpn entries ( probably io) = %lx \n", bogus_rpn_count);
+
+ 
+  
+	printf(" page table counts - kernel entries = %lx  user entries =  %lx \n",
+	       kernel_page_table_count, user_address_table_count); 
+
+	printf("\nDone -------------------\n");
+
+}
+
+
+void mem_check_full_group()
+{
+	unsigned long htab_size_bytes;
+	unsigned count;
+	unsigned count_array[] = {0,0,0,0,0,0,0,0,0}; 
+	unsigned i;
+	unsigned long htab_end;
+	HPTE *hpte1, *hpte2, *hpte3;
+	u64  rpn = 0;
+
+	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
+	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
+
+	printf("\nHardware Page Find full groups \n-------------------\n");
+	printf("htab base      : %.16lx\n", htab_data.htab);
+	printf("htab size      : %.16lx\n", htab_size_bytes);
+
+	for (hpte1 = htab_data.htab; (unsigned long)hpte1 < htab_end; hpte1= hpte1 + 8)
+	{
+		count = 0;
+		hpte2 = hpte1;
+		for (i=0; i<8; ++i)
+		{
+			if ( hpte2->dw0.dw0.v != 0 )
+			{
+				count++;
+			}
+			hpte2++;
+		}
+		if (count == 8 )
+		{
+			printf("  full group starting with entry %lx \n", hpte1);
+			hpte3 = hpte1;
+			for (i=0; i<8; ++i)
+			{
+				if ( hpte3->dw0.dw0.v != 0 )
+				{
+					printf(" entry number %d   \n",i);
+					printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
+					       (hpte3->dw0.dw0.avpn)>>5, 
+					       (hpte3->dw0.dw0.avpn) & 0x1f,
+					       (hpte3->dw0.dw0.h));
+					printf("          rpn: %.13lx \n", (hpte3->dw1.dw1.rpn)); 
+					// Dump out the memmap array entry address, corresponding virtual address, and reference count.
+					rpn = hpte3->dw1.dw1.rpn;
+					printf("          mem_map+rpn=%p, virtual@=%p, count=%lx \n", mem_map+rpn, (mem_map+rpn)->virtual, (mem_map+rpn)->count);
+				}
+				hpte3++;
+			}
+			if (xmon_interrupted())
+				return;
+		}
+
+		count_array[count]++;
+	}
+	for (i=1; i<9; ++i)
+	{
+		printf("  group count for size  %i = %lx \n", i, count_array[i]);
+	}
+
+	printf("\nDone -------------------\n");
+}
+
+
+
+static void show_task(struct task_struct * p)
+{
+	/* unsigned long free = 0;  --Unused */
+	int state;
+	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
+
+	printf("--------------------------------------------------------------------------\n");
+	printf("%-11.11s pid: %5.5lx ppid: %5.5lx state: ", 
+	       p->comm, p->pid, p->p_pptr->pid);
+	state = p->state ? ffz(~p->state) + 1 : 0;
+	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
+		printf(stat_nam[state]);
+	else
+		printf(" ");
+	if (p == current)
+		printf(" pc: current task       ");
+	else
+		printf(" pc: 0x%16.16lx ", thread_saved_pc(&p->thread));
+
+	if (p->p_cptr)
+		printf("%5d ", p->p_cptr->pid);
+	else
+		printf("      ");
+	if (!p->mm)
+		printf(" (L-TLB) ");
+	else
+		printf(" (NOTLB) ");
+	if (p->p_ysptr)
+		printf("%7d", p->p_ysptr->pid);
+	else
+		printf("       ");
+	if (p->p_osptr)
+		printf(" %5d\n", p->p_osptr->pid);
+	else
+		printf("\n");
+
+	{
+		struct sigqueue *q;
+		char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; 
+
+		render_sigset_t(&p->pending.signal, s);
+		render_sigset_t(&p->blocked, b);
+		printf("            sig: %d %s %s :", signal_pending(p), s, b);
+		for (q = p->pending.head; q ; q = q->next)
+			printf(" %d", q->info.si_signo);
+		printf(" X\n");
+	}
+
+	printf("            pers   : %lx  current : %lx", 
+	       p->personality, p);
+	printf("\n");
+
+	printf("            thread : 0x%16.16lx  ksp   : 0x%16.16lx\n", 
+	       &(p->thread), (p->thread.ksp));
+	printf("            pgdir : 0x%16.16lx\n", (p->thread.pgdir));
+	printf("            regs   : 0x%16.16lx  sysc  : 0x%16.16lx\n", 
+	       (p->thread.regs), (p->thread.last_syscall));
+	if(p->thread.regs) {
+	  printf("            nip    : 0x%16.16lx  msr   : 0x%16.16lx\n", 
+		 ((p->thread.regs)->nip), ((p->thread.regs)->msr)); 
+	  printf("            ctr    : 0x%16.16lx  link  : 0x%16.16lx\n", 
+		 ((p->thread.regs)->ctr), ((p->thread.regs)->link));
+	  printf("            xer    : 0x%16.16lx  ccr   : 0x%16.16lx\n", 
+		 ((p->thread.regs)->xer), ((p->thread.regs)->ccr)); 
+	  printf("            trap   : 0x%16.16lx\n", 
+		 ((p->thread.regs)->trap));
+	  printf("            dar    : 0x%16.16lx  dsis  : 0x%16.16lx\n", 
+		 ((p->thread.regs)->dar), ((p->thread.regs)->dsisr));
+	  printf("            rslt   : 0x%16.16lx  org3  : 0x%16.16lx\n", 
+		 ((p->thread.regs)->result), (p->thread.regs->orig_gpr3));
+	}
+
+	if(p->mm) {
+	  struct mm_struct *mm = p->mm; 
+	  printf("            mm     : 0x%16.16lx  pgd   : 0x%16.16lx\n", 
+		 mm, mm->pgd);
+	  printf("            context: 0x%16.16lx  mmap  : 0x%16.16lx\n", 
+		 mm->context, mm->mmap);
+	  
+	  printf("\n");
+	}
+
+}
+
+static void xmon_show_state(void)
+{
+	struct task_struct *p;
+
+#if (BITS_PER_LONG == 32)
+	printf("\n"
+	       "                         free                        sibling\n");
+	printf("task name   st PC              stack   pid father child younger older\n");
+#else
+	printf("\n"
+	       "                                 free                        sibling\n");
+	printf("  task                 PC        stack   pid father child younger older\n");
+#endif
+	read_lock(&tasklist_lock);
+	for_each_task(p)
+		show_task(p);
+	read_unlock(&tasklist_lock);
+}
+
+static void debug_trace(void) {
+        unsigned long val, cmd, on;
+
+	cmd = skipbl();
+	if (cmd == '\n') {
+		/* show current state */
+		unsigned long i;
+		printf("naca->debug_switch = 0x%lx\n", naca->debug_switch);
+		for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) {
+			on = PPCDBG_BITVAL(i) & naca->debug_switch;
+			printf("%02x %s %12s   ", i, on ? "on " : "off",  trace_names[i] ? trace_names[i] : "");
+			if (((i+1) % 3) == 0)
+				printf("\n");
+		}
+		printf("\n");
+		return;
+	}
+	while (cmd != '\n') {
+		on = 1;	/* default if no sign given */
+		while (cmd == '+' || cmd == '-') {
+			on = (cmd == '+');
+			cmd = inchar();
+			if (cmd == ' ' || cmd == '\n') {  /* Turn on or off based on + or - */
+				naca->debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE;
+				printf("Setting all values to %s...\n", on ? "on" : "off");
+				if (cmd == '\n') return;
+				else cmd = skipbl(); 
+			}
+			else
+				termch = cmd;
+		}
+		termch = cmd;	/* not +/- ... let scanhex see it */
+		scanhex((void *)&val);
+		if (val >= 64) {
+			printf("Value %x out of range:\n", val);
+			return;
+		}
+		if (on) {
+			naca->debug_switch |= PPCDBG_BITVAL(val);
+			printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
+		} else {
+			naca->debug_switch &= ~PPCDBG_BITVAL(val);
+			printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
+		}
+		cmd = skipbl();
+	}
+}
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/ioport.c linux-2.4.19-pre5/arch/sparc/kernel/ioport.c
--- linux-2.4.19-pre4/arch/sparc/kernel/ioport.c	Tue Oct 30 15:08:11 2001
+++ linux-2.4.19-pre5/arch/sparc/kernel/ioport.c	Fri Mar 29 14:49:25 2002
@@ -161,7 +161,7 @@
 static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,
     unsigned long size, char *name)
 {
-	static int printed_full = 0;
+	static int printed_full;
 	struct xresource *xres;
 	struct resource *res;
 	char *tack;
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/irq.c linux-2.4.19-pre5/arch/sparc/kernel/irq.c
--- linux-2.4.19-pre4/arch/sparc/kernel/irq.c	Thu Jul 19 18:11:13 2001
+++ linux-2.4.19-pre5/arch/sparc/kernel/irq.c	Fri Mar 29 14:49:25 2002
@@ -90,7 +90,7 @@
  */
 #define MAX_STATIC_ALLOC	4
 struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-int static_irq_count = 0;
+int static_irq_count;
 
 struct irqaction *irq_action[NR_IRQS+1] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/pcic.c linux-2.4.19-pre5/arch/sparc/kernel/pcic.c
--- linux-2.4.19-pre4/arch/sparc/kernel/pcic.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre5/arch/sparc/kernel/pcic.c	Fri Mar 29 14:49:25 2002
@@ -185,7 +185,7 @@
  * Only one PCIC per IIep,
  * and since we have no SMP IIep, only one per system.
  */
-static int pcic0_up = 0;
+static int pcic0_up;
 static struct linux_pcic pcic0;
 
 unsigned int pcic_regs;
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/process.c linux-2.4.19-pre5/arch/sparc/kernel/process.c
--- linux-2.4.19-pre4/arch/sparc/kernel/process.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre5/arch/sparc/kernel/process.c	Fri Mar 29 14:49:25 2002
@@ -67,9 +67,9 @@
 	for (;;) {
 		if (ARCH_SUN4C_SUN4) {
 			static int count = HZ;
-			static unsigned long last_jiffies = 0;
-			static unsigned long last_faults = 0;
-			static unsigned long fps = 0;
+			static unsigned long last_jiffies;
+			static unsigned long last_faults;
+			static unsigned long fps;
 			unsigned long now;
 			unsigned long faults;
 			unsigned long flags;
@@ -87,7 +87,7 @@
 				fps = (fps + (faults - last_faults)) >> 1;
 				last_faults = faults;
 #if 0
-				printk("kernel faults / second = %d\n", fps);
+				printk("kernel faults / second = %ld\n", fps);
 #endif
 				if (fps >= SUN4C_FAULT_HIGH) {
 					sun4c_grow_kernel_ring();
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/setup.c linux-2.4.19-pre5/arch/sparc/kernel/setup.c
--- linux-2.4.19-pre4/arch/sparc/kernel/setup.c	Tue Nov 13 09:16:05 2001
+++ linux-2.4.19-pre5/arch/sparc/kernel/setup.c	Fri Mar 29 14:49:25 2002
@@ -47,8 +47,6 @@
 #include <asm/hardirq.h>
 #include <asm/machines.h>
 
-#undef PROM_DEBUG_CONSOLE
-
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -134,6 +132,19 @@
 	}
 }
 
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+	prom_printf("%s", s);
+}
+
+static struct console prom_debug_console = {
+	name:		"debug",
+	write:		prom_console_write,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
 int obp_system_intr(void)
 {
 	if (boot_flags & BOOTME_KGDB) {
@@ -166,6 +177,10 @@
 		prom_printf("boot_flags_init: Halt!\n");
 		prom_halt();
 		break;
+	case 'p':
+		/* Use PROM debug console. */
+		register_console(&prom_debug_console);
+		break;
 	default:
 		printk("Unknown boot switch (-%c)\n", c);
 		break;
@@ -280,21 +295,6 @@
 
 struct pt_regs fake_swapper_regs;
 
-#ifdef PROM_DEBUG_CONSOLE
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
-	prom_printf("%s", s);
-}
-
-static struct console prom_console = {
-	name:		"debug",
-	write:		prom_console_write,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
-};
-#endif
-
 extern void paging_init(void);
 
 void __init setup_arch(char **cmdline_p)
@@ -348,9 +348,6 @@
 		printk("UNKNOWN!\n");
 		break;
 	};
-#ifdef PROM_DEBUG_CONSOLE
-	register_console(&prom_console);
-#endif
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -381,7 +378,7 @@
 	if (!root_flags)
 		root_mountflags &= ~MS_RDONLY;
 	ROOT_DEV = to_kdev_t(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
 	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
 	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
 	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/signal.c linux-2.4.19-pre5/arch/sparc/kernel/signal.c
--- linux-2.4.19-pre4/arch/sparc/kernel/signal.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc/kernel/signal.c	Wed Jan 24 15:18:06 2001
@@ -1279,7 +1279,10 @@
 #endif
 				/* fall through */
 			default:
-				sig_exit(signr, exit_code, &info);
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
 				/* NOT REACHED */
 			}
 		}
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/sun4d_smp.c linux-2.4.19-pre5/arch/sparc/kernel/sun4d_smp.c
--- linux-2.4.19-pre4/arch/sparc/kernel/sun4d_smp.c	Wed Nov 21 10:31:09 2001
+++ linux-2.4.19-pre5/arch/sparc/kernel/sun4d_smp.c	Fri Mar 29 14:49:25 2002
@@ -47,7 +47,7 @@
 extern volatile int smp_processors_ready;
 extern unsigned long cpu_present_map;
 extern int smp_num_cpus;
-static int smp_highest_cpu = 0;
+static int smp_highest_cpu;
 extern int smp_threads_ready;
 extern unsigned char mid_xlate[NR_CPUS];
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/time.c linux-2.4.19-pre5/arch/sparc/kernel/time.c
--- linux-2.4.19-pre4/arch/sparc/kernel/time.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre5/arch/sparc/kernel/time.c	Fri Mar 29 14:49:25 2002
@@ -115,7 +115,7 @@
 void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
+	static long last_rtc_update;
 
 #ifndef CONFIG_SMP
 	if(!user_mode(regs))
diff -urN linux-2.4.19-pre4/arch/sparc/kernel/traps.c linux-2.4.19-pre5/arch/sparc/kernel/traps.c
--- linux-2.4.19-pre4/arch/sparc/kernel/traps.c	Thu Sep  7 08:32:00 2000
+++ linux-2.4.19-pre5/arch/sparc/kernel/traps.c	Fri Mar 29 14:49:25 2002
@@ -272,7 +272,7 @@
 void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		 unsigned long psr)
 {
-	static int calls = 0;
+	static int calls;
 	siginfo_t info;
 	unsigned long fsr;
 	int ret = 0;
diff -urN linux-2.4.19-pre4/arch/sparc/mm/iommu.c linux-2.4.19-pre5/arch/sparc/mm/iommu.c
--- linux-2.4.19-pre4/arch/sparc/mm/iommu.c	Sun Feb 18 19:49:54 2001
+++ linux-2.4.19-pre5/arch/sparc/mm/iommu.c	Fri Mar 29 14:49:25 2002
@@ -25,7 +25,7 @@
 BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
 #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
 extern int flush_page_for_dma_global;
-static int viking_flush = 0;
+static int viking_flush;
 /* viking.S */
 extern void viking_flush_page(unsigned long page);
 extern void viking_mxcc_flush_page(unsigned long page);
diff -urN linux-2.4.19-pre4/arch/sparc/mm/srmmu.c linux-2.4.19-pre5/arch/sparc/mm/srmmu.c
--- linux-2.4.19-pre4/arch/sparc/mm/srmmu.c	Tue Nov 13 09:16:05 2001
+++ linux-2.4.19-pre5/arch/sparc/mm/srmmu.c	Fri Mar 29 14:49:25 2002
@@ -1733,7 +1733,7 @@
 static void __init poke_viking(void)
 {
 	unsigned long mreg = srmmu_get_mmureg();
-	static int smp_catch = 0;
+	static int smp_catch;
 
 	if(viking_mxcc_present) {
 		unsigned long mxcc_control = mxcc_get_creg();
diff -urN linux-2.4.19-pre4/arch/sparc/mm/swift.S linux-2.4.19-pre5/arch/sparc/mm/swift.S
--- linux-2.4.19-pre4/arch/sparc/mm/swift.S	Tue Jul 18 12:29:47 2000
+++ linux-2.4.19-pre5/arch/sparc/mm/swift.S	Fri Mar 29 14:49:25 2002
@@ -53,11 +53,9 @@
 
 	.globl	swift_flush_cache_mm
 swift_flush_cache_mm:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_cache_mm_out
-#endif
 	WINDOW_FLUSH(%g4, %g5)
 	rd	%psr, %g1
 	andn	%g1, PSR_ET, %g3
@@ -120,11 +118,9 @@
 swift_flush_cache_page:
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 70:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_cache_page_out
-#endif
 	WINDOW_FLUSH(%g4, %g5)
 	rd	%psr, %g1
 	andn	%g1, PSR_ET, %g3
@@ -224,11 +220,9 @@
 	.globl	swift_flush_tlb_all
 swift_flush_tlb_mm:
 swift_flush_tlb_range:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_tlb_all_out
-#endif
 swift_flush_tlb_all:
 	mov	0x400, %o1
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
@@ -242,11 +236,9 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	swift_flush_tlb_page_out
 	 nop
-#endif
 #if 1
 	mov	0x400, %o1
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE	
diff -urN linux-2.4.19-pre4/arch/sparc/mm/tsunami.S linux-2.4.19-pre5/arch/sparc/mm/tsunami.S
--- linux-2.4.19-pre4/arch/sparc/mm/tsunami.S	Tue Jul 18 12:29:47 2000
+++ linux-2.4.19-pre5/arch/sparc/mm/tsunami.S	Fri Mar 29 14:49:25 2002
@@ -27,10 +27,8 @@
 tsunami_flush_cache_mm:
 tsunami_flush_cache_range:
 	ld	[%o0 + AOFF_mm_context], %g2
-#ifndef CONFIG_SMP
 	cmp	%g2, -1
 	be	tsunami_flush_cache_out
-#endif
 tsunami_flush_cache_all:
 	WINDOW_FLUSH(%g4, %g5)
 tsunami_flush_page_for_dma:
@@ -49,11 +47,9 @@
 	/* More slick stuff... */
 tsunami_flush_tlb_mm:
 tsunami_flush_tlb_range:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	tsunami_flush_tlb_out
-#endif
 tsunami_flush_tlb_all:
 	 mov	0x400, %o1
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
@@ -72,10 +68,8 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	tsunami_flush_tlb_page_out
-#endif
 	 lda	[%g1] ASI_M_MMUREGS, %g5
 	sta	%o3, [%g1] ASI_M_MMUREGS
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
diff -urN linux-2.4.19-pre4/arch/sparc64/defconfig linux-2.4.19-pre5/arch/sparc64/defconfig
--- linux-2.4.19-pre4/arch/sparc64/defconfig	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/defconfig	Fri Mar 29 14:49:25 2002
@@ -96,6 +96,7 @@
 CONFIG_FB_PM2=y
 # CONFIG_FB_PM2_FIFO_DISCONNECT is not set
 CONFIG_FB_PM2_PCI=y
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
@@ -260,6 +261,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -274,6 +276,7 @@
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -285,12 +288,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 CONFIG_BLK_DEV_ALI15X3=y
@@ -298,6 +304,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -305,6 +312,7 @@
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
@@ -314,6 +322,7 @@
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_ELEVATOR_NOOP is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
@@ -354,6 +363,7 @@
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=5000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
@@ -471,6 +481,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=m
+# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 CONFIG_DE4X5=m
@@ -505,7 +516,6 @@
 CONFIG_ACENIC=m
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 CONFIG_DL2K=m
-CONFIG_E1000=m
 CONFIG_MYRI_SBUS=m
 CONFIG_NS83820=m
 CONFIG_HAMACHI=m
@@ -748,8 +758,9 @@
 # CONFIG_USB_LONG_TIMEOUT is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+# CONFIG_USB_EHCI_HCD is not set
 CONFIG_USB_UHCI=y
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
@@ -758,6 +769,7 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
 CONFIG_USB_BLUETOOTH=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -848,6 +860,7 @@
 # USB Miscellaneous drivers
 #
 CONFIG_USB_RIO500=m
+# CONFIG_USB_AUERSWALD is not set
 
 #
 # Bluetooth support
@@ -876,3 +889,4 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
+# CONFIG_STACK_DEBUG is not set
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/ebus.c linux-2.4.19-pre5/arch/sparc64/kernel/ebus.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/ebus.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/ebus.c	Fri Mar 29 14:49:26 2002
@@ -275,6 +275,25 @@
 	printk("]");
 }
 
+static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
+{
+	struct pci_dev *pdev = start;
+
+	do {
+		pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev);
+		if (pdev &&
+		    (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
+		     pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
+			break;
+	} while (pdev != NULL);
+
+	if (pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
+		*is_rio_p = 1;
+	else
+		*is_rio_p = 0;
+
+	return pdev;
+}
 
 void __init ebus_init(void)
 {
@@ -289,12 +308,7 @@
 	if (!pci_present())
 		return;
 
-	is_rio = 0;
-	pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
-	if (!pdev) {
-		pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0);
-		is_rio = 1;
-	}
+	pdev = find_next_ebus(NULL, &is_rio);
 	if (!pdev) {
 		printk("ebus: No EBus's found.\n");
 		return;
@@ -315,16 +329,7 @@
 		   we'd have to tweak with the ebus_chain
 		   in the runtime after initialization. -jj */
 		if (!prom_getchild (ebusnd)) {
-			struct pci_dev *orig_pdev = pdev;
-
-			is_rio = 0;
-			pdev = pci_find_device(PCI_VENDOR_ID_SUN, 
-					       PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
-			if (!pdev) {
-				pdev = pci_find_device(PCI_VENDOR_ID_SUN, 
-						       PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
-				is_rio = 1;
-			}
+			pdev = find_next_ebus(pdev, &is_rio);
 			if (!pdev) {
 				if (ebus == ebus_chain) {
 					ebus_chain = NULL;
@@ -374,20 +379,9 @@
 	next_ebus:
 		printk("\n");
 
-		{
-			struct pci_dev *orig_pdev = pdev;
-
-			is_rio = 0;
-			pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-					       PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
-			if (!pdev) {
-				pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-						       PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
-				is_rio = 1;
-			}
-			if (!pdev)
-				break;
-		}
+		pdev = find_next_ebus(pdev, &is_rio);
+		if (!pdev)
+			break;
 
 		cookie = pdev->sysdata;
 		ebusnd = cookie->prom_node;
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/head.S linux-2.4.19-pre5/arch/sparc64/kernel/head.S
--- linux-2.4.19-pre4/arch/sparc64/kernel/head.S	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre5/arch/sparc64/kernel/head.S	Fri Mar 29 14:49:27 2002
@@ -567,13 +567,6 @@
 #define KERN_HIGHBITS		((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 
-#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 	mov	TSB_REG, %g1
 	stxa	%g0, [%g1] ASI_DMMU
 	membar	#Sync
@@ -604,8 +597,6 @@
 	clr	%g7
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
 
 	/* Setup Interrupt globals */
 	wrpr	%o1, (PSTATE_IG|PSTATE_IE), %pstate
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/ioctl32.c linux-2.4.19-pre5/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/ioctl32.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/ioctl32.c	Fri Mar 29 14:49:27 2002
@@ -1061,7 +1061,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("%s: Unknown fb ioctl cmd fd(%d) "
 				       "cmd(%08x) arg(%08lx)\n",
@@ -1714,7 +1714,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("ppp_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1824,7 +1824,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("mt_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1942,7 +1942,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("cdrom_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -2029,7 +2029,7 @@
 		}
 		break;
 	default: {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("%s: Unknown loop ioctl cmd, fd(%d) "
 			       "cmd(%08x) arg(%08lx)\n",
@@ -4887,7 +4887,7 @@
 		handler = (void *)(long)t->handler;
 		error = handler(fd, cmd, arg, filp);
 	} else {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
 			       "cmd(%08x) arg(%08x)\n",
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/irq.c linux-2.4.19-pre5/arch/sparc64/kernel/irq.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/irq.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre5/arch/sparc64/kernel/irq.c	Fri Mar 29 14:49:27 2002
@@ -81,7 +81,7 @@
  */
 #define MAX_STATIC_ALLOC	4
 static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-static int static_irq_count = 0;
+static int static_irq_count;
 
 /* This is exported so that fast IRQ handlers can get at it... -DaveM */
 struct irqaction *irq_action[NR_IRQS+1] = {
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/pci.c linux-2.4.19-pre5/arch/sparc64/kernel/pci.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/pci.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/pci.c	Fri Mar 29 14:49:27 2002
@@ -234,33 +234,63 @@
 	return request_resource(root, res);
 }
 
+/*
+ * Given the PCI bus a device resides on, try to
+ * find an acceptable resource allocation for a
+ * specific device resource..
+ */
+static int pci_assign_bus_resource(const struct pci_bus *bus,
+	struct pci_dev *dev,
+	struct resource *res,
+	unsigned long size,
+	unsigned long min,
+	int resno)
+{
+	unsigned int type_mask;
+	int i;
+
+	type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+	for (i = 0 ; i < 4; i++) {
+		struct resource *r = bus->resource[i];
+		if (!r)
+			continue;
+
+		/* type_mask must match */
+		if ((res->flags ^ r->flags) & type_mask)
+			continue;
+
+		/* Ok, try it out.. */
+		if (allocate_resource(r, res, size, min, -1, size, NULL, NULL) < 0)
+			continue;
+
+		/* PCI config space updated by caller.  */
+		return 0;
+	}
+	return -EBUSY;
+}
+
 int pci_assign_resource(struct pci_dev *pdev, int resource)
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = pcp->pbm;
 	struct resource *res = &pdev->resource[resource];
-	struct resource *root;
-	unsigned long min, max, size, align;
+	unsigned long min, size;
 	int err;
 
-	if (res->flags & IORESOURCE_IO) {
-		root = &pbm->io_space;
-		min = root->start + 0x400UL;
-		max = root->end;
-	} else {
-		root = &pbm->mem_space;
-		min = root->start;
-		max = min + 0x80000000UL;
-	}
+	if (res->flags & IORESOURCE_IO)
+		min = pbm->io_space.start + 0x400UL;
+	else
+		min = pbm->mem_space.start;
+
+	size = res->end - res->start + 1;
 
-	size = res->end - res->start;
-	align = size + 1;
+	err = pci_assign_bus_resource(pdev->bus, pdev, res, size, min, resource);
 
-	err = allocate_resource(root, res, size + 1, min, max, align, NULL, NULL);
 	if (err < 0) {
 		printk("PCI: Failed to allocate resource %d for %s\n",
 		       resource, pdev->name);
 	} else {
+		/* Update PCI config space. */
 		pbm->parent->base_address_update(pdev, resource);
 	}
 
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/pci_common.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_common.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/pci_common.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_common.c	Fri Mar 29 14:49:27 2002
@@ -571,14 +571,12 @@
 	struct pci_pbm_info *pbm = dev_pcp->pbm;
 	struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
 	unsigned int hi, mid, lo, irq;
-	int i, num_intmap;
-
-	if (pbm->num_pbm_intmap == 0)
-		return 0;
+	int i, num_intmap, map_slot;
 
 	intmap = &pbm->pbm_intmap[0];
 	intmask = &pbm->pbm_intmask;
 	num_intmap = pbm->num_pbm_intmap;
+	map_slot = 0;
 
 	/* If we are underneath a PCI bridge, use PROM register
 	 * property of the parent bridge which is closest to
@@ -639,11 +637,21 @@
 				printk("pci_intmap_match: Trying to recover.\n");
 				return 0;
 			}
+
+			if (pdev->bus->self != bus_dev)
+				map_slot = 1;
 		} else {
 			pregs = bus_pcp->prom_regs;
+			map_slot = 1;
 		}
 	}
 
+	if (map_slot) {
+		*interrupt = ((*interrupt
+			       - 1
+			       + PCI_SLOT(pdev->devfn)) & 0x3) + 1;
+	}
+
 	hi   = pregs->phys_hi & intmask->phys_hi;
 	mid  = pregs->phys_mid & intmask->phys_mid;
 	lo   = pregs->phys_lo & intmask->phys_lo;
@@ -655,24 +663,33 @@
 		    intmap[i].phys_lo  == lo	&&
 		    intmap[i].interrupt == irq) {
 			*interrupt = intmap[i].cinterrupt;
+			printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n",
+			       pdev->bus->number, PCI_SLOT(pdev->devfn),
+			       map_slot, *interrupt);
 			return 1;
 		}
 	}
 
-	/* Print it both to OBP console and kernel one so that if bootup
-	 * hangs here the user has the information to report.
+	/* We will run this code even if pbm->num_pbm_intmap is zero, just so
+	 * we can apply the slot mapping to the PROM interrupt property value.
+	 * So do not spit out these warnings in that case.
 	 */
-	prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
-		    pdev->bus->number, pdev->devfn);
-	prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
-		    pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
-	prom_printf("Please email this information to davem@redhat.com\n");
-
-	printk("pci_intmap_match: bus %02x, devfn %02x: ",
-	       pdev->bus->number, pdev->devfn);
-	printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
-	       pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
-	printk("Please email this information to davem@redhat.com\n");
+	if (num_intmap != 0) {
+		/* Print it both to OBP console and kernel one so that if bootup
+		 * hangs here the user has the information to report.
+		 */
+		prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
+			    pdev->bus->number, pdev->devfn);
+		prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+			    pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+		prom_printf("Please email this information to davem@redhat.com\n");
+
+		printk("pci_intmap_match: bus %02x, devfn %02x: ",
+		       pdev->bus->number, pdev->devfn);
+		printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+		       pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+		printk("Please email this information to davem@redhat.com\n");
+	}
 
 	return 0;
 }
@@ -720,20 +737,6 @@
 		goto have_irq;
 	}
 
-	/* Firmware gets quad-hme interrupts property totally
-	 * wrong.  It is 4 EBUS+HME devices behind a Digital bridge.
-	 * For each of the 4 instances the EBUS has interrupt property
-	 * '1' and the HME has interrupt property '2'.  So we have to
-	 * fix this up.
-	 */
-	if (!strcmp(pcp->prom_name, "SUNW,qfe") ||
-	    !strcmp(pcp->prom_name, "qfe")) {
-		if (PCI_SLOT(pdev->devfn) & ~3)
-			BUG();
-
-		prom_irq = PCI_SLOT(pdev->devfn) + 1;
-	}
-
 	/* Can we find a matching entry in the interrupt-map? */
 	if (pci_intmap_match(pdev, &prom_irq)) {
 		pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq);
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/pci_psycho.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_psycho.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/pci_psycho.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_psycho.c	Fri Mar 29 14:49:27 2002
@@ -1101,7 +1101,14 @@
 	int where, size, is_64bit;
 
 	res = &pdev->resource[resource];
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
@@ -1117,6 +1124,10 @@
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - root->start)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
 	pci_write_config_dword(pdev, where, reg);
 
 	/* This knows that the upper 32-bits of the address
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/pci_sabre.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_sabre.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/pci_sabre.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_sabre.c	Fri Mar 29 14:49:27 2002
@@ -1067,7 +1067,14 @@
 	int where, size, is_64bit;
 
 	res = &pdev->resource[resource];
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
@@ -1083,6 +1090,10 @@
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - base)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
 	pci_write_config_dword(pdev, where, reg);
 
 	/* This knows that the upper 32-bits of the address
@@ -1148,7 +1159,7 @@
 
 static void __init sabre_scan_bus(struct pci_controller_info *p)
 {
-	static int once = 0;
+	static int once;
 	struct pci_bus *sabre_bus;
 	struct pci_pbm_info *pbm;
 	struct pcidev_cookie *cookie;
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/pci_schizo.c linux-2.4.19-pre5/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/pci_schizo.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/pci_schizo.c	Fri Mar 29 14:49:27 2002
@@ -383,7 +383,7 @@
 	struct ino_bucket *bucket;
 	unsigned long imap, iclr, pbm_off;
 	unsigned long imap_off, iclr_off;
-	int pil, inofixup = 0;
+	int pil;
 
 	if (pbm == &p->pbm_A)
 		pbm_off = SCHIZO_PBM_A_REGS_OFF;
@@ -406,10 +406,13 @@
 	iclr = p->controller_regs + pbm_off + iclr_off;
 	iclr += 4;
 
-	if (ino < 0x18)
-		inofixup = ino & 0x03;
-
-	bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+	/* On Schizo, no inofixup occurs.  This is because each
+	 * INO has it's own IMAP register.  On Psycho and Sabre
+	 * there is only one IMAP register for each PCI slot even
+	 * though four different INOs can be generated by each
+	 * PCI slot.
+	 */
+	bucket = __bucket(build_irq(pil, 0, iclr, imap));
 	bucket->flags |= IBF_PCI;
 
 	return __irq(bucket);
@@ -1423,7 +1426,14 @@
 	int where, size, is_64bit;
 
 	res = &pdev->resource[resource];
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
@@ -1439,6 +1449,10 @@
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - root->start)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
 	pci_write_config_dword(pdev, where, reg);
 
 	/* This knows that the upper 32-bits of the address
@@ -1469,24 +1483,12 @@
 #define SCHIZO_PCI_B_IO_MATCH		0x00070UL
 #define SCHIZO_PCI_B_IO_MASK		0x00078UL
 
-/* VAL must be non-zero. */
-static unsigned long strip_to_lowest_bit_set(unsigned long val)
-{
-	unsigned long tmp;
-
-	tmp = 1UL;
-	while (!(tmp & val))
-		tmp <<= 1UL;
-
-	return tmp;
-}
-
 static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,
 					  int is_pbm_a, unsigned long reg_base)
 {
 	u64 mem_match, mem_mask;
 	u64 io_match;
-	u64 long a, b;
+	u64 a;
 
 	if (is_pbm_a) {
 		mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH;
@@ -1498,11 +1500,12 @@
 	mem_mask = mem_match + 0x8UL;
 
 	a = schizo_read(mem_match) & ~0x8000000000000000UL;
-	b = strip_to_lowest_bit_set(schizo_read(mem_mask));
 
-	/* It should be 2GB in size. */
+	/* It should be 2GB in size but the decode is set for the full
+	 * 4GB so we have to add the 2G by hand.
+	 */
 	pbm->mem_space.start = a;
-	pbm->mem_space.end = a + (b - 1UL);
+	pbm->mem_space.end = a + 0x80000000;
 	pbm->mem_space.flags = IORESOURCE_MEM;
 
 	/* This 32MB area is divided into two pieces.  The first
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/power.c linux-2.4.19-pre5/arch/sparc64/kernel/power.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/power.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/power.c	Fri Mar 29 14:49:27 2002
@@ -22,7 +22,7 @@
 #define POWER_COURTESY_OFF (1 << 1)
 
 static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed = 0;
+static int button_pressed;
 
 static void power_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -81,7 +81,7 @@
 {
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
-	static int invoked = 0;
+	static int invoked;
 
 	if (invoked)
 		return;
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/smp.c linux-2.4.19-pre5/arch/sparc64/kernel/smp.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/smp.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/smp.c	Fri Mar 29 14:49:28 2002
@@ -46,8 +46,8 @@
 volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 /* Please don't make this stuff initdata!!!  --DaveM */
-static unsigned char boot_cpu_id = 0;
-static int smp_activated = 0;
+static unsigned char boot_cpu_id;
+static int smp_activated;
 
 /* Kernel spinlock */
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
@@ -904,7 +904,7 @@
 
 static atomic_t smp_capture_depth = ATOMIC_INIT(0);
 static atomic_t smp_capture_registry = ATOMIC_INIT(0);
-static unsigned long penguins_are_doing_time = 0;
+static unsigned long penguins_are_doing_time;
 
 void smp_capture(void)
 {
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/sys_sparc.c linux-2.4.19-pre5/arch/sparc64/kernel/sys_sparc.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/sys_sparc.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/sys_sparc.c	Fri Mar 29 14:49:28 2002
@@ -380,7 +380,7 @@
 asmlinkage unsigned long
 c_sys_nis_syscall (struct pt_regs *regs)
 {
-	static int count=0;
+	static int count;
 	
 	/* Don't make the system unusable, if someone goes stuck */
 	if (count++ > 5)
@@ -450,7 +450,7 @@
 
 asmlinkage int solaris_syscall(struct pt_regs *regs)
 {
-	static int count = 0;
+	static int count;
 
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
@@ -470,7 +470,7 @@
 #ifndef CONFIG_SUNOS_EMUL
 asmlinkage int sunos_syscall(struct pt_regs *regs)
 {
-	static int count = 0;
+	static int count;
 
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/sys_sunos32.c linux-2.4.19-pre5/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/sys_sunos32.c	Tue Aug 14 19:57:28 2001
+++ linux-2.4.19-pre5/arch/sparc64/kernel/sys_sunos32.c	Fri Mar 29 14:49:28 2002
@@ -210,7 +210,7 @@
 
 asmlinkage void sunos_vadvise(u32 strategy)
 {
-	static int count = 0;
+	static int count;
 
 	/* I wanna see who uses this... */
 	if (count++ < 5)
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/time.c linux-2.4.19-pre5/arch/sparc64/kernel/time.c
--- linux-2.4.19-pre4/arch/sparc64/kernel/time.c	Fri Mar 29 14:49:07 2002
+++ linux-2.4.19-pre5/arch/sparc64/kernel/time.c	Fri Mar 29 14:49:28 2002
@@ -62,7 +62,7 @@
 static __inline__ void timer_check_rtc(void)
 {
 	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
+	static long last_rtc_update;
 
 	/* Determine when to update the Mostek clock. */
 	if ((time_status & STA_UNSYNC) == 0 &&
@@ -410,7 +410,7 @@
 	struct linux_ebus *ebus = NULL;
 	struct isa_bridge *isa_br = NULL;
 #endif
-	static int invoked = 0;
+	static int invoked;
 
 	if (invoked)
 		return;
diff -urN linux-2.4.19-pre4/arch/sparc64/kernel/trampoline.S linux-2.4.19-pre5/arch/sparc64/kernel/trampoline.S
--- linux-2.4.19-pre4/arch/sparc64/kernel/trampoline.S	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre5/arch/sparc64/kernel/trampoline.S	Fri Mar 29 14:49:28 2002
@@ -218,13 +218,6 @@
 #define KERN_HIGHBITS		((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 
-#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 	mov		TSB_REG, %g1
 	stxa		%g0, [%g1] ASI_DMMU
 	membar		#Sync
@@ -255,8 +248,6 @@
 	clr	%g7
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
 
 	/* Setup interrupt globals, we are always SMP. */
 	wrpr		%o1, PSTATE_IG, %pstate
diff -urN linux-2.4.19-pre4/arch/sparc64/mm/init.c linux-2.4.19-pre5/arch/sparc64/mm/init.c
--- linux-2.4.19-pre4/arch/sparc64/mm/init.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre5/arch/sparc64/mm/init.c	Fri Mar 29 14:49:28 2002
@@ -616,7 +616,7 @@
 	}
 }
 
-static int prom_ditlb_set = 0;
+static int prom_ditlb_set;
 struct prom_tlb_entry {
 	int		tlb_ent;
 	unsigned long	tlb_tag;
diff -urN linux-2.4.19-pre4/arch/sparc64/prom/bootstr.c linux-2.4.19-pre5/arch/sparc64/prom/bootstr.c
--- linux-2.4.19-pre4/arch/sparc64/prom/bootstr.c	Tue Aug 31 11:23:30 1999
+++ linux-2.4.19-pre5/arch/sparc64/prom/bootstr.c	Fri Mar 29 14:49:28 2002
@@ -9,6 +9,11 @@
 #include <linux/init.h>
 #include <asm/oplib.h>
 
+/* WARNING: The boot loader knows that these next three variables come one right
+ *          after another in the .data section.  Do not move this stuff into
+ *          the .bss section or it will break things.
+ */
+
 #define BARG_LEN  256
 int bootstr_len = BARG_LEN;
 static int bootstr_valid = 0;
diff -urN linux-2.4.19-pre4/arch/sparc64/prom/misc.c linux-2.4.19-pre5/arch/sparc64/prom/misc.c
--- linux-2.4.19-pre4/arch/sparc64/prom/misc.c	Mon Oct  1 09:19:56 2001
+++ linux-2.4.19-pre5/arch/sparc64/prom/misc.c	Fri Mar 29 14:49:28 2002
@@ -171,7 +171,7 @@
 
 static int prom_get_memory_ihandle(void)
 {
-	static int memory_ihandle_cache = 0;
+	static int memory_ihandle_cache;
 	int node, ret;
 
 	if (memory_ihandle_cache != 0)
diff -urN linux-2.4.19-pre4/arch/sparc64/solaris/misc.c linux-2.4.19-pre5/arch/sparc64/solaris/misc.c
--- linux-2.4.19-pre4/arch/sparc64/solaris/misc.c	Thu Sep 20 14:11:57 2001
+++ linux-2.4.19-pre5/arch/sparc64/solaris/misc.c	Fri Mar 29 14:49:28 2002
@@ -56,7 +56,7 @@
 	/* Do we need it here? */
 	set_personality(PER_SVR4);
 	if (flags & MAP_NORESERVE) {
-		static int cnt = 0;
+		static int cnt;
 		
 		if (cnt < 5) {
 			printk("%s:  unimplemented Solaris MAP_NORESERVE mmap() flag\n",
diff -urN linux-2.4.19-pre4/arch/sparc64/solaris/timod.c linux-2.4.19-pre5/arch/sparc64/solaris/timod.c
--- linux-2.4.19-pre4/arch/sparc64/solaris/timod.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre5/arch/sparc64/solaris/timod.c	Fri Mar 29 14:49:28 2002
@@ -46,7 +46,7 @@
 void * mykmalloc(size_t s, int gfp)
 {
 	static char * page;
-	static size_t free = 0;
+	static size_t free;
 	void * r;
 	s = ((s + 63) & ~63);
 	if( s > PAGE_SIZE ) {
diff -urN linux-2.4.19-pre4/drivers/block/ll_rw_blk.c linux-2.4.19-pre5/drivers/block/ll_rw_blk.c
--- linux-2.4.19-pre4/drivers/block/ll_rw_blk.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/block/ll_rw_blk.c	Fri Mar 29 14:49:29 2002
@@ -117,16 +117,6 @@
  */
 int * max_sectors[MAX_BLKDEV];
 
-/*
- * The total number of requests in each queue.
- */
-static int queue_nr_requests;
-
-/*
- * The threshold around which we make wakeup decisions
- */
-static int batch_requests;
-
 static inline int get_max_sectors(kdev_t dev)
 {
 	if (!max_sectors[MAJOR(dev)])
@@ -180,7 +170,7 @@
  **/
 void blk_cleanup_queue(request_queue_t * q)
 {
-	int count = queue_nr_requests;
+	int count = q->nr_requests;
 
 	count -= __blk_cleanup_queue(&q->rq[READ]);
 	count -= __blk_cleanup_queue(&q->rq[WRITE]);
@@ -330,31 +320,64 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
+/** blk_grow_request_list
+ *  @q: The &request_queue_t
+ *  @nr_requests: how many requests are desired
+ *
+ * More free requests are added to the queue's free lists, bringing
+ * the total number of requests to @nr_requests.
+ *
+ * The requests are added equally to the request queue's read
+ * and write freelists.
+ *
+ * This function can sleep.
+ *
+ * Returns the (new) number of requests which the queue has available.
+ */
+int blk_grow_request_list(request_queue_t *q, int nr_requests)
+{
+	spin_lock_irq(&io_request_lock);
+	while (q->nr_requests < nr_requests) {
+		struct request *rq;
+		int rw;
+
+		spin_unlock_irq(&io_request_lock);
+		rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL);
+		spin_lock_irq(&io_request_lock);
+		if (rq == NULL)
+			break;
+		memset(rq, 0, sizeof(*rq));
+		rq->rq_status = RQ_INACTIVE;
+		rw = q->nr_requests & 1;
+		list_add(&rq->queue, &q->rq[rw].free);
+		q->rq[rw].count++;
+		q->nr_requests++;
+	}
+	q->batch_requests = q->nr_requests / 4;
+	if (q->batch_requests > 32)
+		q->batch_requests = 32;
+	spin_unlock_irq(&io_request_lock);
+	return q->nr_requests;
+}
+
 static void blk_init_free_list(request_queue_t *q)
 {
-	struct request *rq;
-	int i;
+	struct sysinfo si;
+	int megs;		/* Total memory, in megabytes */
+	int nr_requests;
 
 	INIT_LIST_HEAD(&q->rq[READ].free);
 	INIT_LIST_HEAD(&q->rq[WRITE].free);
 	q->rq[READ].count = 0;
 	q->rq[WRITE].count = 0;
+	q->nr_requests = 0;
 
-	/*
-	 * Divide requests in half between read and write
-	 */
-	for (i = 0; i < queue_nr_requests; i++) {
-		rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL);
-		if (rq == NULL) {
-			/* We'll get a `leaked requests' message from blk_cleanup_queue */
-			printk(KERN_EMERG "blk_init_free_list: error allocating requests\n");
-			break;
-		}
-		memset(rq, 0, sizeof(struct request));
-		rq->rq_status = RQ_INACTIVE;
-		list_add(&rq->queue, &q->rq[i&1].free);
-		q->rq[i&1].count++;
-	}
+	si_meminfo(&si);
+	megs = si.totalram >> (20 - PAGE_SHIFT);
+	nr_requests = 128;
+	if (megs < 32)
+		nr_requests /= 2;
+	blk_grow_request_list(q, nr_requests);
 
 	init_waitqueue_head(&q->wait_for_requests[0]);
 	init_waitqueue_head(&q->wait_for_requests[1]);
@@ -610,7 +633,7 @@
 	 */
 	if (q) {
 		list_add(&req->queue, &q->rq[rw].free);
-		if (++q->rq[rw].count >= batch_requests &&
+		if (++q->rq[rw].count >= q->batch_requests &&
 				waitqueue_active(&q->wait_for_requests[rw]))
 			wake_up(&q->wait_for_requests[rw]);
 	}
@@ -802,7 +825,7 @@
 		 * See description above __get_request_wait()
 		 */
 		if (rw_ahead) {
-			if (q->rq[rw].count < batch_requests) {
+			if (q->rq[rw].count < q->batch_requests) {
 				spin_unlock_irq(&io_request_lock);
 				goto end_io;
 			}
@@ -958,6 +981,7 @@
 		BUG();
 
 	set_bit(BH_Req, &bh->b_state);
+	set_bit(BH_Launder, &bh->b_state);
 
 	/*
 	 * First step, 'identity mapping' - RAID or LVM might
@@ -1149,12 +1173,9 @@
 	blkdev_release_request(req);
 }
 
-#define MB(kb)	((kb) << 10)
-
 int __init blk_dev_init(void)
 {
 	struct blk_dev_struct *dev;
-	int total_ram;
 
 	request_cachep = kmem_cache_create("blkdev_requests",
 					   sizeof(struct request),
@@ -1170,22 +1191,6 @@
 	memset(max_readahead, 0, sizeof(max_readahead));
 	memset(max_sectors, 0, sizeof(max_sectors));
 
-	total_ram = nr_free_pages() << (PAGE_SHIFT - 10);
-
-	/*
-	 * Free request slots per queue.
-	 * (Half for reads, half for writes)
-	 */
-	queue_nr_requests = 64;
-	if (total_ram > MB(32))
-		queue_nr_requests = 128;
-
-	/*
-	 * Batch frees according to queue length
-	 */
-	batch_requests = queue_nr_requests/4;
-	printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests);
-
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
 #endif
@@ -1296,6 +1301,7 @@
 EXPORT_SYMBOL(io_request_lock);
 EXPORT_SYMBOL(end_that_request_first);
 EXPORT_SYMBOL(end_that_request_last);
+EXPORT_SYMBOL(blk_grow_request_list);
 EXPORT_SYMBOL(blk_init_queue);
 EXPORT_SYMBOL(blk_get_queue);
 EXPORT_SYMBOL(blk_cleanup_queue);
diff -urN linux-2.4.19-pre4/drivers/block/rd.c linux-2.4.19-pre5/drivers/block/rd.c
--- linux-2.4.19-pre4/drivers/block/rd.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/block/rd.c	Fri Mar 29 14:49:29 2002
@@ -44,9 +44,6 @@
 
 #include <linux/config.h>
 #include <linux/sched.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/romfs_fs.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/hdreg.h>
@@ -79,18 +76,9 @@
 /* The RAM disk size is now a parameter */
 #define NUM_RAMDISKS 16		/* This cannot be overridden (yet) */ 
 
-#ifndef MODULE
-/* We don't have to load RAM disks or gunzip them in a module. */
-#define RD_LOADER
-#define BUILD_CRAMDISK
-
-void rd_load(void);
-static int crd_load(struct file *fp, struct file *outfp);
-
 #ifdef CONFIG_BLK_DEV_INITRD
 static int initrd_users;
 #endif
-#endif
 
 /* Various static variables go here.  Most are used only in the RAM disk code.
  */
@@ -536,6 +524,8 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* We ought to separate initrd operations here */
 	register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &rd_bd_op, rd_size<<1);
+	devfs_register(devfs_handle, "initrd", DEVFS_FL_DEFAULT, MAJOR_NR,
+			INITRD_MINOR, S_IFBLK | S_IRUSR, &rd_bd_op, NULL);
 #endif
 
 	hardsect_size[MAJOR_NR] = rd_hardsec;		/* Size of the RAM disk blocks */
@@ -562,462 +552,3 @@
 MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes.");
 
 MODULE_LICENSE("GPL");
-
-/* End of non-loading portions of the RAM disk driver */
-
-#ifdef RD_LOADER 
-/*
- * This routine tries to find a RAM disk image to load, and returns the
- * number of blocks to read for a non-compressed image, 0 if the image
- * is a compressed image, and -1 if an image with the right magic
- * numbers could not be found.
- *
- * We currently check for the following magic numbers:
- * 	minix
- * 	ext2
- *	romfs
- * 	gzip
- */
-static int __init 
-identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
-{
-	const int size = 512;
-	struct minix_super_block *minixsb;
-	struct ext2_super_block *ext2sb;
-	struct romfs_super_block *romfsb;
-	int nblocks = -1;
-	unsigned char *buf;
-
-	buf = kmalloc(size, GFP_KERNEL);
-	if (buf == 0)
-		return -1;
-
-	minixsb = (struct minix_super_block *) buf;
-	ext2sb = (struct ext2_super_block *) buf;
-	romfsb = (struct romfs_super_block *) buf;
-	memset(buf, 0xe5, size);
-
-	/*
-	 * Read block 0 to test for gzipped kernel
-	 */
-	if (fp->f_op->llseek)
-		fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0);
-	fp->f_pos = start_block * BLOCK_SIZE;
-	
-	fp->f_op->read(fp, buf, size, &fp->f_pos);
-
-	/*
-	 * If it matches the gzip magic numbers, return -1
-	 */
-	if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
-		printk(KERN_NOTICE
-		       "RAMDISK: Compressed image found at block %d\n",
-		       start_block);
-		nblocks = 0;
-		goto done;
-	}
-
-	/* romfs is at block zero too */
-	if (romfsb->word0 == ROMSB_WORD0 &&
-	    romfsb->word1 == ROMSB_WORD1) {
-		printk(KERN_NOTICE
-		       "RAMDISK: romfs filesystem found at block %d\n",
-		       start_block);
-		nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
-		goto done;
-	}
-
-	/*
-	 * Read block 1 to test for minix and ext2 superblock
-	 */
-	if (fp->f_op->llseek)
-		fp->f_op->llseek(fp, (start_block+1) * BLOCK_SIZE, 0);
-	fp->f_pos = (start_block+1) * BLOCK_SIZE;
-
-	fp->f_op->read(fp, buf, size, &fp->f_pos);
-		
-	/* Try minix */
-	if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
-	    minixsb->s_magic == MINIX_SUPER_MAGIC2) {
-		printk(KERN_NOTICE
-		       "RAMDISK: Minix filesystem found at block %d\n",
-		       start_block);
-		nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
-		goto done;
-	}
-
-	/* Try ext2 */
-	if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
-		printk(KERN_NOTICE
-		       "RAMDISK: ext2 filesystem found at block %d\n",
-		       start_block);
-		nblocks = le32_to_cpu(ext2sb->s_blocks_count);
-		goto done;
-	}
-
-	printk(KERN_NOTICE
-	       "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
-	       start_block);
-	
-done:
-	if (fp->f_op->llseek)
-		fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0);
-	fp->f_pos = start_block * BLOCK_SIZE;	
-
-	kfree(buf);
-	return nblocks;
-}
-
-/*
- * This routine loads in the RAM disk image.
- */
-static void __init rd_load_image(kdev_t device, int offset, int unit)
-{
- 	struct inode *inode, *out_inode;
-	struct file infile, outfile;
-	struct dentry in_dentry, out_dentry;
-	mm_segment_t fs;
-	kdev_t ram_device;
-	int nblocks, i;
-	char *buf;
-	unsigned short rotate = 0;
-	unsigned short devblocks = 0;
-#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
-	char rotator[4] = { '|' , '/' , '-' , '\\' };
-#endif
-	ram_device = MKDEV(MAJOR_NR, unit);
-
-	if ((inode = get_empty_inode()) == NULL)
-		return;
-	memset(&infile, 0, sizeof(infile));
-	memset(&in_dentry, 0, sizeof(in_dentry));
-	infile.f_mode = 1; /* read only */
-	infile.f_dentry = &in_dentry;
-	in_dentry.d_inode = inode;
-	infile.f_op = &def_blk_fops;
-	init_special_inode(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device));
-
-	if ((out_inode = get_empty_inode()) == NULL)
-		goto free_inode;
-	memset(&outfile, 0, sizeof(outfile));
-	memset(&out_dentry, 0, sizeof(out_dentry));
-	outfile.f_mode = 3; /* read/write */
-	outfile.f_dentry = &out_dentry;
-	out_dentry.d_inode = out_inode;
-	outfile.f_op = &def_blk_fops;
-	init_special_inode(out_inode, S_IFBLK | S_IRUSR | S_IWUSR, kdev_t_to_nr(ram_device));
-
-	if (blkdev_open(inode, &infile) != 0) {
-		iput(out_inode);
-		goto free_inode;
-	}
-	if (blkdev_open(out_inode, &outfile) != 0)
-		goto free_inodes;
-
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	
-	nblocks = identify_ramdisk_image(device, &infile, offset);
-	if (nblocks < 0)
-		goto done;
-
-	if (nblocks == 0) {
-#ifdef BUILD_CRAMDISK
-		if (crd_load(&infile, &outfile) == 0)
-			goto successful_load;
-#else
-		printk(KERN_NOTICE
-		       "RAMDISK: Kernel does not support compressed "
-		       "RAM disk images\n");
-#endif
-		goto done;
-	}
-
-	/*
-	 * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so
-	 * rd_load_image will work only with filesystem BLOCK_SIZE wide!
-	 * So make sure to use 1k blocksize while generating ext2fs
-	 * ramdisk-images.
-	 */
-	if (nblocks > (rd_length[unit] >> BLOCK_SIZE_BITS)) {
-		printk("RAMDISK: image too big! (%d/%ld blocks)\n",
-		       nblocks, rd_length[unit] >> BLOCK_SIZE_BITS);
-		goto done;
-	}
-		
-	/*
-	 * OK, time to copy in the data
-	 */
-	buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
-	if (buf == 0) {
-		printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
-		goto done;
-	}
-
-	if (blk_size[MAJOR(device)])
-		devblocks = blk_size[MAJOR(device)][MINOR(device)];
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (MAJOR(device) == MAJOR_NR && MINOR(device) == INITRD_MINOR)
-		devblocks = nblocks;
-#endif
-
-	if (devblocks == 0) {
-		printk(KERN_ERR "RAMDISK: could not determine device size\n");
-		goto done;
-	}
-
-	printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", 
-		nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
-	for (i=0; i < nblocks; i++) {
-		if (i && (i % devblocks == 0)) {
-			printk("done disk #%d.\n", i/devblocks);
-			rotate = 0;
-			if (infile.f_op->release(inode, &infile) != 0) {
-				printk("Error closing the disk.\n");
-				goto noclose_input;
-			}
-			printk("Please insert disk #%d and press ENTER\n", i/devblocks+1);
-			wait_for_keypress();
-			if (blkdev_open(inode, &infile) != 0)  {
-				printk("Error opening disk.\n");
-				goto noclose_input;
-			}
-			infile.f_pos = 0;
-			printk("Loading disk #%d... ", i/devblocks+1);
-		}
-		infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos);
-		outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);
-#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
-		if (!(i % 16)) {
-			printk("%c\b", rotator[rotate & 0x3]);
-			rotate++;
-		}
-#endif
-	}
-	printk("done.\n");
-	kfree(buf);
-
-successful_load:
-	ROOT_DEV = MKDEV(MAJOR_NR, unit);
-	if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0");
-
-done:
-	infile.f_op->release(inode, &infile);
-noclose_input:
-	blkdev_close(out_inode, &outfile);
-	iput(inode);
-	iput(out_inode);
-	set_fs(fs);
-	return;
-free_inodes: /* free inodes on error */ 
-	iput(out_inode);
-	infile.f_op->release(inode, &infile);
-free_inode:
-	iput(inode);
-}
-
-#ifdef CONFIG_MAC_FLOPPY
-int swim3_fd_eject(int devnum);
-#endif
-
-static void __init rd_load_disk(int n)
-{
-
-	if (rd_doload == 0)
-		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
-		floppy_eject();
-#endif
-#ifdef CONFIG_MAC_FLOPPY
-		if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR)
-			swim3_fd_eject(MINOR(ROOT_DEV));
-		else if(MAJOR(real_root_dev) == FLOPPY_MAJOR)
-			swim3_fd_eject(MINOR(real_root_dev));
-#endif
-		printk(KERN_NOTICE
-		       "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n");
-		wait_for_keypress();
-	}
-
-	rd_load_image(ROOT_DEV,rd_image_start, n);
-
-}
-
-void __init rd_load(void)
-{
-	rd_load_disk(0);
-}
-
-void __init rd_load_secondary(void)
-{
-	rd_load_disk(1);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init initrd_load(void)
-{
-	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);
-}
-#endif
-
-#endif /* RD_LOADER */
-
-#ifdef BUILD_CRAMDISK
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-
-#ifndef memzero
-#define memzero(s, n)     memset ((s), 0, (n))
-#endif
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000    /* window size--must be a power of two, and */
-			/*  at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize;  /* valid bytes in inbuf */
-static unsigned inptr;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt;  /* bytes in output buffer */
-static int exit_code;
-static long bytes_out;
-static struct file *crd_infp, *crd_outfp;
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-		
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int  fill_inbuf(void);
-static void flush_window(void);
-static void *malloc(int size);
-static void free(void *where);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#include "../../lib/inflate.c"
-
-static void __init *malloc(int size)
-{
-	return kmalloc(size, GFP_KERNEL);
-}
-
-static void __init free(void *where)
-{
-	kfree(where);
-}
-
-static void __init gzip_mark(void **ptr)
-{
-}
-
-static void __init gzip_release(void **ptr)
-{
-}
-
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int __init fill_inbuf(void)
-{
-	if (exit_code) return -1;
-	
-	insize = crd_infp->f_op->read(crd_infp, inbuf, INBUFSIZ,
-				      &crd_infp->f_pos);
-	if (insize == 0) return -1;
-
-	inptr = 1;
-
-	return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void __init flush_window(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, ch;
-    
-    crd_outfp->f_op->write(crd_outfp, window, outcnt, &crd_outfp->f_pos);
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-	    ch = *in++;
-	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void __init error(char *x)
-{
-	printk(KERN_ERR "%s", x);
-	exit_code = 1;
-}
-
-static int __init 
-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);
-	if (inbuf == 0) {
-		printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
-		return -1;
-	}
-	window = kmalloc(WSIZE, GFP_KERNEL);
-	if (window == 0) {
-		printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
-		kfree(inbuf);
-		return -1;
-	}
-	makecrc();
-	result = gunzip();
-	kfree(inbuf);
-	kfree(window);
-	return result;
-}
-
-#endif  /* BUILD_CRAMDISK */
-
diff -urN linux-2.4.19-pre4/drivers/block/xd.c linux-2.4.19-pre5/drivers/block/xd.c
--- linux-2.4.19-pre4/drivers/block/xd.c	Fri Nov  9 14:01:21 2001
+++ linux-2.4.19-pre5/drivers/block/xd.c	Fri Mar 29 14:49:29 2002
@@ -107,6 +107,8 @@
 	{ 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
 	{ 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
 	{ 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
+	{ 0x0008,"(C) Copyright 1984 Western Digital Corp", xd_wd_init_controller, xd_wd_init_drive," Western Dig. 1002s-wx2" },
+	{ 0x0008,"(C) Copyright 1986 Western Digital Corporation", xd_wd_init_controller, xd_wd_init_drive," 1986 Western Digital" }, /* jfree@sovereign.org */
 };
 
 static unsigned int xd_bases[] __initdata =
diff -urN linux-2.4.19-pre4/drivers/char/Config.in linux-2.4.19-pre5/drivers/char/Config.in
--- linux-2.4.19-pre4/drivers/char/Config.in	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/char/Config.in	Fri Mar 29 14:49:29 2002
@@ -62,7 +62,7 @@
      tristate '    Stallion EasyIO or EC8/32 support' CONFIG_STALLION
      tristate '    Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
-   if [ "CONFIG_MIPS" = "y" ]; then
+   if [ "$CONFIG_MIPS" = "y" ]; then
      bool '  TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
      dep_bool '     Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
      bool '  Enable Au1000 UART Support' CONFIG_AU1000_UART
@@ -154,6 +154,7 @@
    bool '  PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
    tristate '  C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
    tristate '  PC110 digitizer pad support' CONFIG_PC110_PAD
+   tristate '  MK712 touch screen support' CONFIG_MK712_MOUSE
 fi
 endmenu
 
@@ -201,7 +202,9 @@
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
    tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  ZF MachZ Watchdog' CONFIG_MACHZ_WDT
-   dep_tristate '  Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22
+   if [ "$CONFIG_SGI_IP22" = "y" ]; then
+      tristate '  Indy/I2 Hardware Watchdog' CONFIG_INDYDOG
+   fi
 fi
 endmenu
 
@@ -214,6 +217,7 @@
    tristate 'NetWinder flash support' CONFIG_NWFLASH
 fi
 
+dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
 dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
diff -urN linux-2.4.19-pre4/drivers/char/Makefile linux-2.4.19-pre5/drivers/char/Makefile
--- linux-2.4.19-pre4/drivers/char/Makefile	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/char/Makefile	Fri Mar 29 14:49:29 2002
@@ -202,6 +202,7 @@
 obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
 obj-$(CONFIG_ADBMOUSE) += adbmouse.o
 obj-$(CONFIG_PC110_PAD) += pc110pad.o
+obj-$(CONFIG_MK712_MOUSE) += mk712.o
 obj-$(CONFIG_RTC) += rtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_PPC),)
@@ -211,6 +212,8 @@
 obj-$(CONFIG_I8K) += i8k.o
 obj-$(CONFIG_DS1620) += ds1620.o
 obj-$(CONFIG_INTEL_RNG) += i810_rng.o
+obj-$(CONFIG_AMD_RNG) += amd768_rng.o
+
 obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
 obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o
 obj-$(CONFIG_COBALT_LCD) += lcd.o
@@ -244,6 +247,8 @@
 obj-$(CONFIG_IB700_WDT) += ib700wdt.o
 obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
 obj-$(CONFIG_WDT) += wdt.o
 obj-$(CONFIG_WDTPCI) += wdt_pci.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
@@ -252,8 +257,11 @@
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
-obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 
 subdir-$(CONFIG_MWAVE) += mwave
 ifeq ($(CONFIG_MWAVE),y)
diff -urN linux-2.4.19-pre4/drivers/char/alim7101_wdt.c linux-2.4.19-pre5/drivers/char/alim7101_wdt.c
--- linux-2.4.19-pre4/drivers/char/alim7101_wdt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/char/alim7101_wdt.c	Fri Mar 29 14:49:29 2002
@@ -0,0 +1,335 @@
+/*
+ *	ALi M7101 PMU Computer Watchdog Timer driver for Linux 2.4.x
+ *
+ *	Based on w83877f_wdt.c by Scott Jennings <management@oro.net>
+ *	and the Cobalt kernel WDT timer driver by Tim Hockin
+ *	                                      <thockin@cobaltnet.com>
+ *
+ *	(c)2002 Steve Hill <steve@navaho.co.uk>
+ * 
+ *  Theory of operation:
+ *  A Watchdog Timer (WDT) is a hardware circuit that can 
+ *  reset the computer system in case of a software fault.
+ *  You probably knew that already.
+ *
+ *  Usually a userspace daemon will notify the kernel WDT driver
+ *  via the /proc/watchdog special device file that userspace is
+ *  still alive, at regular intervals.  When such a notification
+ *  occurs, the driver will usually tell the hardware watchdog
+ *  that everything is in order, and that the watchdog should wait
+ *  for yet another little while to reset the system.
+ *  If userspace fails (RAM error, kernel bug, whatever), the
+ *  notifications cease to occur, and the hardware watchdog will
+ *  reset the system (causing a reboot) after the timeout occurs.
+ *
+ *  This WDT driver is different from most other Linux WDT
+ *  drivers in that the driver will ping the watchdog by itself,
+ *  because this particular WDT has a very short timeout (1.6
+ *  seconds) and it would be insane to count on any userspace
+ *  daemon always getting scheduled within that time frame.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#define OUR_NAME "alim7101_wdt"
+
+#define WDT_ENABLE 0x9C
+#define WDT_DISABLE 0x8C
+
+#define ALI_7101_WDT    0x92
+#define ALI_WDT_ARM     0x01
+
+/*
+ * We're going to use a 1 second timeout.
+ * If we reset the watchdog every ~250ms we should be safe.  */
+
+#define WDT_INTERVAL (HZ/4+1)
+
+/*
+ * We must not require too good response from the userspace daemon.
+ * Here we require the userspace daemon to send us a heartbeat
+ * char to /dev/watchdog every 30 seconds.
+ */
+
+#define WDT_HEARTBEAT (HZ * 30)
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_is_open;
+static int wdt_expect_close;
+static struct pci_dev *alim7101_pmu;
+
+/*
+ *	Whack the dog
+ */
+
+static void wdt_timer_ping(unsigned long data)
+{
+	/* If we got a heartbeat pulse within the WDT_US_INTERVAL
+	 * we agree to ping the WDT 
+	 */
+	char	tmp;
+
+	if(time_before(jiffies, next_heartbeat)) 
+	{
+		/* Ping the WDT (this is actually a disarm/arm sequence) */
+		pci_read_config_byte(alim7101_pmu, 0x92, &tmp);
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
+	} else {
+		printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n");
+	}
+	/* Re-set the timer interval */
+	timer.expires = jiffies + WDT_INTERVAL;
+	add_timer(&timer);
+}
+
+/* 
+ * Utility routines
+ */
+
+static void wdt_change(int writeval)
+{
+	char	tmp;
+
+	pci_read_config_byte(alim7101_pmu, 0x92, &tmp);
+	if (writeval == WDT_ENABLE)
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
+	else
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
+}
+
+static void wdt_startup(void)
+{
+	next_heartbeat = jiffies + WDT_HEARTBEAT;
+
+	/* We must enable before we kick off the timer in case the timer
+	   occurs as we ping it */
+
+	wdt_change(WDT_ENABLE);
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;	
+	add_timer(&timer);
+
+
+	printk(OUR_NAME ": Watchdog timer is now enabled.\n");  
+}
+
+static void wdt_turnoff(void)
+{
+	/* Stop the timer */
+	del_timer_sync(&timer);
+	wdt_change(WDT_DISABLE);
+	printk(OUR_NAME ": Watchdog timer is now disabled...\n");
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos)
+{
+	/* We can't seek */
+	if(ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* See if we got the magic character */
+	if(count) 
+	{
+		size_t ofs;
+
+		/* note: just in case someone wrote the magic character
+		 * five months ago... */
+		wdt_expect_close = 0;
+
+		/* now scan */
+		for(ofs = 0; ofs != count; ofs++)
+			if(buf[ofs] == 'V')
+				wdt_expect_close = 1;
+
+		/* someone wrote to us, we should restart timer */
+		next_heartbeat = jiffies + WDT_HEARTBEAT;
+		return 1;
+	};
+	return 0;
+}
+
+static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos)
+{
+	/* No can do */
+	return -EINVAL;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	/* Just in case we're already talking to someone... */
+	if(test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+	/* Good, fire up the show */
+	wdt_startup();
+	return 0;
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+#ifdef CONFIG_WDT_NOWAYOUT
+	if(wdt_expect_close)
+		wdt_turnoff();
+	else {
+		printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
+	}
+#else
+	wdt_turnoff();
+#endif
+	clear_bit(0, &wdt_is_open);
+	return 0;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident=
+	{
+		0,
+		1,
+		"ALiM7101"
+	};
+	
+	switch(cmd)
+	{
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_KEEPALIVE:
+			next_heartbeat = jiffies + WDT_HEARTBEAT;
+			return 0;
+		default:
+			return -ENOTTY;
+	}
+}
+
+static struct file_operations wdt_fops = {
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		fop_read,
+	write:		fop_write,
+	open:		fop_open,
+	release:	fop_close,
+	ioctl:		fop_ioctl
+};
+
+static struct miscdevice wdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&wdt_fops
+};
+
+/*
+ *	Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) wdt_turnoff();
+	if (code==SYS_RESTART) {
+		/*
+		 * Cobalt devices have no way of rebooting themselves other than
+		 * getting the watchdog to pull reset, so we restart the watchdog on
+		 * reboot with no heartbeat
+		 */
+		wdt_change(WDT_ENABLE);
+		printk(OUR_NAME ": Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n");
+	};
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block wdt_notifier=
+{
+	wdt_notify_sys,
+	0,
+	0
+};
+
+static void __exit alim7101_wdt_unload(void)
+{
+	wdt_turnoff();
+	/* Deregister */
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+}
+
+static int __init alim7101_wdt_init(void)
+{
+	int rc = -EBUSY;
+	struct pci_dev *ali1543_south;
+	char tmp;
+
+	printk(KERN_INFO OUR_NAME ": Steve Hill <steve@navaho.co.uk>.\n");
+	alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL);
+	if (!alim7101_pmu) {
+		printk(KERN_INFO OUR_NAME ": ALi M7101 PMU not present - WDT not set\n");
+		return -EBUSY;
+	};
+	
+	/* Set the WDT in the PMU to 1 second */
+	pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
+
+	ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+	if (!ali1543_south) {
+		printk(KERN_INFO OUR_NAME ": ALi 1543 South-Bridge not present - WDT not set\n");
+		return -EBUSY;
+	};
+	pci_read_config_byte(ali1543_south, 0x5e, &tmp);
+	if ((tmp & 0x1e) != 0x12) {
+		printk(KERN_INFO OUR_NAME ": ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
+		return -EBUSY;
+	};
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 1;
+		
+	rc = misc_register(&wdt_miscdev);
+	if (rc)
+		return rc;
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc) {
+		misc_deregister(&wdt_miscdev);
+		return rc;
+	};
+	
+	printk(KERN_INFO OUR_NAME ": WDT driver for ALi M7101 initialised.\n");
+	return 0;
+}
+
+module_init(alim7101_wdt_init);
+module_exit(alim7101_wdt_unload);
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Steve Hill");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre4/drivers/char/drm/sis_ds.c linux-2.4.19-pre5/drivers/char/drm/sis_ds.c
--- linux-2.4.19-pre4/drivers/char/drm/sis_ds.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre5/drivers/char/drm/sis_ds.c	Fri Mar 29 14:49:29 2002
@@ -33,7 +33,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/poll.h>
 #include <asm/io.h>
 #include <linux/pci.h>
diff -urN linux-2.4.19-pre4/drivers/char/mk712.c linux-2.4.19-pre5/drivers/char/mk712.c
--- linux-2.4.19-pre4/drivers/char/mk712.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/char/mk712.c	Fri Mar 29 14:49:29 2002
@@ -0,0 +1,505 @@
+/* -*- c -*- --------------------------------------------------------- *
+ *
+ * linux/drivers/char/mk712.c
+ *
+ * Copyright 1999-2002 Transmeta Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver supports the MK712 touch screen.
+ * based on busmouse.c, pc_keyb.c, and other mouse drivers
+ *
+ * 1999-12-18: original version, Daniel Quinlan
+ * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
+ *             to use queue_empty, Nathan Laredo
+ * 1999-12-20: improved random point rejection, Nathan Laredo
+ * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
+ *             queue code, added module options, other fixes, Daniel Quinlan
+ * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
+ *	       Fixed multi open race, fixed memory checks, fixed resource
+ *	       allocation, fixed close/powerdown bug, switched to new init
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#define DEBUG(x)	x
+#define SQUARE(x)	((x)*(x))
+
+#define MK712_DEFAULT_IO 0x260		/* demo board: 0x200, 0x208, 0x300 */
+#define MK712_DEFAULT_IRQ 10		/* demo board: 10, 12, 14 or 15  */
+
+/* eight 8-bit registers */
+#define MK712_STATUS_LOW 0	/* READ */
+#define MK712_STATUS_HIGH 1	/* READ */
+#define MK712_X_LOW 2		/* READ */
+#define MK712_X_HIGH 3		/* READ */
+#define MK712_Y_LOW 4		/* READ */
+#define MK712_Y_HIGH 5		/* READ */
+#define MK712_CONTROL 6		/* R/W */
+#define MK712_RATE 7		/* R/W */
+
+/* status */
+#define	MK712_STATUS_TOUCH 0x10
+#define	MK712_CONVERSION_COMPLETE 0x80
+
+#define MK712_ENABLE_INT			0x01 /* enable interrupts */
+#define MK712_INT_ON_CONVERSION_COMPLETE	0x02 /* if bit 0 = 1 */
+#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_A	0x04 /* if bit 0 = 1 */
+#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_B	0x08 /* if bit 0 = 1 */
+#define MK712_ENABLE_PERIODIC_CONVERSIONS	0x10
+#define MK712_READ_ONE_POINT			0x20
+#define MK712_POWERDOWN_A			0x40
+#define MK712_POWERDOWN_B			0x80
+
+#define MK712_BUF_SIZE 256      /* a page */
+
+struct mk712_packet {
+        unsigned int header;
+        unsigned int x;
+        unsigned int y;
+        unsigned int reserved;
+};
+
+struct mk712_queue {
+	unsigned long head;
+	unsigned long tail;
+	wait_queue_head_t proc_list;
+	struct fasync_struct *fasync;
+	struct mk712_packet buf[256];
+};
+
+#ifdef MODULE
+static int io = 0;
+static int irq = 0;
+#endif
+static int mk712_io = MK712_DEFAULT_IO;
+static int mk712_irq = MK712_DEFAULT_IRQ;
+static int mk712_users = 0;
+static spinlock_t mk712_lock = SPIN_LOCK_UNLOCKED;
+static struct mk712_queue *queue; /* mouse data buffer */
+
+static struct mk712_packet get_from_queue(void)
+{
+	struct mk712_packet result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+	result = queue->buf[queue->tail];
+	queue->tail = (queue->tail + 1) & (MK712_BUF_SIZE-1);
+	spin_unlock_irqrestore(&mk712_lock, flags);
+	return result;
+}
+
+static inline int queue_empty(void)
+{
+	return queue->head == queue->tail;
+}
+
+static int mk712_fasync(int fd, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(fd, filp, on, &queue->fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static void mk712_output_packet(struct mk712_packet data)
+{
+        int head = queue->head;
+
+        queue->buf[head] = data;
+        head = (head + 1) & (MK712_BUF_SIZE-1);
+        if (head != queue->tail) {
+                queue->head = head;
+                kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+                wake_up_interruptible(&queue->proc_list);
+        }
+}
+
+static int points = 0;          /* number of stored points */
+static int output_point = 0;    /* did I output a point since last release? */
+
+static void mk712_output_point(int x, int y)
+{
+        struct mk712_packet t;
+
+        t.header = 0;
+        t.x = x;
+        t.y = y;
+        t.reserved = 0;
+
+        mk712_output_packet(t);
+        output_point = 1;
+}
+
+static void mk712_store_point(int x_new, int y_new)
+{
+        static int x[3], y[3];
+        int x_out, y_out;
+
+        x[points] = x_new;
+        y[points] = y_new;
+
+        if (points == 1 && abs(x[0] - x[1]) < 88 && abs(y[0] - y[1]) < 88)
+	{
+		x_out = (x[0] + x[1]) >> 1;
+                y_out = (y[0] + y[1]) >> 1;
+                mk712_output_point(x_out, y_out);
+        }
+
+        if (points == 2) {
+                if ((abs(x[1] - x[2]) < 88 && abs(y[1] - y[2]) < 88) &&
+                    (abs(x[0] - x[1]) < 88 && abs(y[0] - y[1]) < 88))
+                {
+                        x_out = (x[0] + x[1] + x[2]) / 3;
+                        y_out = (y[0] + y[1] + y[2]) / 3;
+                        mk712_output_point(x_out, y_out);
+                }
+                else if (abs(x[1] - x[2]) < 88 && abs(y[1] - y[2]) < 88)
+                {
+                        x_out = (x[1] + x[2]) >> 1;
+                        y_out = (y[1] + y[2]) >> 1;
+                        mk712_output_point(x_out, y_out);
+                }
+                else
+                {
+                        int x_avg, y_avg, d0, d1, d2;
+
+                        x_avg = (x[0] + x[1] + x[2]) / 3;
+                        y_avg = (y[0] + y[1] + y[2]) / 3;
+
+                        d0 = SQUARE(x[0] - x_avg) + SQUARE(y[0] - y_avg);
+                        d1 = SQUARE(x[1] - x_avg) + SQUARE(y[1] - y_avg);
+                        d2 = SQUARE(x[2] - x_avg) + SQUARE(y[2] - y_avg);
+
+                        if (d2 > d1 && d2 > d0)
+			{
+                                x_out = (x[0] + x[1]) >> 1;
+                                y_out = (y[0] + y[1]) >> 1;
+                        }
+                        if (d1 > d0 && d1 > d2)
+			{
+                                x_out = (x[0] + x[2]) >> 1;
+                                y_out = (y[0] + y[2]) >> 1;
+                        }
+                        else
+                        {
+                                x_out = (x[1] + x[2]) >> 1;
+                                y_out = (y[1] + y[2]) >> 1;
+                        }
+
+                        mk712_output_point(x_out, y_out);
+
+                        x[0] = x[1];
+                        x[1] = x[2];
+                        y[0] = y[1];
+                        y[1] = y[2];
+                }
+        }
+        else
+	{
+                points++;
+        }
+}
+
+static void mk712_release_event(void)
+{
+        struct mk712_packet t;
+
+        if (!output_point) {
+                points = 0;
+                return;
+        }
+        output_point = 0;
+
+        t.header = 1;
+        t.x = t.y = t.reserved = 0;
+
+        mk712_output_packet(t);
+        points = 0;
+}
+
+#define MK712_FILTER
+static void mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned short x;
+	unsigned short y;
+        unsigned char status;
+	unsigned long flags;
+#ifdef MK712_FILTER
+        static int drop_next = 1;
+#endif
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+        status = inb(mk712_io + MK712_STATUS_LOW);
+
+	if (!(status & MK712_CONVERSION_COMPLETE)) {
+#ifdef MK712_FILTER
+                drop_next = 1;
+#endif
+		return;
+	}
+	if (!(status & MK712_STATUS_TOUCH))	/* release event */
+	{
+#ifdef MK712_FILTER
+                drop_next = 1;
+#endif
+                mk712_release_event();
+
+                spin_unlock_irqrestore(&mk712_lock, flags);
+                wake_up_interruptible(&queue->proc_list);
+
+		return;
+	}
+
+        x = inw(mk712_io + MK712_X_LOW) & 0x0fff;
+        y = inw(mk712_io + MK712_Y_LOW) & 0x0fff;
+
+#ifdef MK712_FILTER
+        if (drop_next)
+        {
+                drop_next = 0;
+
+                spin_unlock_irqrestore(&mk712_lock, flags);
+                wake_up_interruptible(&queue->proc_list);
+
+                return;
+        }
+#endif
+
+        x = inw(mk712_io + MK712_X_LOW) & 0x0fff;
+	y = inw(mk712_io + MK712_Y_LOW) & 0x0fff;
+
+        mk712_store_point(x, y);
+
+        spin_unlock_irqrestore(&mk712_lock, flags);
+        wake_up_interruptible(&queue->proc_list);
+}
+
+static int mk712_open(struct inode *inode, struct file *file) 
+{
+	unsigned char control;
+	unsigned long flags;
+
+	control = 0;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+	if(!mk712_users++)
+	{
+		outb(0, mk712_io + MK712_CONTROL);
+
+		control |= (MK712_ENABLE_INT |
+	                    MK712_INT_ON_CONVERSION_COMPLETE |
+	                    MK712_INT_ON_CHANGE_IN_TOUCH_STATUS_B |
+	                    MK712_ENABLE_PERIODIC_CONVERSIONS |
+	                    MK712_POWERDOWN_A);
+		outb(control, mk712_io + MK712_CONTROL);
+
+	        outb(10, mk712_io + MK712_RATE); /* default count = 10 */
+
+		queue->head = queue->tail = 0;          /* Flush input queue */
+	}
+	spin_unlock_irqrestore(&mk712_lock, flags);
+	return 0;
+}
+
+static int mk712_close(struct inode * inode, struct file * file) {
+        /* power down controller */
+        unsigned long flags;
+        spin_lock_irqsave(&mk712_lock, flags);
+	if(--mk712_users==0)
+		outb(0, mk712_io + MK712_CONTROL);
+	spin_unlock_irqrestore(&mk712_lock, flags);
+	return 0;
+}
+
+static unsigned int mk712_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &queue->proc_list, wait);
+	if(!queue_empty())
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int mk712_ioctl(struct inode *inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	if (!inode)
+		BUG();
+	return -ENOTTY;
+}
+
+
+static ssize_t mk712_read(struct file *file, char *buffer,
+			  size_t count, loff_t *pos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t bytes_read = 0;
+	struct mk712_packet p;
+
+	/* wait for an event */
+	if (queue_empty()) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		add_wait_queue(&queue->proc_list, &wait);
+repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (queue_empty() && !signal_pending(current)) {
+			schedule();
+			goto repeat;
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&queue->proc_list, &wait);
+	}
+
+	while (bytes_read < count && !queue_empty()) {
+		p = get_from_queue();
+		if (copy_to_user (buffer+bytes_read, (void *) &p, sizeof(p)))
+		{
+			bytes_read = -EFAULT;
+			break;
+		}
+		bytes_read += sizeof(p);
+	}
+
+        if (bytes_read > 0)
+        {
+                file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+                return bytes_read;
+        }
+
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	return bytes_read;
+}
+
+static ssize_t mk712_write(struct file *file, const char *buffer, size_t count,
+			   loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+struct file_operations mk712_fops = {
+	owner: THIS_MODULE,
+	read: mk712_read,
+	write: mk712_write,
+	poll: mk712_poll,
+	ioctl: mk712_ioctl,
+	open: mk712_open,
+	release: mk712_close,
+	fasync: mk712_fasync,
+};
+
+static struct miscdevice mk712_touchscreen = {
+	MK712_MINOR, "mk712_touchscreen", &mk712_fops
+};
+
+int __init mk712_init(void)
+{
+#ifdef MODULE
+        if (io)
+                mk712_io = io;
+        if (irq)
+                mk712_irq = irq;
+#endif
+
+	if(request_region(mk712_io, 8, "mk712_touchscreen"))
+	{
+		printk("mk712: unable to get IO region\n");
+		return -ENODEV;
+	}
+
+	/* set up wait queue */
+	queue = (struct mk712_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	if(queue == NULL)
+	{
+		release_region(mk712_io, 8);
+		return -ENOMEM;
+	}
+	memset(queue, 0, sizeof(*queue));
+	queue->head = queue->tail = 0;
+	init_waitqueue_head(&queue->proc_list);
+
+        /* The MK712 is ISA and hard-coded to a particular IRQ, so the
+           driver should keep the IRQ as long as it is loaded. */
+	if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712_touchscreen",
+		       queue))
+	{
+		printk("mk712: unable to get IRQ\n");
+		release_region(mk712_io, 8);
+		kfree(queue);
+		return -EBUSY;
+	}
+
+        /* register misc device */
+	if(misc_register(&mk712_touchscreen)<0)
+	{
+		release_region(mk712_io, 8);
+		kfree(queue);
+		free_irq(mk712_irq, queue);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit mk712_exit(void)
+{
+	misc_deregister(&mk712_touchscreen);
+	release_region(mk712_io, 8);
+	free_irq(mk712_irq, queue);
+	kfree(queue);
+	printk(KERN_INFO "mk712 touchscreen uninstalled\n");
+}
+
+MODULE_AUTHOR("Daniel Quinlan");
+MODULE_DESCRIPTION("MK712 touch screen driver");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O base address of MK712 touch screen controller");
+MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(irq, "IRQ of MK712 touch screen controller");
+MODULE_LICENSE("GPL");
+
+module_init(mk712_init);
+module_exit(mk712_exit);
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -urN linux-2.4.19-pre4/drivers/char/rocket_int.h linux-2.4.19-pre5/drivers/char/rocket_int.h
--- linux-2.4.19-pre4/drivers/char/rocket_int.h	Mon Dec 11 12:51:57 2000
+++ linux-2.4.19-pre5/drivers/char/rocket_int.h	Fri Mar 29 14:49:29 2002
@@ -185,7 +185,7 @@
 
 /* Old clock prescale definition and baud rates associated with it */
 
-#define CLOCK_PRESC 0x19  */        /* mod 9 (divide by 10) prescale */
+#define CLOCK_PRESC 0x19          /* mod 9 (divide by 10) prescale */
 #define BRD50             4607
 #define BRD75             3071
 #define BRD110            2094
diff -urN linux-2.4.19-pre4/drivers/char/sc1200wdt.c linux-2.4.19-pre5/drivers/char/sc1200wdt.c
--- linux-2.4.19-pre4/drivers/char/sc1200wdt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/char/sc1200wdt.c	Fri Mar 29 14:49:29 2002
@@ -0,0 +1,432 @@
+/*
+ *	National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+ *	(c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>,
+ *			All Rights Reserved.
+ *	Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	The author(s) of this software shall not be held liable for damages
+ *	of any nature resulting due to the use of this software. This
+ *	software is provided AS-IS with no warranties.
+ *
+ *	Changelog:
+ *	20020220 Zwane Mwaikambo	Code based on datasheet, no hardware.
+ *	20020221 Zwane Mwaikambo	Cleanups as suggested by Jeff Garzik and Alan Cox.
+ *	20020222 Zwane Mwaikambo	Added probing.
+ *	20020225 Zwane Mwaikambo	Added ISAPNP support.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/isapnp.h>
+
+#define SC1200_MODULE_VER	"build 20020303"
+#define SC1200_MODULE_NAME	"sc1200wdt"
+#define PFX			SC1200_MODULE_NAME ": "
+
+#define	MAX_TIMEOUT	255	/* 255 minutes */
+#define PMIR		(io)	/* Power Management Index Register */
+#define PMDR		(io+1)	/* Power Management Data Register */
+
+/* Data Register indexes */
+#define FER1		0x00	/* Function enable register 1 */
+#define FER2		0x01	/* Function enable register 2 */
+#define PMC1		0x02	/* Power Management Ctrl 1 */
+#define PMC2		0x03	/* Power Management Ctrl 2 */
+#define PMC3		0x04	/* Power Management Ctrl 3 */
+#define WDTO		0x05	/* Watchdog timeout register */
+#define	WDCF		0x06	/* Watchdog config register */
+#define WDST		0x07	/* Watchdog status register */
+
+/* WDO Status */
+#define WDO_ENABLED	0x00	
+#define WDO_DISABLED	0x01	
+
+/* WDCF bitfields - which devices assert WDO */
+#define KBC_IRQ		0x01	/* Keyboard Controller */
+#define MSE_IRQ		0x02	/* Mouse */
+#define UART1_IRQ	0x03	/* Serial0 */
+#define UART2_IRQ	0x04	/* Serial1 */
+/* 5 -7 are reserved */
+
+static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER;
+static int timeout = 1;
+static int io = -1;
+static int io_len = 2;		/* for non plug and play */
+struct semaphore open_sem;
+static int expect_close = 0;
+spinlock_t sc1200wdt_lock;	/* io port access serialisation */
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static int isapnp = 1;
+static struct pci_dev *wdt_dev;
+#endif
+
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "io port");
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+MODULE_PARM(isapnp, "i");
+MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
+#endif
+
+
+/* Read from Data Register */
+static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data)
+{
+	spin_lock(&sc1200wdt_lock);
+	outb_p(index, PMIR);
+	*data = inb(PMDR);
+	spin_unlock(&sc1200wdt_lock);
+}
+
+
+/* Write to Data Register */
+static inline void sc1200wdt_write_data(unsigned char index, unsigned char data)
+{
+	spin_lock(&sc1200wdt_lock);
+	outb_p(index, PMIR);
+	outb(data, PMDR);
+	spin_unlock(&sc1200wdt_lock);
+}
+
+
+/* This returns the status of the WDO signal, inactive high.
+ * returns WDO_ENABLED or WDO_DISABLED
+ */
+static inline int sc1200wdt_status(void)
+{
+	unsigned char ret;
+
+	sc1200wdt_read_data(WDST, &ret);
+	return (ret & 0x01);		/* bits 1 - 7 are undefined */
+}
+
+
+static int sc1200wdt_open(struct inode *inode, struct file *file)
+{
+	unsigned char reg;
+
+	/* allow one at a time */
+	if (down_trylock(&open_sem))
+		return -EBUSY;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT	
+	MOD_INC_USE_COUNT;
+#endif
+
+	if (timeout > MAX_TIMEOUT)
+		timeout = MAX_TIMEOUT;
+
+	sc1200wdt_read_data(WDCF, &reg);
+	/* assert WDO when any of the following interrupts are triggered too */
+	reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
+	sc1200wdt_write_data(WDCF, reg);
+	/* set the timeout and get the ball rolling */
+	sc1200wdt_write_data(WDTO, timeout);
+	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
+	
+	return 0;
+}
+
+
+static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int new_timeout;
+	static struct watchdog_info ident = {
+		options:		WDIOF_SETTIMEOUT,
+		identity:		"PC87307/PC97307"
+	};
+
+	switch (cmd) {
+		default:
+			return -ENOTTY;	/* Keep Pavel Machek amused ;) */
+
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident))
+				return -EFAULT;
+			return 0;
+
+		case WDIOC_GETSTATUS:
+			return put_user(sc1200wdt_status(), (int *)arg);
+	
+		case WDIOC_KEEPALIVE:
+			sc1200wdt_write_data(WDTO, timeout);
+			return 0;
+
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_timeout, (int *)arg))
+				return -EFAULT;
+
+			/* the API states this is given in secs */
+			new_timeout /= 60;
+			if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
+				return -EINVAL;
+
+			timeout = new_timeout;
+			sc1200wdt_write_data(WDTO, timeout);
+			/* fall through and return the new timeout */
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout * 60, (int *)arg);
+	}
+}
+
+
+static int sc1200wdt_release(struct inode *inode, struct file *file)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if (expect_close) {
+		sc1200wdt_write_data(WDTO, 0);
+		printk(KERN_INFO PFX "Watchdog disabled\n");
+	} else {
+		sc1200wdt_write_data(WDTO, timeout);
+		printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout);
+	}	
+#endif
+	up(&open_sem);
+
+	return 0;
+}
+
+
+static ssize_t sc1200wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	
+	if (len) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		size_t i;
+
+		expect_close = 0;
+
+		for (i = 0; i != len; i++)
+		{
+			if (data[i] == 'V')
+				expect_close = 1;
+		}
+#endif
+		sc1200wdt_write_data(WDTO, timeout);
+		return len;
+	}
+
+	return 0;
+}
+
+
+static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		sc1200wdt_write_data(WDTO, 0);
+
+	return NOTIFY_DONE;
+}
+
+
+static struct notifier_block sc1200wdt_notifier =
+{
+	notifier_call:	sc1200wdt_notify_sys
+};
+
+static struct file_operations sc1200wdt_fops =
+{
+	owner:		THIS_MODULE,
+	write:		sc1200wdt_write,
+	ioctl:		sc1200wdt_ioctl,
+	open:		sc1200wdt_open,
+	release:	sc1200wdt_release
+};
+
+static struct miscdevice sc1200wdt_miscdev =
+{
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&sc1200wdt_fops
+};
+
+
+static int __init sc1200wdt_probe(void)
+{
+	/* The probe works by reading the PMC3 register's default value of 0x0e
+	 * there is one caveat, if the device disables the parallel port or any
+	 * of the UARTs we won't be able to detect it.
+	 * Nb. This could be done with accuracy by reading the SID registers, but
+	 * we don't have access to those io regions.
+	 */
+	
+	unsigned char reg;
+
+	sc1200wdt_read_data(PMC3, &reg);
+	reg &= 0x0f;				/* we don't want the UART busy bits */
+	return (reg == 0x0e) ? 0 : -ENODEV;
+}
+
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+
+static int __init sc1200wdt_isapnp_probe(void)
+{
+	int ret;
+
+	/* The WDT is logical device 8 on the main device */
+	wdt_dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('N','S','C'), ISAPNP_FUNCTION(0x08), NULL);
+	if (!wdt_dev)
+		return -ENODEV;
+	
+	if (wdt_dev->prepare(wdt_dev) < 0) {
+		printk(KERN_ERR PFX "ISA PnP found device that could not be autoconfigured\n");
+		return -EAGAIN;
+	}
+
+	if (!(pci_resource_flags(wdt_dev, 0) & IORESOURCE_IO)) {
+		printk(KERN_ERR PFX "ISA PnP could not find io ports\n");
+		return -ENODEV;
+	}
+
+	ret = wdt_dev->activate(wdt_dev);
+	if (ret && (ret != -EBUSY))
+		return -ENOMEM;
+
+	/* io port resource overriding support? */
+	io = pci_resource_start(wdt_dev, 0);
+	io_len = pci_resource_len(wdt_dev, 0);
+
+	printk(KERN_DEBUG PFX "ISA PnP found device at io port %#x/%d\n", io, io_len);
+	return 0;
+}
+
+#endif /* CONFIG_ISAPNP */
+
+
+static int __init sc1200wdt_init(void)
+{
+	int ret;
+
+	printk(banner);
+
+	spin_lock_init(&sc1200wdt_lock);
+	sema_init(&open_sem, 1);
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+	if (isapnp) {
+		ret = sc1200wdt_isapnp_probe();
+		if (ret)
+			goto out_clean;
+	}
+#endif
+
+	if (io == -1) {
+		printk(KERN_ERR PFX "io parameter must be specified\n");
+		ret = -EINVAL;
+		goto out_clean;
+	}
+
+	if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
+		printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+		ret = -EBUSY;
+		goto out_pnp;
+	}
+
+	ret = sc1200wdt_probe();
+	if (ret)
+		goto out_io;
+
+	ret = register_reboot_notifier(&sc1200wdt_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
+		goto out_io;
+	}
+
+	ret = misc_register(&sc1200wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
+		goto out_rbt;
+	}
+
+	/* ret = 0 */
+
+out_clean:
+	return ret;
+
+out_rbt:
+	unregister_reboot_notifier(&sc1200wdt_notifier);
+
+out_io:
+	release_region(io, io_len);
+
+out_pnp:
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+	if (isapnp && wdt_dev)
+		wdt_dev->deactivate(wdt_dev);
+#endif
+	goto out_clean;
+}	
+
+
+static void __exit sc1200wdt_exit(void)
+{
+	misc_deregister(&sc1200wdt_miscdev);
+	unregister_reboot_notifier(&sc1200wdt_notifier);
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+	if(isapnp && wdt_dev)
+		wdt_dev->deactivate(wdt_dev);
+#endif
+
+	release_region(io, io_len);
+}
+
+
+#ifndef MODULE
+static int __init sc1200wdt_setup(char *str)
+{
+	int ints[4];
+
+	str = get_options (str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		io = ints[1];
+		if (ints[0] > 1)
+			timeout = ints[2];
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+		if (ints[0] > 2)
+			isapnp = ints[3];
+#endif
+	}
+
+	return 1;
+}
+
+__setup("sc1200wdt=", sc1200wdt_setup);
+#endif /* MODULE */
+
+
+module_init(sc1200wdt_init);
+module_exit(sc1200wdt_exit);
+
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
diff -urN linux-2.4.19-pre4/drivers/char/sc520_wdt.c linux-2.4.19-pre5/drivers/char/sc520_wdt.c
--- linux-2.4.19-pre4/drivers/char/sc520_wdt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/char/sc520_wdt.c	Fri Mar 29 14:49:29 2002
@@ -0,0 +1,381 @@
+/*
+ *	AMD Elan SC520 processor Watchdog Timer driver for Linux 2.4.x
+ *
+ *      Based on acquirewdt.c by Alan Cox,
+ *           and sbc60xxwdt.c by Jakob Oestergaard <jakob@ostenfeld.dk>
+ *     
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *	
+ *	The authors do NOT admit liability nor provide warranty for 
+ *	any of this software. This material is provided "AS-IS" in 
+ *      the hope that it may be useful for others.
+ *
+ *	(c) Copyright 2001    Scott Jennings <linuxdrivers@oro.net>
+ *           9/27 - 2001      [Initial release]
+ *	
+ *	Additional fixes Alan Cox
+ *	-	Fixed formatting
+ *	-	Removed debug printks
+ *	-	Fixed SMP built kernel deadlock
+ *	-	Switched to private locks not lock_kernel
+ *	-	Used ioremap/writew/readw
+ *	-	Added NOWAYOUT support
+ *
+ *  Theory of operation:
+ *  A Watchdog Timer (WDT) is a hardware circuit that can 
+ *  reset the computer system in case of a software fault.
+ *  You probably knew that already.
+ *
+ *  Usually a userspace daemon will notify the kernel WDT driver
+ *  via the /proc/watchdog special device file that userspace is
+ *  still alive, at regular intervals.  When such a notification
+ *  occurs, the driver will usually tell the hardware watchdog
+ *  that everything is in order, and that the watchdog should wait
+ *  for yet another little while to reset the system.
+ *  If userspace fails (RAM error, kernel bug, whatever), the
+ *  notifications cease to occur, and the hardware watchdog will
+ *  reset the system (causing a reboot) after the timeout occurs.
+ *
+ *  This WDT driver is different from most other Linux WDT
+ *  drivers in that the driver will ping the watchdog by itself,
+ *  because this particular WDT has a very short timeout (1.6
+ *  seconds) and it would be insane to count on any userspace
+ *  daemon always getting scheduled within that time frame.
+ *
+ *  This driver uses memory mapped IO, and spinlock.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+/*
+ * The SC520 can timeout anywhere from 492us to 32.21s.
+ * If we reset the watchdog every ~250ms we should be safe.
+ */
+
+#define WDT_INTERVAL (HZ/4+1)
+
+/*
+ * We must not require too good response from the userspace daemon.
+ * Here we require the userspace daemon to send us a heartbeat
+ * char to /dev/watchdog every 30 seconds.
+ */
+
+#define WDT_HEARTBEAT (HZ * 30)
+
+/*
+ * AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
+ *
+ *   0: 492us    2: 1.01s    4: 4.03s   6: 16.22s
+ *   1: 503ms    3: 2.01s    5: 8.05s   7: 32.21s
+ */
+
+#define TIMEOUT_EXPONENT ( 1 << 3 )  /* 0x08 = 2.01s */
+
+/* #define MMCR_BASE_DEFAULT 0xfffef000 */
+#define MMCR_BASE_DEFAULT ((__u16 *)0xffffe)
+#define OFFS_WDTMRCTL ((unsigned int)0xcb0)
+#define WDT_ENB 0x8000		/* [15] Watchdog Timer Enable */
+#define WDT_WRST_ENB 0x4000	/* [14] Watchdog Timer Reset Enable */
+
+#define OUR_NAME "sc520_wdt"
+
+#define WRT_DOG(data) *wdtmrctl=data
+
+static __u16 *wdtmrctl;
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_is_open;
+static int wdt_expect_close;
+
+static spinlock_t wdt_spinlock;
+/*
+ *	Whack the dog
+ */
+
+static void wdt_timer_ping(unsigned long data)
+{
+	/* If we got a heartbeat pulse within the WDT_US_INTERVAL
+	 * we agree to ping the WDT 
+	 */
+	if(time_before(jiffies, next_heartbeat)) 
+	{
+		/* Ping the WDT */
+		spin_lock(&wdt_spinlock);
+		writew(0xAAAA, wdtmrctl);
+		writew(0x5555, wdtmrctl);
+		spin_unlock(&wdt_spinlock);
+
+		/* Re-set the timer interval */
+		timer.expires = jiffies + WDT_INTERVAL;
+		add_timer(&timer);
+	} else {
+		printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+/* 
+ * Utility routines
+ */
+
+static void wdt_config(int writeval)
+{
+	__u16 dummy;
+	unsigned long flags;
+
+	/* buy some time (ping) */
+	spin_lock_irqsave(&wdt_spinlock, flags);
+	dummy=readw(wdtmrctl);  /* ensure write synchronization */
+	writew(0xAAAA, wdtmrctl);
+	writew(0x5555, wdtmrctl);
+	/* make WDT configuration register writable one time */
+	writew(0x3333, wdtmrctl);
+	writew(0xCCCC, wdtmrctl);
+	/* write WDT configuration register */
+	writew(writeval, wdtmrctl);
+	spin_unlock_irqrestore(&wdt_spinlock, flags);
+}
+
+static void wdt_startup(void)
+{
+	next_heartbeat = jiffies + WDT_HEARTBEAT;
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;	
+	add_timer(&timer);
+
+	wdt_config(WDT_ENB | WDT_WRST_ENB | TIMEOUT_EXPONENT);
+	printk(OUR_NAME ": Watchdog timer is now enabled.\n");  
+}
+
+static void wdt_turnoff(void)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	/* Stop the timer */
+	del_timer(&timer);
+	wdt_config(0);
+	printk(OUR_NAME ": Watchdog timer is now disabled...\n");
+#endif
+}
+
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos)
+{
+	/* We can't seek */
+	if(ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* See if we got the magic character */
+	if(count) 
+	{
+		size_t ofs;
+
+		/* note: just in case someone wrote the magic character
+		 * five months ago... */
+		wdt_expect_close = 0;
+
+		/* now scan */
+		for(ofs = 0; ofs != count; ofs++) 
+			if(buf[ofs] == 'V')
+				wdt_expect_close = 1;
+
+		/* Well, anyhow someone wrote to us, we should return that favour */
+		next_heartbeat = jiffies + WDT_HEARTBEAT;
+		return 1;
+	}
+	return 0;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	switch(MINOR(inode->i_rdev)) 
+	{
+		case WATCHDOG_MINOR:
+			/* Just in case we're already talking to someone... */
+			if(test_and_set_bit(0, &wdt_is_open))
+				return -EBUSY;
+			/* Good, fire up the show */
+			wdt_startup();
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+			MOD_INC_USE_COUNT;
+#endif	
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+	if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) 
+	{
+		if(wdt_expect_close)
+			wdt_turnoff();
+		else {
+			del_timer(&timer);
+			printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
+		}
+	}
+	clear_bit(0, &wdt_is_open);
+	return 0;
+}
+
+static long long fop_llseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	static struct watchdog_info ident=
+	{
+		0,
+		1,
+		"SC520"
+	};
+	
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_KEEPALIVE:
+			next_heartbeat = jiffies + WDT_HEARTBEAT;
+			return 0;
+	}
+}
+
+static struct file_operations wdt_fops = {
+	owner:		THIS_MODULE,
+	llseek:		fop_llseek,
+	write:		fop_write,
+	open:		fop_open,
+	release:	fop_close,
+	ioctl:		fop_ioctl
+};
+
+static struct miscdevice wdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&wdt_fops
+};
+
+/*
+ *	Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) 
+		wdt_turnoff();
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block wdt_notifier=
+{
+	wdt_notify_sys,
+	0,
+	0
+};
+
+static void __exit sc520_wdt_unload(void)
+{
+	wdt_turnoff();
+
+	/* Deregister */
+	misc_deregister(&wdt_miscdev);
+	iounmap(wdtmrctl);
+	unregister_reboot_notifier(&wdt_notifier);
+}
+
+static int __init sc520_wdt_init(void)
+{
+	int rc = -EBUSY;
+	unsigned long cbar;
+
+	spin_lock_init(&wdt_spinlock);
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 0;
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc)
+		goto err_out_region2;
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc)
+		goto err_out_miscdev;
+
+	/* get the Base Address Register */
+	cbar = inl_p(0xfffc);
+	printk(OUR_NAME ": CBAR: 0x%08lx\n", cbar);
+	/* check if MMCR aliasing bit is set */
+	if (cbar & 0x80000000) {
+		printk(OUR_NAME ": MMCR Aliasing enabled.\n");
+		wdtmrctl = (__u16 *)(cbar & 0x3fffffff);
+	} else {
+		printk(OUR_NAME "!!! WARNING !!!\n"
+		  "\t MMCR Aliasing found NOT enabled!\n"
+		  "\t Using default value of: %p\n"
+		  "\t This has not been tested!\n"
+		  "\t Please email Scott Jennings <smj@oro.net>\n"
+		  "\t  and Bill Jennings <bj@oro.net> if it works!\n"
+		  , MMCR_BASE_DEFAULT
+		  );
+	  wdtmrctl = MMCR_BASE_DEFAULT;
+	}
+
+	wdtmrctl = (__u16 *)((char *)wdtmrctl + OFFS_WDTMRCTL);
+	wdtmrctl = ioremap((unsigned long)wdtmrctl, 2);
+	printk(KERN_INFO OUR_NAME ": WDT driver for SC520 initialised.\n");
+
+	return 0;
+
+err_out_miscdev:
+	misc_deregister(&wdt_miscdev);
+err_out_region2:
+	return rc;
+}
+
+module_init(sc520_wdt_init);
+module_exit(sc520_wdt_unload);
+
+MODULE_AUTHOR("Scott and Bill Jennings");
+MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.19-pre4/drivers/char/serial_txx927.c linux-2.4.19-pre5/drivers/char/serial_txx927.c
--- linux-2.4.19-pre4/drivers/char/serial_txx927.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/char/serial_txx927.c	Fri Mar 29 14:49:29 2002
@@ -55,9 +55,6 @@
  * End of serial driver configuration section.
  */
 
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>    
 
 #include <linux/config.h>
diff -urN linux-2.4.19-pre4/drivers/char/tty_io.c linux-2.4.19-pre5/drivers/char/tty_io.c
--- linux-2.4.19-pre4/drivers/char/tty_io.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/char/tty_io.c	Fri Mar 29 14:49:30 2002
@@ -1849,6 +1849,9 @@
 	for_each_task(p) {
 		if ((p->tty == tty) ||
 		    ((session > 0) && (p->session == session))) {
+			printk(KERN_NOTICE "SAK: killed process %d"
+			    " (%s): p->session==tty->session\n",
+			    p->pid, p->comm);
 			send_sig(SIGKILL, p, 1);
 			continue;
 		}
@@ -1859,6 +1862,9 @@
 				filp = fcheck_files(p->files, i);
 				if (filp && (filp->f_op == &tty_fops) &&
 				    (filp->private_data == tty)) {
+					printk(KERN_NOTICE "SAK: killed process %d"
+					    " (%s): fd#%d opened to the tty\n",
+					    p->pid, p->comm, i);
 					send_sig(SIGKILL, p, 1);
 					break;
 				}
diff -urN linux-2.4.19-pre4/drivers/char/w83877f_wdt.c linux-2.4.19-pre5/drivers/char/w83877f_wdt.c
--- linux-2.4.19-pre4/drivers/char/w83877f_wdt.c	Thu Sep 13 15:21:32 2001
+++ linux-2.4.19-pre5/drivers/char/w83877f_wdt.c	Fri Mar 29 14:49:30 2002
@@ -13,9 +13,10 @@
  *	any of this software. This material is provided "AS-IS" in 
  *      the hope that it may be useful for others.
  *
- *	(c) Copyright 2001    Scott Jennings <management@oro.net>
+ *	(c) Copyright 2001    Scott Jennings <linuxdrivers@oro.net>
  *
  *           4/19 - 2001      [Initial revision]
+ *           9/27 - 2001      Added spinlocking
  *
  *
  *  Theory of operation:
@@ -88,8 +89,9 @@
 static void wdt_timer_ping(unsigned long);
 static struct timer_list timer;
 static unsigned long next_heartbeat;
-static int wdt_is_open;
+static unsigned long wdt_is_open;
 static int wdt_expect_close;
+static spinlock_t wdt_spinlock;
 
 /*
  *	Whack the dog
@@ -102,11 +104,18 @@
 	 */
 	if(time_before(jiffies, next_heartbeat)) 
 	{
+		/* Ping the WDT */
+		spin_lock(&wdt_spinlock);
+
 		/* Ping the WDT by reading from WDT_PING */
 		inb_p(WDT_PING);
+
 		/* Re-set the timer interval */
 		timer.expires = jiffies + WDT_INTERVAL;
 		add_timer(&timer);
+
+		spin_unlock(&wdt_spinlock);
+
 	} else {
 		printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n");
 	}
@@ -118,19 +127,24 @@
 
 static void wdt_change(int writeval)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_spinlock, flags);
+
 	/* buy some time */
 	inb_p(WDT_PING);
 
 	/* make W83877F available */
-	outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT);
-	outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT);
+	outb_p(ENABLE_W83877F,  ENABLE_W83877F_PORT);
+	outb_p(ENABLE_W83877F,  ENABLE_W83877F_PORT);
 
 	/* enable watchdog */
-	outb_p(WDT_REGISTER,ENABLE_W83877F_PORT);
-	outb_p(writeval,ENABLE_W83877F_PORT+1);
+	outb_p(WDT_REGISTER,    ENABLE_W83877F_PORT);
+	outb_p(writeval,        ENABLE_W83877F_PORT+1);
 
 	/* lock the W8387FF away */
-	outb_p(DISABLE_W83877F,ENABLE_W83877F_PORT);
+	outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT);
+
+	spin_unlock_irqrestore(&wdt_spinlock, flags);
 }
 
 static void wdt_startup(void)
@@ -178,7 +192,7 @@
 
 		/* now scan */
 		for(ofs = 0; ofs != count; ofs++)
-		  if(buf[ofs] == 'V')
+			if(buf[ofs] == 'V')
 				wdt_expect_close = 1;
 
 		/* someone wrote to us, we should restart timer */
@@ -200,10 +214,11 @@
 	{
 		case WATCHDOG_MINOR:
 			/* Just in case we're already talking to someone... */
-			if(wdt_is_open)
+			if(test_and_set_bit(0, &wdt_is_open)) {
+				spin_unlock(&fop_spinlock);
 				return -EBUSY;
+			}
 			/* Good, fire up the show */
-			wdt_is_open = 1;
 			wdt_startup();
 			return 0;
 
@@ -214,7 +229,6 @@
 
 static int fop_close(struct inode * inode, struct file * file)
 {
-	lock_kernel();
 	if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) 
 	{
 		if(wdt_expect_close)
@@ -224,13 +238,11 @@
 			printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
 		}
 	}
-	wdt_is_open = 0;
-	unlock_kernel();
+	clear_bit(0, &wdt_is_open);
 	return 0;
 }
 
-static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	unsigned long arg)
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	static struct watchdog_info ident=
 	{
@@ -307,6 +319,9 @@
 {
 	int rc = -EBUSY;
 
+	spin_lock_init(&wdt_spinlock);
+	spin_lock_init(&fop_spinlock);
+
 	if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT"))
 		goto err_out;
 	if (!request_region(WDT_PING, 1, "W8387FF WDT"))
@@ -341,4 +356,7 @@
 module_init(w83877f_wdt_init);
 module_exit(w83877f_wdt_unload);
 
+MODULE_AUTHOR("Scott and Bill Jennings");
+MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip");
 MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.19-pre4/drivers/char/wafer5823wdt.c linux-2.4.19-pre5/drivers/char/wafer5823wdt.c
--- linux-2.4.19-pre4/drivers/char/wafer5823wdt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/char/wafer5823wdt.c	Fri Mar 29 14:49:30 2002
@@ -0,0 +1,220 @@
+/*
+ *	ICP Wafer 5823 Single Board Computer WDT driver for Linux 2.4.x
+ *      http://www.icpamerica.com/wafer_5823.php
+ *      May also work on other similar models
+ *
+ *	(c) Copyright 2002 Justin Cormack <justin@street-vision.com>
+ *
+ *      Release 0.02
+ *
+ *	Based on advantechwdt.c which is based on wdt.c.
+ *	Original copyright messages:
+ *
+ *	(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.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.
+ *	
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+static unsigned long wafwdt_is_open;
+static spinlock_t wafwdt_lock;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ *
+ *      To enable, write the timeout value in seconds (1 to 255) to I/O
+ *      port WDT_START, then read the port to start the watchdog. To pat
+ *      the dog, read port WDT_STOP to stop the timer, then read WDT_START
+ *      to restart it again.
+ */
+
+#define WDT_START 0x443
+#define WDT_STOP 0x843
+
+#define WD_TIMO 60		/* 1 minute */
+
+static void wafwdt_ping(void)
+{
+	/* pat watchdog */
+        spin_lock(&wafwdt_lock);
+	inb_p(WDT_STOP);
+	inb_p(WDT_START);
+        spin_unlock(&wafwdt_lock);
+}
+
+static void wafwdt_start(void)
+{
+	/* start up watchdog */
+	outb_p(WD_TIMO, WDT_START);
+	inb_p(WDT_START);
+}
+
+static void
+wafwdt_stop(void)
+{
+	/* stop watchdog */
+	inb_p(WDT_STOP);
+}
+
+static ssize_t wafwdt_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count) {
+		wafwdt_ping();
+		return 1;
+	}
+	return 0;
+}
+
+static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	     unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		WDIOF_KEEPALIVEPING, 1, "Wafer 5823 WDT"
+	};
+	int one=1;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user
+		    ((struct watchdog_info *) arg, &ident, sizeof (ident)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+		if (copy_to_user((int *) arg, &one, sizeof (int)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wafwdt_ping();
+		break;
+
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static int wafwdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &wafwdt_is_open))
+		return -EBUSY;
+	wafwdt_start();
+	return 0;
+}
+
+static int
+wafwdt_close(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &wafwdt_is_open);
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+        wafwdt_stop();
+#endif
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the WDT off */
+		wafwdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations wafwdt_fops = {
+	owner:THIS_MODULE,
+	write:wafwdt_write,
+	ioctl:wafwdt_ioctl,
+	open:wafwdt_open,
+	release:wafwdt_close,
+};
+
+static struct miscdevice wafwdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&wafwdt_fops
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+
+static struct notifier_block wafwdt_notifier = {
+	wafwdt_notify_sys,
+	NULL,
+	0
+};
+
+static int __init wafwdt_init(void)
+{
+	printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n");
+
+	spin_lock_init(&wafwdt_lock);
+	if(!request_region(WDT_STOP, 1, "Wafer 5823 WDT"))
+		goto error;
+	if(!request_region(WDT_START, 1, "Wafer 5823 WDT"))
+		goto error2;
+	if(misc_register(&wafwdt_miscdev)<0)
+		goto error3;
+	register_reboot_notifier(&wafwdt_notifier);
+	return 0;
+error3:
+	release_region(WDT_START, 1);
+error2:
+	release_region(WDT_STOP, 1);
+error:
+	return -ENODEV;
+}
+
+static void __exit wafwdt_exit(void)
+{
+	misc_deregister(&wafwdt_miscdev);
+	unregister_reboot_notifier(&wafwdt_notifier);
+	release_region(WDT_STOP, 1);
+	release_region(WDT_START, 1);
+}
+
+module_init(wafwdt_init);
+module_exit(wafwdt_exit);
+
+MODULE_AUTHOR("Justin Cormack");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
+/* end of wafer5823wdt.c */
diff -urN linux-2.4.19-pre4/drivers/char/wdt.c linux-2.4.19-pre5/drivers/char/wdt.c
--- linux-2.4.19-pre4/drivers/char/wdt.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19-pre5/drivers/char/wdt.c	Fri Mar 29 14:49:30 2002
@@ -51,7 +51,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 
-static int wdt_is_open;
+static unsigned long wdt_is_open;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -355,7 +355,7 @@
 	switch(MINOR(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
-			if(wdt_is_open)
+			if(test_and_set_bit(0, &wdt_is_open))
 				return -EBUSY;
 			/*
 			 *	Activate 
@@ -392,16 +392,14 @@
  
 static int wdt_release(struct inode *inode, struct file *file)
 {
-	lock_kernel();
 	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 #ifndef CONFIG_WATCHDOG_NOWAYOUT	
 		inb_p(WDT_DC);		/* Disable counters */
 		wdt_ctr_load(2,0);	/* 0 length reset pulses now */
 #endif		
-		wdt_is_open=0;
+		clear_bit(0, &wdt_is_open);
 	}
-	unlock_kernel();
 	return 0;
 }
 
diff -urN linux-2.4.19-pre4/drivers/char/wdt_pci.c linux-2.4.19-pre5/drivers/char/wdt_pci.c
--- linux-2.4.19-pre4/drivers/char/wdt_pci.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19-pre5/drivers/char/wdt_pci.c	Fri Mar 29 14:49:30 2002
@@ -31,6 +31,7 @@
  *		Jeff Garzik	:	PCI cleanups
  *		Tigran Aivazian	:	Restructured wdtpci_init_one() to handle failures
  *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
+ *		Zwane Mwaikambo :	Magic char closing, locking changes, cleanups
  */
 
 #include <linux/config.h>
@@ -53,7 +54,8 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
 
 #include <linux/pci.h>
 
@@ -72,52 +74,19 @@
 #define PCI_DEVICE_ID_WDG_CSM 0x22c0
 #endif
 
-static int wdt_is_open;
+static struct semaphore open_sem;
+static spinlock_t wdtpci_lock;
+static int expect_close = 0;
 
-/*
- *	You must set these - there is no sane way to probe for this board.
- *	You can use wdt=x,y to set these now.
- */
- 
-static int io=0x240;
-static int irq=11;
+static int io;
+static int irq;
 
 /* Default timeout */
 #define WD_TIMO (100*60)		/* 1 minute */
+#define WD_TIMO_MAX (WD_TIMO*60)	/* 1 hour(?) */
 
 static int wd_margin = WD_TIMO;
 
-#ifndef MODULE
-
-/**
- *	wdtpci_setup:
- *	@str: command line string
- *
- *	Setup options. The board isn't really probe-able so we have to
- *	get the user to tell us the configuration. Sane people build it 
- *	modular but the others come here.
- */
- 
-static int __init wdtpci_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options (str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] > 0)
-	{
-		io = ints[1];
-		if(ints[0] > 1)
-			irq = ints[2];
-	}
-
-	return 1;
-}
-
-__setup("wdt=", wdtpci_setup);
-
-#endif /* !MODULE */
- 
 /*
  *	Programming support
  */
@@ -233,11 +202,15 @@
  
 static void wdtpci_ping(void)
 {
+	unsigned long flags;
+
 	/* Write a watchdog value */
+	spin_lock_irqsave(&wdtpci_lock, flags);
 	inb_p(WDT_DC);
 	wdtpci_ctr_mode(1,2);
 	wdtpci_ctr_load(1,wd_margin);		/* Timeout */
 	outb_p(0, WDT_DC);
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
 }
 
 /**
@@ -257,12 +230,21 @@
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
 
-	if(count)
-	{
+	if (count) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		size_t i;
+
+		expect_close = 0;
+
+		for (i = 0; i != count; i++) {
+			if (buf[i] == 'V')
+				expect_close = 1;
+		}
+#endif
 		wdtpci_ping();
-		return 1;
 	}
-	return 0;
+
+	return count;
 }
 
 /**
@@ -343,13 +325,14 @@
 			if (get_user(new_margin, (int *)arg))
 				return -EFAULT;
 			/* Arbitrary, can't find the card's limits */
-			if ((new_margin < 0) || (new_margin > 60))
+			new_margin *= 100;
+			if ((new_margin < 0) || (new_margin > WD_TIMO_MAX))
 				return -EINVAL;
-			wd_margin = new_margin * 100;
+			wd_margin = new_margin;
 			wdtpci_ping();
 			/* Fall */
 		case WDIOC_GETTIMEOUT:
-			return put_user(wd_margin, (int *)arg);
+			return put_user(wd_margin / 100, (int *)arg);
 	}
 }
 
@@ -367,20 +350,22 @@
  
 static int wdtpci_open(struct inode *inode, struct file *file)
 {
+	unsigned long flags;
+
 	switch(MINOR(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
-			if(wdt_is_open)
-				return -EBUSY;
+			 if (down_trylock(&open_sem))
+                        	return -EBUSY;
+
 #ifdef CONFIG_WATCHDOG_NOWAYOUT	
 			MOD_INC_USE_COUNT;
 #endif
 			/*
 			 *	Activate 
 			 */
-	 
-			wdt_is_open=1;
-
+			spin_lock_irqsave(&wdtpci_lock, flags);
+			
 			inb_p(WDT_DC);		/* Disable */
 
 			/*
@@ -405,6 +390,7 @@
 			wdtpci_ctr_load(1,wd_margin);/* Timeout 60 seconds */
 			/* DO NOT LOAD CTR2 on PCI card! -- JPN */
 			outb_p(0, WDT_DC);	/* Enable */
+			spin_unlock_irqrestore(&wdtpci_lock, flags);
 			return 0;
 		case TEMP_MINOR:
 			return 0;
@@ -427,15 +413,21 @@
  
 static int wdtpci_release(struct inode *inode, struct file *file)
 {
-	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
-	{
-		lock_kernel();
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_DC);		/* Disable counters */
-		wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
+
+	if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		unsigned long flags;
+		if (expect_close) {
+			spin_lock_irqsave(&wdtpci_lock, flags);
+			inb_p(WDT_DC);		/* Disable counters */
+			wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
+			spin_unlock_irqrestore(&wdtpci_lock, flags);
+		} else {
+			printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
+			wdtpci_ping();
+		}
 #endif		
-		wdt_is_open=0;
-		unlock_kernel();
+		up(&open_sem);
 	}
 	return 0;
 }
@@ -455,11 +447,14 @@
 static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
 	void *unused)
 {
-	if(code==SYS_DOWN || code==SYS_HALT)
-	{
+	unsigned long flags;
+
+	if (code==SYS_DOWN || code==SYS_HALT) {
 		/* Turn the card off */
+		spin_lock_irqsave(&wdtpci_lock, flags);
 		inb_p(WDT_DC);
 		wdtpci_ctr_load(2,0);
+		spin_unlock_irqrestore(&wdtpci_lock, flags);
 	}
 	return NOTIFY_DONE;
 }
@@ -520,6 +515,9 @@
 			"this driver only supports 1 device\n");
 		return -ENODEV;
 	}
+	
+	sema_init(&open_sem, 1);
+	spin_lock_init(&wdtpci_lock);
 
 	irq = dev->irq;
 	io = pci_resource_start (dev, 2);
@@ -577,7 +575,7 @@
 }
 
 
-static void __exit wdtpci_remove_one (struct pci_dev *pdev)
+static void __devexit wdtpci_remove_one (struct pci_dev *pdev)
 {
 	/* here we assume only one device will ever have
 	 * been picked up and registered by probe function */
@@ -602,7 +600,7 @@
 	name:		"wdt-pci",
 	id_table:	wdtpci_pci_tbl,
 	probe:		wdtpci_init_one,
-	remove:		wdtpci_remove_one,
+	remove:		__devexit_p(wdtpci_remove_one),
 };
 
 
diff -urN linux-2.4.19-pre4/drivers/fc4/soc.c linux-2.4.19-pre5/drivers/fc4/soc.c
--- linux-2.4.19-pre4/drivers/fc4/soc.c	Thu Oct 11 09:14:32 2001
+++ linux-2.4.19-pre5/drivers/fc4/soc.c	Fri Mar 29 14:49:30 2002
@@ -741,7 +741,6 @@
 	
 	for_each_soc(s) {
 		irq = s->port[0].fc.irq;
-		disable_irq (irq);
 		free_irq (irq, s);
 
 		fcp_release(&(s->port[0].fc), 2);
diff -urN linux-2.4.19-pre4/drivers/fc4/socal.c linux-2.4.19-pre5/drivers/fc4/socal.c
--- linux-2.4.19-pre4/drivers/fc4/socal.c	Thu Oct 11 09:14:32 2001
+++ linux-2.4.19-pre5/drivers/fc4/socal.c	Fri Mar 29 14:49:30 2002
@@ -880,7 +880,6 @@
 	
 	for_each_socal(s) {
 		irq = s->port[0].fc.irq;
-		disable_irq (irq);
 		free_irq (irq, s);
 
 		fcp_release(&(s->port[0].fc), 2);
diff -urN linux-2.4.19-pre4/drivers/ide/Config.in linux-2.4.19-pre5/drivers/ide/Config.in
--- linux-2.4.19-pre4/drivers/ide/Config.in	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/ide/Config.in	Fri Mar 29 14:49:30 2002
@@ -82,7 +82,7 @@
 	    fi
 	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
 	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
+#	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
 	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
@@ -159,8 +159,6 @@
 	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
       fi
    fi
-
-   bool '  Use the NOOP Elevator (WARNING)' CONFIG_BLK_DEV_ELEVATOR_NOOP
 else
    bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
    define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_ONLY
diff -urN linux-2.4.19-pre4/drivers/ide/ide-pci.c linux-2.4.19-pre5/drivers/ide/ide-pci.c
--- linux-2.4.19-pre4/drivers/ide/ide-pci.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/ide/ide-pci.c	Fri Mar 29 14:49:30 2002
@@ -56,6 +56,7 @@
 #define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
 #define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
 #define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
+#define DEVID_PDC20276	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
 #define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
 #define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
@@ -420,6 +421,7 @@
 	{DEVID_PDC20268R,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20276,"PDC20276",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -481,6 +483,7 @@
 		case PCI_DEVICE_ID_PROMISE_20268R:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
 		case PCI_DEVICE_ID_ARTOP_ATP860:
 		case PCI_DEVICE_ID_ARTOP_ATP860R:
@@ -810,6 +813,7 @@
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
diff -urN linux-2.4.19-pre4/drivers/ide/ide-tape.c linux-2.4.19-pre5/drivers/ide/ide-tape.c
--- linux-2.4.19-pre4/drivers/ide/ide-tape.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/ide/ide-tape.c	Fri Mar 29 14:49:30 2002
@@ -3096,10 +3096,10 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
 	
-//#if IDETAPE_DEBUG_LOG
-//	if (tape->debug_level >= 4)
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
 		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
@@ -3273,10 +3273,10 @@
 	idetape_pc_t pc;
 	int position;
 
-//#if IDETAPE_DEBUG_LOG
-//        if (tape->debug_level >= 4)
+#if IDETAPE_DEBUG_LOG
+        if (tape->debug_level >= 4)
 	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_LOG */
 
 #ifdef NO_LONGER_REQUIRED
 	idetape_flush_tape_buffers(drive);
diff -urN linux-2.4.19-pre4/drivers/ide/ide-timing.h linux-2.4.19-pre5/drivers/ide/ide-timing.h
--- linux-2.4.19-pre4/drivers/ide/ide-timing.h	Sat Feb  3 11:27:43 2001
+++ linux-2.4.19-pre5/drivers/ide/ide-timing.h	Fri Mar 29 14:49:30 2002
@@ -2,11 +2,9 @@
 #define _IDE_TIMING_H
 
 /*
- * $Id: ide-timing.h,v 1.5 2001/01/15 21:48:56 vojtech Exp $
+ * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -25,16 +23,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/hdreg.h>
 
-#ifndef XFER_PIO_5
 #define XFER_PIO_5		0x0d
 #define XFER_UDMA_SLOW		0x4f
-#endif
 
 struct ide_timing {
 	short mode;
@@ -49,13 +45,15 @@
 };
 
 /*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds).
+ * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
  * These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for PIO 5, which is a nonstandard extension.
+ * for PIO 5, which is a nonstandard extension and UDMA6, which
+ * is currently supported only by Maxtor drives. 
  */
 
 static struct ide_timing ide_timing[] = {
 
+	{ XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
 	{ XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
 	{ XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
 	{ XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
@@ -105,6 +103,7 @@
 #define EZ(v,unit)	((v)?ENOUGH(v,unit):0)
 
 #define XFER_MODE	0xf0
+#define XFER_UDMA_133	0x48
 #define XFER_UDMA_100	0x44
 #define XFER_UDMA_66	0x42
 #define XFER_UDMA	0x40
@@ -123,6 +122,9 @@
 
 	if ((map & XFER_UDMA) && (id->field_valid & 4)) {	/* Want UDMA and UDMA bitmap valid */
 
+		if ((map & XFER_UDMA_133) == XFER_UDMA_133)
+			if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
+
 		if ((map & XFER_UDMA_100) == XFER_UDMA_100)
 			if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
 
@@ -174,14 +176,14 @@
 
 static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
 {
-	q->setup   = EZ(t->setup,   T);
-	q->act8b   = EZ(t->act8b,   T);
-	q->rec8b   = EZ(t->rec8b,   T);
-	q->cyc8b   = EZ(t->cyc8b,   T);
-	q->active  = EZ(t->active,  T);
-	q->recover = EZ(t->recover, T);
-	q->cycle   = EZ(t->cycle,   T);
-	q->udma    = EZ(t->udma,   UT);
+	q->setup   = EZ(t->setup   * 1000,  T);
+	q->act8b   = EZ(t->act8b   * 1000,  T);
+	q->rec8b   = EZ(t->rec8b   * 1000,  T);
+	q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
+	q->active  = EZ(t->active  * 1000,  T);
+	q->recover = EZ(t->recover * 1000,  T);
+	q->cycle   = EZ(t->cycle   * 1000,  T);
+	q->udma    = EZ(t->udma    * 1000, UT);
 }
 
 static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what)
diff -urN linux-2.4.19-pre4/drivers/ide/pdc202xx.c linux-2.4.19-pre5/drivers/ide/pdc202xx.c
--- linux-2.4.19-pre4/drivers/ide/pdc202xx.c	Fri Mar 29 14:49:08 2002
+++ linux-2.4.19-pre5/drivers/ide/pdc202xx.c	Fri Mar 29 14:49:30 2002
@@ -215,6 +215,9 @@
 //	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
 
 	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "\n                                PDC20276 Chipset.\n");
+			break;
 		case PCI_DEVICE_ID_PROMISE_20275:
 			p += sprintf(p, "\n                                PDC20275 Chipset.\n");
 			break;
@@ -236,6 +239,7 @@
 {
 	char *p = buffer;
 	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
@@ -729,6 +733,7 @@
 				   (ultra_100)) ? 1 : 0;
 
 	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 			udma_133 = (udma_66) ? 1 : 0;
@@ -984,6 +989,7 @@
 	unsigned long dma_base	= hwif->dma_base;
 
 	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268R:
@@ -1116,6 +1122,7 @@
 	}
 
 	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268R:
@@ -1210,6 +1217,7 @@
 	unsigned short CIS;
 
         switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
@@ -1228,6 +1236,7 @@
 	hwif->quirkproc = &pdc202xx_quirkproc;
 
         switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
diff -urN linux-2.4.19-pre4/drivers/ide/via82cxxx.c linux-2.4.19-pre5/drivers/ide/via82cxxx.c
--- linux-2.4.19-pre4/drivers/ide/via82cxxx.c	Tue Sep 11 08:40:36 2001
+++ linux-2.4.19-pre5/drivers/ide/via82cxxx.c	Fri Mar 29 14:49:31 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: via82cxxx.c,v 3.29 2001/09/10 10:06:00 vojtech Exp $
+ * $Id: via82cxxx.c,v 3.34 2002/02/12 11:26:11 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
@@ -7,23 +7,21 @@
  *	Michel Aubry
  *	Jeff Garzik
  *	Andre Hedrick
- *
- *  Sponsored by SuSE
  */
 
 /*
  * VIA IDE driver for Linux. Supports
  *
  *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a
  *
  * southbridges, which can be found in
  *
  *  VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro,
  *    ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z,
  *    PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T,
- *    PX266, PM266, KX133, KT133, KT133A, KLE133, KT266, KX266, KM133, KM133A,
- *    KL133, KN133, KM266
+ *    PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133,
+ *    KM133A, KL133, KN133, KM266
  *  PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo,
  *    BXTel, BXpert
  *  AMD 640, 640 AGP, 750 IronGate, 760, 760MP
@@ -32,9 +30,9 @@
  *
  * chipsets. Supports
  *
- *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5
+ *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6
  *
- * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are
+ * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are
  * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore
  * the BIOS data and assume the cable is present, use 'ide0=ata66' or
  * 'ide1=ata66' on the kernel command line.
@@ -56,8 +54,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
@@ -87,10 +85,12 @@
 #define VIA_UDMA_33		0x001
 #define VIA_UDMA_66		0x002
 #define VIA_UDMA_100		0x003
+#define VIA_UDMA_133		0x004
 #define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
 #define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
 #define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
 #define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
 
 /*
  * VIA SouthBridge chips.
@@ -104,10 +104,11 @@
 	unsigned short flags;
 } via_isa_bridges[] = {
 #ifdef FUTURE_BRIDGES
-	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C,    0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
 #endif
+	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
@@ -121,6 +122,7 @@
 	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
 	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
 	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
 	{ NULL }
 };
 
@@ -128,7 +130,7 @@
 static unsigned char via_enabled;
 static unsigned int via_80w;
 static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
 
 /*
  * VIA /proc entry.
@@ -151,7 +153,7 @@
 
 static int via_get_info(char *buffer, char **addr, off_t offset, int count)
 {
-	short speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
 		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
 	struct pci_dev *dev = bmide_dev;
 	unsigned int v, u, i;
@@ -161,7 +163,7 @@
 
 	via_print("----------VIA BusMastering IDE Configuration----------------");
 
-	via_print("Driver Version:                     3.29");
+	via_print("Driver Version:                     3.34");
 	via_print("South Bridge:                       VIA %s", via_config->name);
 
 	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
@@ -170,7 +172,7 @@
 	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
 
 	via_print("BM-DMA base:                        %#x", via_base);
-	via_print("PCI clock:                          %dMHz", via_clock);
+	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
 
 	pci_read_config_byte(dev, VIA_MISC_1, &t);
 	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
@@ -218,40 +220,45 @@
 		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
 		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
 
-		speed[i] = 20 * via_clock / (active[i] + recover[i]);
-		cycle[i] = 1000 / via_clock * (active[i] + recover[i]);
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
 
 		if (!uen[i] || !den[i])
 			continue;
 
 		switch (via_config->flags & VIA_UDMA) {
-			
-			case VIA_UDMA_100:
-				speed[i] = 60 * via_clock / udma[i];
-				cycle[i] = 333 / via_clock * udma[i];
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
 				break;
 
 			case VIA_UDMA_66:
-				speed[i] = 40 * via_clock / (udma[i] * umul[i]);
-				cycle[i] = 500 / via_clock * (udma[i] * umul[i]);
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
 				break;
 
-			case VIA_UDMA_33:
-				speed[i] = 20 * via_clock / udma[i];
-				cycle[i] = 1000 / via_clock * udma[i];
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
 				break;
 		}
 	}
 
 	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
 
-	via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]);
-	via_print_drive("Cmd Active:    ", "%8dns", (1000 / via_clock) * active8b[i]);
-	via_print_drive("Cmd Recovery:  ", "%8dns", (1000 / via_clock) * recover8b[i]);
-	via_print_drive("Data Active:   ", "%8dns", (1000 / via_clock) * active[i]);
-	via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]);
+	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
 	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
-	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
 
 	return p - buffer;	/* hoping it is less than 4K... */
 }
@@ -280,6 +287,7 @@
 		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
 		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
 		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
 		default: return;
 	}
 
@@ -296,20 +304,21 @@
 {
 	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
 	struct ide_timing t, p;
-	int T, UT;
+	unsigned int T, UT;
 
 	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
 		if (ide_config_drive_speed(drive, speed))
 			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
 				drive->dn >> 1, drive->dn & 1);
 
-	T = 1000 / via_clock;
+	T = 1000000000 / via_clock;
 
 	switch (via_config->flags & VIA_UDMA) {
 		case VIA_UDMA_33:   UT = T;   break;
 		case VIA_UDMA_66:   UT = T/2; break;
 		case VIA_UDMA_100:  UT = T/3; break;
-		default:	    UT = T;   break;
+		case VIA_UDMA_133:  UT = T/4; break;
+		default: UT = T;
 	}
 
 	ide_timing_compute(drive, speed, &t, T, UT);
@@ -365,7 +374,8 @@
 			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
 			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
 			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0));
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
 
 		via_set_drive(drive, speed);
 
@@ -395,14 +405,16 @@
  */
 
 	for (via_config = via_isa_bridges; via_config->id; via_config++)
-		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) {
+		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+			!!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
+
 			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
 			if (t >= via_config->rev_min && t <= via_config->rev_max)
 				break;
 		}
 
 	if (!via_config->id) {
-		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@suse.cz>\n");
+		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
 		return -ENODEV;
 	}
 
@@ -412,22 +424,28 @@
 
 	switch (via_config->flags & VIA_UDMA) {
 
-		case VIA_UDMA_100:
-
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */
-			break;
-
 		case VIA_UDMA_66:
-
 			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
 			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
 			for (i = 24; i >= 0; i -= 8)
 				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
 					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
 			break;
+
+		case VIA_UDMA_100:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
+					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
+			break;
+
+		case VIA_UDMA_133:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
+					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
+			break;
+
 	}
 
 	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
@@ -466,11 +484,18 @@
  * Determine system bus clock.
  */
 
-	via_clock = system_bus_clock();
-	if (via_clock < 20 || via_clock > 50) {
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
 		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
-		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n");
-		via_clock = 33;
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
+		via_clock = 33333;
 	}
 
 /*
diff -urN linux-2.4.19-pre4/drivers/ieee1394/Config.in linux-2.4.19-pre5/drivers/ieee1394/Config.in
--- linux-2.4.19-pre4/drivers/ieee1394/Config.in	Thu Jul 19 17:48:15 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/Config.in	Fri Mar 29 14:49:31 2002
@@ -19,7 +19,14 @@
 	comment "Protocol Drivers"
 	dep_tristate '  OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
+	dep_tristate '  Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394
+	dep_tristate '  OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
+	dep_tristate '  IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394
+
+	if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
+	    dep_tristate '    IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP
+	fi
 
 	bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
     fi
diff -urN linux-2.4.19-pre4/drivers/ieee1394/Makefile linux-2.4.19-pre5/drivers/ieee1394/Makefile
--- linux-2.4.19-pre4/drivers/ieee1394/Makefile	Wed Oct 17 14:19:20 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/Makefile	Fri Mar 29 14:49:31 2002
@@ -4,7 +4,7 @@
 
 O_TARGET := ieee1394drv.o
 
-export-objs := ieee1394_core.o ohci1394.o
+export-objs := ieee1394_core.o ohci1394.o cmp.o
 
 list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
@@ -16,6 +16,10 @@
 obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
 obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
 obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
+obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
+obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
+obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o
+obj-$(CONFIG_IEEE1394_CMP) += cmp.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.19-pre4/drivers/ieee1394/amdtp.c linux-2.4.19-pre5/drivers/ieee1394/amdtp.c
--- linux-2.4.19-pre4/drivers/ieee1394/amdtp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/amdtp.c	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,1141 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * amdtp.c - Audio and Music Data Transmission Protocol Driver
+ * Copyright (C) 2001 Kristian Høgsberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* OVERVIEW
+ * --------
+ *
+ * The AMDTP driver is designed to expose the IEEE1394 bus as a
+ * regular OSS soundcard, i.e. you can link /dev/dsp to /dev/amdtp and
+ * then your favourite MP3 player, game or whatever sound program will
+ * output to an IEEE1394 isochronous channel.  The signal destination
+ * could be a set of IEEE1394 loudspeakers (if and when such things
+ * become available) or an amplifier with IEEE1394 input (like the
+ * Sony STR-LSA1).  The driver only handles the actual streaming, some
+ * connection management is also required for this to actually work.
+ * That is outside the scope of this driver, and furthermore it is not
+ * really standardized yet.
+ *
+ * The Audio and Music Data Tranmission Protocol is avaiable at
+ *
+ *     http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf
+ *
+ *
+ * TODO
+ * ----
+ *
+ * - We should be able to change input sample format between LE/BE, as
+ *   we already shift the bytes around when we construct the iso
+ *   packets.
+ *
+ * - Fix DMA stop after bus reset!
+ *
+ * - Implement poll.
+ *
+ * - Clean up iso context handling in ohci1394.
+ *
+ *
+ * MAYBE TODO
+ * ----------
+ *
+ * - Receive data for local playback or recording.  Playback requires
+ *   soft syncing with the sound card.
+ *
+ * - Signal processing, i.e. receive packets, do some processing, and
+ *   transmit them again using the same packet structure and timestamps
+ *   offset by processing time.
+ *
+ * - Maybe make an ALSA interface, that is, create a file_ops
+ *   implementation that recognizes ALSA ioctls and uses defaults for
+ *   things that can't be controlled through ALSA (iso channel).
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include "hosts.h"
+#include "highlevel.h"
+#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "ohci1394.h"
+
+#include "amdtp.h"
+#include "cmp.h"
+
+#define FMT_AMDTP 0x10
+#define FDF_AM824 0x00
+#define FDF_SFC_32KHZ  0x00 /* 32kHz */
+#define FDF_SFC_44K1HZ 0x01 /* 44.1kHz */
+#define FDF_SFC_48KHZ  0x02 /* 44.1kHz */
+
+struct descriptor_block {
+	struct output_more_immediate {
+		u32 control;
+		u32 pad0;
+		u32 skip;
+		u32 pad1;
+		u32 header[4];
+	} header_desc;
+
+	struct output_last {
+		u32 control;
+		u32 data_address;
+		u32 branch;
+		u32 status;
+	} payload_desc;
+};
+
+struct packet {
+	struct descriptor_block *db;
+	dma_addr_t db_bus;
+	quadlet_t *payload;
+	dma_addr_t payload_bus;
+};
+
+struct fraction {
+	int integer;
+	int numerator;
+	int denominator;
+	int counter;
+};
+
+#define PACKET_LIST_SIZE 256
+#define MAX_PACKET_LISTS 4
+
+struct packet_list {
+	struct list_head link;
+	int last_cycle_count;
+	struct packet packets[PACKET_LIST_SIZE];
+};
+
+#define BUFFER_SIZE 128
+
+/* This implements a circular buffer for incoming samples. */
+
+struct buffer {
+	int head, tail, length, size;
+	unsigned char data[0];
+};
+
+struct stream {
+	int iso_channel;
+	int format;
+	int rate;
+	int dimension;
+	int fdf;
+	struct cmp_pcr *opcr;
+
+	/* Input samples are copied here. */
+	struct buffer *input;
+
+	/* ISO Packer state */
+	unsigned char dbc;
+	struct packet_list *current_packet_list;
+	int current_packet;
+	struct fraction packet_size_fraction;
+
+	/* We use these to generate control bits when we are packing
+	 * iec958 data.
+	 */
+	int iec958_frame_count;
+	int iec958_rate_code;
+
+	/* The cycle_count and cycle_offset fields are used for the
+	 * synchronization timestamps (syt) in the cip header.  They
+	 * are incremented by at least a cycle every time we put a
+	 * time stamp in a packet.  As we dont time stamp all
+	 * packages, cycle_count isn't updated in every cycle, and
+	 * sometimes it's incremented by 2.  Thus, we have
+	 * cycle_count2, which is simply incremented by one with each
+	 * packet, so we can compare it to the transmission time
+	 * written back in the dma programs.
+	 */
+	atomic_t cycle_count, cycle_count2;
+	int cycle_offset;
+	struct fraction syt_fraction;
+	int syt_interval;
+	int stale_count;
+
+	/* Theses fields control the sample output to the DMA engine.
+	 * The dma_packet_lists list holds packet lists currently
+	 * queued for dma; the head of the list is currently being
+	 * processed.  The last program in a packet list generates an
+	 * interrupt, which removes the head from dma_packet_lists and
+	 * puts it back on the free list.
+	 */
+	struct list_head dma_packet_lists;
+	struct list_head free_packet_lists;
+        wait_queue_head_t packet_list_wait;
+	spinlock_t packet_list_lock;
+	int iso_context;
+	struct pci_pool *descriptor_pool, *packet_pool;
+
+	/* Streams at a host controller are chained through this field. */
+	struct list_head link;
+	struct amdtp_host *host;
+};
+
+struct amdtp_host {
+	struct hpsb_host *host;
+	struct ti_ohci *ohci;
+	struct list_head stream_list;
+	spinlock_t stream_list_lock;
+	struct list_head link;
+};
+
+static struct hpsb_highlevel *amdtp_highlevel;
+static LIST_HEAD(host_list);
+static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
+
+/* FIXME: This doesn't belong here... */
+
+#define OHCI1394_CONTEXT_CYCLE_MATCH 0x80000000
+#define OHCI1394_CONTEXT_RUN         0x00008000
+#define OHCI1394_CONTEXT_WAKE        0x00001000
+#define OHCI1394_CONTEXT_DEAD        0x00000800
+#define OHCI1394_CONTEXT_ACTIVE      0x00000400
+
+static inline int ohci1394_alloc_it_ctx(struct ti_ohci *ohci)
+{
+	int i;
+
+	for (i = 0; i < ohci->nb_iso_xmit_ctx; i++)
+		if (!test_and_set_bit(i, &ohci->it_ctx_usage))
+			return i;
+
+	return -EBUSY;
+}
+	
+static inline void ohci1394_free_it_ctx(struct ti_ohci *ohci, int ctx)
+{
+	clear_bit(ctx, &ohci->it_ctx_usage);
+}
+
+
+void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx,
+			   dma_addr_t first_cmd, int z, int cycle_match)
+{
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx);
+	reg_write(ohci, OHCI1394_IsoXmitCommandPtr + ctx * 16, first_cmd | z);
+	reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16, ~0);
+	wmb();
+	reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16,
+		  OHCI1394_CONTEXT_CYCLE_MATCH | (cycle_match << 16) |
+		  OHCI1394_CONTEXT_RUN);
+}
+
+void ohci1394_wake_it_ctx(struct ti_ohci *ohci, int ctx)
+{
+	reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16,
+		  OHCI1394_CONTEXT_WAKE);
+}
+
+void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx)
+{
+	u32 control;
+	int wait;
+
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << ctx);
+	reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16,
+		  OHCI1394_CONTEXT_RUN);
+	wmb();
+
+	for (wait = 0; wait < 5; wait++) {
+		control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16);
+		if ((control & OHCI1394_CONTEXT_ACTIVE) == 0)
+			break;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+}
+
+/* Note: we can test if free_packet_lists is empty without aquiring
+ * the packet_list_lock.  The interrupt handler only adds to the free
+ * list, there is no race condition between testing the list non-empty
+ * and acquiring the lock.
+ */
+
+static struct packet_list *stream_get_free_packet_list(struct stream *s)
+{
+	struct packet_list *pl;
+	unsigned long flags;
+
+	if (list_empty(&s->free_packet_lists))
+		return NULL;
+
+	spin_lock_irqsave(&s->packet_list_lock, flags);
+	pl = list_entry(s->free_packet_lists.next, struct packet_list, link);
+	list_del(&pl->link);
+	spin_unlock_irqrestore(&s->packet_list_lock, flags);
+
+	return pl;
+}
+
+static void stream_put_dma_packet_list(struct stream *s,
+				       struct packet_list *pl)
+{
+	unsigned long flags;
+	struct packet_list *prev;
+
+	/* Remember the cycle_count used for timestamping the last packet. */
+	pl->last_cycle_count = atomic_read(&s->cycle_count2) - 1;
+	pl->packets[PACKET_LIST_SIZE - 1].db->payload_desc.branch = 0;
+
+	spin_lock_irqsave(&s->packet_list_lock, flags);
+	list_add_tail(&pl->link, &s->dma_packet_lists);
+	spin_unlock_irqrestore(&s->packet_list_lock, flags);
+
+	prev = list_entry(pl->link.prev, struct packet_list, link);
+	if (pl->link.prev != &s->dma_packet_lists) {
+		struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1];
+		last->db->payload_desc.branch = pl->packets[0].db_bus | 3;
+		ohci1394_wake_it_ctx(s->host->ohci, s->iso_context);
+	}
+	else {
+		u32 syt, cycle_count;
+
+		cycle_count = reg_read(s->host->host->hostdata,
+				       OHCI1394_IsochronousCycleTimer) >> 12;
+		syt = (pl->packets[0].payload[1] >> 12) & 0x0f;
+		cycle_count = (cycle_count & ~0x0f) + 32 + syt;
+		if ((cycle_count & 0x1fff) >= 8000)
+			cycle_count = cycle_count - 8000 + 0x2000;
+
+		ohci1394_start_it_ctx(s->host->ohci, s->iso_context,
+				      pl->packets[0].db_bus, 3,
+				      cycle_count & 0x7fff);
+	}
+}
+
+static void stream_shift_packet_lists(struct stream *s)
+{
+	struct packet_list *pl;
+	struct packet *last;
+	int diff;
+
+	if (list_empty(&s->dma_packet_lists)) {
+		HPSB_ERR("empty dma_packet_lists in %s", __FUNCTION__);
+		return;
+	}
+
+	/* Now that we know the list is non-empty, we can get the head
+	 * of the list without locking, because the process context
+	 * only adds to the tail.  
+	 */
+	pl = list_entry(s->dma_packet_lists.next, struct packet_list, link);
+	last = &pl->packets[PACKET_LIST_SIZE - 1];
+
+	/* This is weird... if we stop dma processing in the middle of
+	 * a packet list, the dma context immediately generates an
+	 * interrupt if we enable it again later.  This only happens
+	 * when amdtp_release is interrupted while waiting for dma to
+	 * complete, though.  Anyway, we detect this by seeing that
+	 * the status of the dma descriptor that we expected an
+	 * interrupt from is still 0.
+	 */
+	if (last->db->payload_desc.status == 0) {
+		HPSB_INFO("weird interrupt...");
+		return;
+	}		
+
+	/* If the last descriptor block does not specify a branch
+	 * address, we have a sample underflow.
+	 */
+	if (last->db->payload_desc.branch == 0)
+		HPSB_INFO("FIXME: sample underflow...");
+
+	/* Here we check when (which cycle) the last packet was sent
+	 * and compare it to what the iso packer was using at the
+	 * time.  If there is a mismatch, we adjust the cycle count in
+	 * the iso packer.  However, there are still up to
+	 * MAX_PACKET_LISTS packet lists queued with bad time stamps,
+	 * so we disable time stamp monitoring for the next
+	 * MAX_PACKET_LISTS packet lists.
+	 */
+	diff = (last->db->payload_desc.status - pl->last_cycle_count) & 0xf;
+	if (diff > 0 && s->stale_count == 0) {
+		atomic_add(diff, &s->cycle_count);
+		atomic_add(diff, &s->cycle_count2);
+		s->stale_count = MAX_PACKET_LISTS;
+	}
+
+	if (s->stale_count > 0)
+		s->stale_count--;
+
+	/* Finally, we move the packet list that was just processed
+	 * back to the free list, and notify any waiters.
+	 */
+	spin_lock(&s->packet_list_lock);
+	list_del(&pl->link);
+	list_add_tail(&pl->link, &s->free_packet_lists);
+	spin_unlock(&s->packet_list_lock);
+
+	wake_up_interruptible(&s->packet_list_wait);
+}
+
+static struct packet *stream_current_packet(struct stream *s)
+{
+	if (s->current_packet_list == NULL &&
+	    (s->current_packet_list = stream_get_free_packet_list(s)) == NULL)
+		return NULL;
+
+	return &s->current_packet_list->packets[s->current_packet];
+}
+	
+static void stream_queue_packet(struct stream *s)
+{
+	s->current_packet++;
+	if (s->current_packet == PACKET_LIST_SIZE) {
+		stream_put_dma_packet_list(s, s->current_packet_list);
+		s->current_packet_list = NULL;
+		s->current_packet = 0;
+	}
+}
+
+/* Integer fractional math.  When we transmit a 44k1Hz signal we must
+ * send 5 41/80 samples per isochronous cycle, as these occur 8000
+ * times a second.  Of course, we must send an integral number of
+ * samples in a packet, so we use the integer math to alternate
+ * between sending 5 and 6 samples per packet.
+ */
+
+static void fraction_init(struct fraction *f, int numerator, int denominator)
+{
+	f->integer = numerator / denominator;
+	f->numerator = numerator % denominator;
+	f->denominator = denominator;
+	f->counter = 0;
+}
+
+static int fraction_next_size(struct fraction *f)
+{
+	return f->integer + ((f->counter + f->numerator) / f->denominator);
+}
+
+static void fraction_inc(struct fraction *f)
+{
+	f->counter = (f->counter + f->numerator) % f->denominator;
+}
+
+static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent,
+			      quadlet_t isoXmitIntEvent, void *data)
+{
+	struct amdtp_host *host = data;
+	struct list_head *lh;
+	struct stream *s = NULL;
+
+	spin_lock(&host->stream_list_lock);
+	list_for_each(lh, &host->stream_list) {
+		s = list_entry(lh, struct stream, link);
+		if (isoXmitIntEvent & (1 << s->iso_context))
+			break;
+	}
+	spin_unlock(&host->stream_list_lock);
+
+	if (s != NULL)
+		stream_shift_packet_lists(s);
+}
+
+void packet_initialize(struct packet *p, struct packet *next)
+{
+	/* Here we initialize the dma descriptor block for
+	 * transferring one iso packet.  We use two descriptors per
+	 * packet: an OUTPUT_MORE_IMMMEDIATE descriptor for the
+	 * IEEE1394 iso packet header and an OUTPUT_LAST descriptor
+	 * for the payload.
+	 */
+
+	p->db->header_desc.control =
+		DMA_CTL_OUTPUT_MORE | DMA_CTL_IMMEDIATE | 8;
+	p->db->header_desc.skip = 0;
+
+	if (next) {
+		p->db->payload_desc.control = 
+			DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
+		p->db->payload_desc.branch = next->db_bus | 3;
+	}
+	else {
+		p->db->payload_desc.control = 
+			DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH |
+			DMA_CTL_UPDATE | DMA_CTL_IRQ;
+		p->db->payload_desc.branch = 0;
+	}
+	p->db->payload_desc.data_address = p->payload_bus;
+	p->db->payload_desc.status = 0;
+}
+
+struct packet_list *packet_list_alloc(struct stream *s)
+{
+	int i;
+	struct packet_list *pl;
+	struct packet *next;
+
+	pl = kmalloc(sizeof *pl, SLAB_KERNEL);
+	if (pl == NULL)
+		return NULL;
+
+	for (i = 0; i < PACKET_LIST_SIZE; i++) {
+		struct packet *p = &pl->packets[i];
+		p->db = pci_pool_alloc(s->descriptor_pool, SLAB_KERNEL,
+				       &p->db_bus);
+		p->payload = pci_pool_alloc(s->packet_pool, SLAB_KERNEL,
+					    &p->payload_bus);
+	}
+
+	for (i = 0; i < PACKET_LIST_SIZE; i++) {
+		if (i < PACKET_LIST_SIZE - 1)
+			next = &pl->packets[i + 1];
+		else 
+			next = NULL;
+		packet_initialize(&pl->packets[i], next);
+	}
+
+	return pl;
+}
+
+void packet_list_free(struct packet_list *pl, struct stream *s)
+{
+	int i;
+
+	for (i = 0; i < PACKET_LIST_SIZE; i++) {
+		struct packet *p = &pl->packets[i];
+		pci_pool_free(s->descriptor_pool, p->db, p->db_bus);
+		pci_pool_free(s->packet_pool, p->payload, p->payload_bus);
+	}
+	kfree(pl);
+}
+
+static struct buffer *buffer_alloc(int size)
+{
+	struct buffer *b;
+
+	b = kmalloc(sizeof *b + size, SLAB_KERNEL);
+	b->head = 0;
+	b->tail = 0;
+	b->length = 0;
+	b->size = size;
+
+	return b;
+}
+
+static unsigned char *buffer_get_bytes(struct buffer *buffer, int size)
+{
+	unsigned char *p;
+
+	if (buffer->head + size > buffer->size)
+		BUG();
+
+	p = &buffer->data[buffer->head];
+	buffer->head += size;
+	if (buffer->head == buffer->size)
+		buffer->head = 0;
+	buffer->length -= size;
+
+	return p;
+}
+
+static unsigned char *buffer_put_bytes(struct buffer *buffer,
+				       int max, int *actual)
+{
+	int length;
+	unsigned char *p;
+
+	p = &buffer->data[buffer->tail];
+	length = min(buffer->size - buffer->length, max);
+	if (buffer->tail + length < buffer->size) {
+		*actual = length;
+		buffer->tail += length;
+	}
+	else {
+		*actual = buffer->size - buffer->tail;
+		 buffer->tail = 0;
+	}
+
+	buffer->length += *actual;
+	return p;
+}
+
+static u32 get_iec958_header_bits(struct stream *s, int sub_frame, u32 sample)
+{
+	int csi, parity, shift;
+	int block_start;
+	u32 bits;
+
+	switch (s->iec958_frame_count) {
+	case 1:
+		csi = s->format == AMDTP_FORMAT_IEC958_AC3;
+		break;
+	case 2:
+	case 9:
+		csi = 1;
+		break;
+	case 24 ... 27:
+		csi = (s->iec958_rate_code >> (27 - s->iec958_frame_count)) & 0x01;
+		break;
+	default:
+		csi = 0;
+		break;
+	}
+
+	block_start = (s->iec958_frame_count == 0 && sub_frame == 0);
+
+	/* The parity bit is the xor of the sample bits and the
+	 * channel status info bit. */
+	for (shift = 16, parity = sample ^ csi; shift > 0; shift >>= 1)
+		parity ^= (parity >> shift);
+
+	bits =  (block_start << 5) |		/* Block start bit */
+		((sub_frame == 0) << 4) |	/* Subframe bit */
+		((parity & 1) << 3) |		/* Parity bit */
+		(csi << 2);			/* Channel status info bit */
+
+	return bits;
+}
+
+static u32 get_header_bits(struct stream *s, int sub_frame, u32 sample)
+{
+	switch (s->format) {
+	case AMDTP_FORMAT_IEC958_PCM:
+	case AMDTP_FORMAT_IEC958_AC3:
+		return get_iec958_header_bits(s, sub_frame, sample);
+		
+	case AMDTP_FORMAT_RAW:
+		return 0x40000000;
+
+	default:
+		return 0;
+	}
+}
+
+
+static void fill_packet(struct stream *s, struct packet *packet, int nevents)
+{
+	int size, node_id, i, j;
+	quadlet_t *event;
+	unsigned char *p;
+	u32 control, sample, bits;
+	int syt_index, syt, next;
+
+	size = (nevents * s->dimension + 2) * sizeof(quadlet_t);
+	node_id = s->host->host->node_id & 0x3f;
+
+	/* Update DMA descriptors */
+	packet->db->payload_desc.status = 0;
+	control = packet->db->payload_desc.control & 0xffff0000;
+	packet->db->payload_desc.control = control | size;
+
+	/* Fill IEEE1394 headers */
+	packet->db->header_desc.header[0] =
+		(SPEED_100 << 16) | (0x01 << 14) | 
+		(s->iso_channel << 8) | (TCODE_ISO_DATA << 4);
+	packet->db->header_desc.header[1] = size << 16;
+	
+	/* Fill cip header */
+	syt_index = s->dbc & (s->syt_interval - 1);
+	if (syt_index == 0 || syt_index + nevents > s->syt_interval) {
+		syt = ((atomic_read(&s->cycle_count) << 12) | 
+		       s->cycle_offset) & 0xffff;
+		next = fraction_next_size(&s->syt_fraction) + s->cycle_offset;
+		/* This next addition should be modulo 8000 (0x1f40),
+		 * but we only use the lower 4 bits of cycle_count, so
+		 * we dont need the modulo. */
+		atomic_add(next / 3072, &s->cycle_count);
+		s->cycle_offset = next % 3072;
+		fraction_inc(&s->syt_fraction);
+	}
+	else {
+		syt = 0xffff;
+		next = 0;
+	}
+	atomic_inc(&s->cycle_count2);
+
+	packet->payload[0] = cpu_to_be32((node_id << 24) | (s->dimension << 16) | s->dbc);
+	packet->payload[1] = cpu_to_be32((1 << 31) | (FMT_AMDTP << 24) | (s->fdf << 16) | syt);
+
+	/* Fill payload */
+	for (i = 0, event = &packet->payload[2]; i < nevents; i++) {
+
+		for (j = 0; j < s->dimension; j++) {
+			p = buffer_get_bytes(s->input, 2);
+			sample = (p[1] << 16) | (p[0] << 8);
+			bits = get_header_bits(s, j, sample);
+			event[j] = cpu_to_be32((bits << 24) | sample);
+		}
+
+		event += s->dimension;
+		if (++s->iec958_frame_count == 192)
+			s->iec958_frame_count = 0;
+	}
+
+	s->dbc += nevents;
+}
+
+static void stream_flush(struct stream *s)
+{
+	struct packet *p;
+	int nevents;
+
+	while (nevents = fraction_next_size(&s->packet_size_fraction),
+	       p = stream_current_packet(s),
+	       nevents * s->dimension * 2 <= s->input->length && p != NULL) {
+		fill_packet(s, p, nevents);
+		fraction_inc(&s->packet_size_fraction);
+		stream_queue_packet(s);
+	}
+}
+
+static int stream_alloc_packet_lists(struct stream *s)
+{
+	int max_nevents, max_packet_size, i;
+
+	max_nevents = s->packet_size_fraction.integer;
+	if (s->packet_size_fraction.numerator > 0)
+		max_nevents++;
+
+	max_packet_size = max_nevents * s->dimension * 4 + 8;
+	s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev,
+					 max_packet_size, 0, 0, SLAB_KERNEL);
+	if (s->packet_pool == NULL)
+		return -1;
+
+	INIT_LIST_HEAD(&s->free_packet_lists);
+	INIT_LIST_HEAD(&s->dma_packet_lists);
+	for (i = 0; i < MAX_PACKET_LISTS; i++) {
+		struct packet_list *pl = packet_list_alloc(s);
+		if (pl == NULL)
+			break;
+		list_add_tail(&pl->link, &s->free_packet_lists);
+	}
+
+	return i < MAX_PACKET_LISTS ? -1 : 0;
+}
+
+static void stream_free_packet_lists(struct stream *s)
+{
+	struct list_head *lh, *next;
+
+	if (s->current_packet_list != NULL)
+		packet_list_free(s->current_packet_list, s);
+	list_for_each_safe(lh, next, &s->dma_packet_lists)
+		packet_list_free(list_entry(lh, struct packet_list, link), s);
+	list_for_each_safe(lh, next, &s->free_packet_lists)
+		packet_list_free(list_entry(lh, struct packet_list, link), s);
+	if (s->packet_pool != NULL)
+		pci_pool_destroy(s->packet_pool);
+
+	s->current_packet_list = NULL;
+	INIT_LIST_HEAD(&s->free_packet_lists);
+	INIT_LIST_HEAD(&s->dma_packet_lists);
+	s->packet_pool = NULL;
+}
+
+static void plug_update(struct cmp_pcr *plug, void *data)
+{
+	struct stream *s = data;
+
+	HPSB_INFO("plug update: p2p_count=%d, channel=%d",
+		  plug->p2p_count, plug->channel);
+	s->iso_channel = plug->channel;
+	if (plug->p2p_count > 0) {
+		/* start streaming */
+	}
+	else {
+		/* stop streaming */
+	}
+}
+
+static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg)
+{
+	if (cfg->format <= AMDTP_FORMAT_IEC958_AC3)
+		s->format = cfg->format;
+	else
+		return -EINVAL;
+
+	switch (cfg->rate) {
+	case 32000:
+		s->syt_interval = 8;
+		s->fdf = FDF_SFC_32KHZ;
+		s->iec958_rate_code = 0x0c;
+		s->rate = cfg->rate;
+		break;
+	case 44100:
+		s->syt_interval = 8;
+		s->fdf = FDF_SFC_44K1HZ;
+		s->iec958_rate_code = 0x00;
+		s->rate = cfg->rate;
+		break;
+	case 48000:
+		s->syt_interval = 8;
+		s->fdf = FDF_SFC_48KHZ;
+		s->iec958_rate_code = 0x04;
+		s->rate = cfg->rate;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fraction_init(&s->packet_size_fraction, s->rate, 8000);
+
+	/* The syt_fraction is initialized to the number of ticks
+	 * between syt_interval events.  The number of ticks per
+	 * second is 24.576e6, so the number of ticks between
+	 * syt_interval events is 24.576e6 * syt_interval / rate.
+	 */
+	fraction_init(&s->syt_fraction, 24576000 * s->syt_interval, s->rate);
+
+	/* When using the AM824 raw subformat we can stream signals of
+	 * any dimension.  The IEC958 subformat, however, only
+	 * supports 2 channels.
+	 */
+	if (s->format == AMDTP_FORMAT_RAW || cfg->dimension == 2)
+		s->dimension = cfg->dimension;
+	else
+		return -EINVAL;
+
+	if (s->opcr != NULL) {
+		cmp_unregister_opcr(s->host->host, s->opcr);
+		s->opcr = NULL;
+	}
+
+	switch(cmd) {
+	case AMDTP_IOC_PLUG:
+		s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug,
+					   /*payload*/ 12, plug_update, s);
+		if (s->opcr == NULL)
+			return -EINVAL;
+		s->iso_channel = s->opcr->channel;
+		break;
+
+	case AMDTP_IOC_CHANNEL:
+		if (cfg->u.channel >= 0 && cfg->u.channel < 64)
+			s->iso_channel = cfg->u.channel;
+		else
+			return -EINVAL;
+		break;
+	}
+
+	/* The ioctl settings were all valid, so we realloc the packet
+	 * lists to make sure the packet size is big enough.
+	 */
+	if (s->packet_pool != NULL)
+		stream_free_packet_lists(s);
+
+	if (stream_alloc_packet_lists(s) < 0) {
+		stream_free_packet_lists(s);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+struct stream *stream_alloc(struct amdtp_host *host)
+{
+	struct stream *s;
+	unsigned long flags;
+	const int transfer_delay = 8651; /* approx 352 us */
+
+        s = kmalloc(sizeof(struct stream), SLAB_KERNEL);
+        if (s == NULL)
+                return NULL;
+
+        memset(s, 0, sizeof(struct stream));
+	s->host = host;
+
+	s->input = buffer_alloc(BUFFER_SIZE);
+	if (s->input == NULL) {
+		kfree(s);
+		return NULL;
+	}
+
+	s->cycle_offset = transfer_delay % 3072;
+	atomic_set(&s->cycle_count, transfer_delay / 3072);
+	atomic_set(&s->cycle_count2, 0);
+
+	s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev,
+					     sizeof(struct descriptor_block),
+					     16, 0, SLAB_KERNEL);
+	if (s->descriptor_pool == NULL) {
+		kfree(s->input);
+		kfree(s);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&s->free_packet_lists);
+	INIT_LIST_HEAD(&s->dma_packet_lists);
+
+        init_waitqueue_head(&s->packet_list_wait);
+        spin_lock_init(&s->packet_list_lock);
+
+	s->iso_context = ohci1394_alloc_it_ctx(host->ohci);
+	if (s->iso_context < 0) {
+		pci_pool_destroy(s->descriptor_pool);
+		kfree(s->input);
+		kfree(s);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&host->stream_list_lock, flags);
+	list_add_tail(&s->link, &host->stream_list);
+	spin_unlock_irqrestore(&host->stream_list_lock, flags);
+
+	return s;
+}
+
+void stream_free(struct stream *s)
+{
+	unsigned long flags;
+
+	/* Stop the DMA.  We wait for the dma packet list to become
+	 * empty and let the dma controller run out of programs.  This
+	 * seems to be more reliable than stopping it directly, since
+	 * that sometimes generates an it transmit interrupt if we
+	 * later re-enable the context.
+	 */
+	wait_event_interruptible(s->packet_list_wait, 
+				 list_empty(&s->dma_packet_lists));
+
+	ohci1394_stop_it_ctx(s->host->ohci, s->iso_context);
+	ohci1394_free_it_ctx(s->host->ohci, s->iso_context);
+
+	if (s->opcr != NULL)
+		cmp_unregister_opcr(s->host->host, s->opcr);
+
+	spin_lock_irqsave(&s->host->stream_list_lock, flags);
+	list_del(&s->link);
+	spin_unlock_irqrestore(&s->host->stream_list_lock, flags);
+
+	kfree(s->input);
+
+	stream_free_packet_lists(s);
+	pci_pool_destroy(s->descriptor_pool);
+
+	kfree(s);
+}
+
+/* File operations */
+
+static ssize_t amdtp_write(struct file *file, const char *buffer, size_t count,
+			   loff_t *offset_is_ignored)
+{
+	struct stream *s = file->private_data;
+	unsigned char *p;
+	int i, length;
+	
+	if (s->packet_pool == NULL)
+		return -EBADFD;
+
+	/* Fill the circular buffer from the input buffer and call the
+	 * iso packer when the buffer is full.  The iso packer may
+	 * leave bytes in the buffer for two reasons: either the
+	 * remaining bytes wasn't enough to build a new packet, or
+	 * there were no free packet lists.  In the first case we
+	 * re-fill the buffer and call the iso packer again or return
+	 * if we used all the data from userspace.  In the second
+	 * case, the wait_event_interruptible will block until the irq
+	 * handler frees a packet list.
+	 */
+
+	for (i = 0; i < count; i += length) {
+		p = buffer_put_bytes(s->input, count, &length);
+		copy_from_user(p, buffer + i, length);
+		if (s->input->length < s->input->size)
+			continue;
+		
+		stream_flush(s);
+		
+		if (s->current_packet_list == NULL &&
+		    wait_event_interruptible(s->packet_list_wait, 
+					     !list_empty(&s->free_packet_lists)))
+			return -EINTR;
+	}
+
+	return count;
+}
+
+static int amdtp_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct stream *s = file->private_data;
+	struct amdtp_ioctl cfg;
+	int new;
+
+	switch(cmd)
+	{
+	case AMDTP_IOC_PLUG:
+	case AMDTP_IOC_CHANNEL:
+		if (copy_from_user(&cfg, (struct amdtp_ioctl *) arg, sizeof cfg))
+			return -EFAULT;
+		else 
+			return stream_configure(s, cmd, &cfg);
+
+	case AMDTP_IOC_PING:
+		HPSB_INFO("ping: offsetting timpestamps %ld ticks", arg);
+		new = s->cycle_offset + arg;
+		s->cycle_offset = new % 3072;
+		atomic_add(new / 3072, &s->cycle_count);
+		return 0;
+
+	case AMDTP_IOC_ZAP:
+		while (MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int amdtp_open(struct inode *inode, struct file *file)
+{
+	struct amdtp_host *host;
+
+	/* FIXME: We just grab the first registered host */
+	spin_lock(&host_list_lock);
+	if (!list_empty(&host_list))
+		host = list_entry(host_list.next, struct amdtp_host, link);
+	else
+		host = NULL;
+	spin_unlock(&host_list_lock);
+
+	if (host == NULL)
+		return -ENODEV;
+
+	file->private_data = stream_alloc(host);
+	if (file->private_data == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int amdtp_release(struct inode *inode, struct file *file)
+{
+	struct stream *s = file->private_data;
+
+	stream_free(s);
+
+	return 0;
+}
+
+static struct file_operations amdtp_fops =
+{
+	owner:		THIS_MODULE,
+	write:		amdtp_write,
+	ioctl:		amdtp_ioctl,
+	open:		amdtp_open,
+	release:	amdtp_release
+};
+
+/* IEEE1394 Subsystem functions */
+
+static void amdtp_add_host(struct hpsb_host *host)
+{
+	struct amdtp_host *ah;
+
+	/* FIXME: check it's an ohci host. */
+
+	ah = kmalloc(sizeof *ah, SLAB_KERNEL);
+	ah->host = host;
+	ah->ohci = host->hostdata;
+	INIT_LIST_HEAD(&ah->stream_list);
+	spin_lock_init(&ah->stream_list_lock);
+
+	spin_lock_irq(&host_list_lock);
+	list_add_tail(&ah->link, &host_list);
+	spin_unlock_irq(&host_list_lock);
+
+	ohci1394_hook_irq(ah->ohci, amdtp_irq_handler, ah);
+}
+
+static void amdtp_remove_host(struct hpsb_host *host)
+{
+	struct list_head *lh;
+	struct amdtp_host *ah;
+
+	spin_lock_irq(&host_list_lock);
+	list_for_each(lh, &host_list) {
+		if (list_entry(lh, struct amdtp_host, link)->host == host) {
+			list_del(lh);
+			break;
+		}
+	}
+	spin_unlock_irq(&host_list_lock);
+	
+	if (lh != &host_list) {
+		ah = list_entry(lh, struct amdtp_host, link);
+		ohci1394_unhook_irq(ah->ohci, amdtp_irq_handler, ah);
+		kfree(ah);
+	}
+	else
+		HPSB_ERR("remove_host: bogus ohci host: %p", host);
+}
+
+static struct hpsb_highlevel_ops amdtp_highlevel_ops = {
+	add_host:	amdtp_add_host,
+	remove_host:	amdtp_remove_host,
+};
+
+/* Module interface */
+
+MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
+MODULE_DESCRIPTION("Driver for Audio & Music Data Transmission Protocol "
+		   "on OHCI boards.");
+MODULE_SUPPORTED_DEVICE("amdtp");
+MODULE_LICENSE("GPL");
+
+static int __init amdtp_init_module (void)
+{
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL,
+				      THIS_MODULE, &amdtp_fops)) {
+		HPSB_ERR("amdtp: unable to get minor device block");
+ 		return -EIO;
+ 	}
+
+	amdtp_highlevel = hpsb_register_highlevel ("amdtp",
+						   &amdtp_highlevel_ops);
+	if (amdtp_highlevel == NULL) {
+		HPSB_ERR("amdtp: unable to register highlevel ops");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
+		return -EIO;
+	}
+
+	HPSB_INFO("Loaded AMDTP driver");
+
+	return 0;
+}
+
+static void __exit amdtp_exit_module (void)
+{
+        hpsb_unregister_highlevel(amdtp_highlevel);
+        ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
+
+	HPSB_INFO("Unloaded AMDTP driver");
+}
+
+module_init(amdtp_init_module);
+module_exit(amdtp_exit_module);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/amdtp.h linux-2.4.19-pre5/drivers/ieee1394/amdtp.h
--- linux-2.4.19-pre4/drivers/ieee1394/amdtp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/amdtp.h	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,75 @@
+/* -*- c-basic-offset: 8 -*- */
+
+#ifndef __AMDTP_H
+#define __AMDTP_H
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
+/* The userspace interface for the Audio & Music Data Transmission
+ * Protocol driver is really simple. First, open /dev/amdtp, use the
+ * ioctl to configure format, rate, dimension and either plug or
+ * channel, then start writing samples.
+ *
+ * The formats supported by the driver are listed below.
+ * AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can
+ * carry any number of channels, so use this if you're streaming
+ * multichannel audio.  The AMDTP_FORMAT_IEC958_PCM corresponds to the
+ * AM824 IEC958 encapsulation without the IEC958 data bit set, using
+ * AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit
+ * set, suitable for transmitting compressed AC-3 audio.
+ *
+ * The rate field specifies the transmission rate; supported values are
+ * AMDTP_RATE_32KHZ, AMDTP_RATE_44K1HZ and AMDTP_RATE_48KHZ.
+ *
+ * The dimension field specifies the dimension of the signal, that is,
+ * the number of audio channels.  Only AMDTP_FORMAT_RAW supports
+ * settings greater than 2.  
+ *
+ * The last thing to specify is either the isochronous channel to use
+ * or the output plug to connect to.  If you know what channel the
+ * destination device will listen on, you can specify the channel
+ * directly and use the AMDTP_IOC_CHANNEL ioctl.  However, if the
+ * destination device chooses the channel and uses the IEC61883-1 plug
+ * mechanism, you can specify an output plug to connect to.  The
+ * driver will pick up the channel number from the plug once the
+ * destination device locks the output plug control register.  In this
+ * case set the plug field and use the AMDTP_IOC_PLUG ioctl.
+ *
+ * Having configured the interface, the driver now accepts writes of
+ * regular 16 bit signed little endian samples, with the channels
+ * interleaved.  For example, 4 channels would look like:
+ *
+ *   | sample 0                                      | sample 1    ...
+ *   | ch. 0     | ch. 1     | ch. 2     | ch. 3     | ch. 0     | ...
+ *   | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ...
+ *
+ */
+
+/* We use '#' for our ioctl magic number because it's cool. */
+
+#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl))
+#define AMDTP_IOC_PLUG    _IOW('#', 1, sizeof (struct amdtp_ioctl))
+#define AMDTP_IOC_PING    _IOW('#', 2, sizeof (struct amdtp_ioctl))
+#define AMDTP_IOC_ZAP     _IO('#', 3)
+
+enum {
+	AMDTP_FORMAT_RAW,
+	AMDTP_FORMAT_IEC958_PCM,
+	AMDTP_FORMAT_IEC958_AC3
+};
+
+enum {
+	AMDTP_RATE_32KHZ,
+	AMDTP_RATE_44K1HZ,
+	AMDTP_RATE_48KHZ,
+};
+
+struct amdtp_ioctl {
+	__u32 format;
+	__u32 rate;
+	__u32 dimension;
+	union { __u32 channel; __u32 plug; } u;
+};
+
+#endif /* __AMDTP_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/cmp.c linux-2.4.19-pre5/drivers/ieee1394/cmp.c
--- linux-2.4.19-pre4/drivers/ieee1394/cmp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/cmp.c	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,348 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * cmp.c - Connection Management Procedures
+ * Copyright (C) 2001 Kristian Høgsberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* TODO
+ * ----
+ *
+ * - Implement IEC61883-1 output plugs and connection management.
+ *   This should probably be part of the general subsystem, as it could
+ *   be shared with dv1394.
+ *
+ * - Add IEC61883 unit directory when loading this module.  This
+ *   requires a run-time changeable config rom.
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include "hosts.h"
+#include "highlevel.h"
+#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "cmp.h"
+
+struct plug {
+	union {
+		struct cmp_pcr pcr;
+		quadlet_t quadlet;
+	} u;
+	void (*update)(struct cmp_pcr *plug, void *data);
+	void *data;
+};
+
+struct cmp_host {
+	struct hpsb_host *host;
+
+	union {
+		struct cmp_mpr ompr;
+		quadlet_t ompr_quadlet;
+	} u;
+	struct plug opcr[2];
+
+	union {
+		struct cmp_mpr impr;
+		quadlet_t impr_quadlet;
+	} v;
+	struct plug ipcr[2];
+
+	struct list_head link;
+};
+
+enum {
+	CMP_P2P_CONNECTION,
+	CMP_BC_CONNECTION
+};
+
+#define CSR_PCR_MAP      0x900
+#define CSR_PCR_MAP_END  0x9fc
+
+static struct hpsb_highlevel *cmp_highlevel;
+
+static LIST_HEAD(host_list);
+static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
+
+static struct cmp_host *
+lookup_cmp_host(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+	struct list_head *lh;
+	unsigned long flags;
+
+	ch = NULL;
+	spin_lock_irqsave(&host_list_lock, flags);
+	list_for_each(lh, &host_list) {
+		ch = list_entry(lh, struct cmp_host, link);
+		if (ch->host == host)
+			break;
+	}
+	spin_unlock_irqrestore(&host_list_lock, flags);
+
+	if (lh == &host_list)
+		return NULL;
+	else
+		return ch;
+}
+
+struct cmp_pcr *
+cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
+		  void (*update)(struct cmp_pcr *pcr, void *data),
+		  void *data)
+{
+	struct cmp_host *ch;
+	struct plug *plug;
+
+	ch = lookup_cmp_host(host);
+
+	if (opcr_number >= ch->u.ompr.nplugs ||
+	    ch->opcr[opcr_number].update != NULL)
+		return NULL;
+
+	plug = &ch->opcr[opcr_number];
+	plug->u.pcr.online = 1;
+	plug->u.pcr.bcast_count = 0;
+	plug->u.pcr.p2p_count = 0;
+	plug->u.pcr.overhead = 0;
+	plug->u.pcr.payload = payload;
+	plug->update = update;
+	plug->data = data;
+
+	return &plug->u.pcr;
+}
+
+void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
+{
+	struct cmp_host *ch;
+	struct plug *plug;
+
+	ch = lookup_cmp_host(host);
+	plug = (struct plug *)opcr;
+	if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
+
+	plug->u.pcr.online = 0;
+	plug->update = NULL;
+}
+
+static void reset_plugs(struct cmp_host *ch)
+{
+	int i;
+
+	ch->u.ompr.non_persistent_ext = 0xff;
+	for (i = 0; i < ch->u.ompr.nplugs; i++) {
+		ch->opcr[i].u.pcr.bcast_count = 0;
+		ch->opcr[i].u.pcr.p2p_count = 0;
+		ch->opcr[i].u.pcr.overhead = 0;
+	}
+}
+
+static void cmp_add_host(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+
+	ch = kmalloc(sizeof *ch, SLAB_KERNEL);
+	if (ch == NULL) {
+		HPSB_ERR("Failed to allocate cmp_host");
+		return;
+	}
+	memset(ch, 0, sizeof *ch);
+	ch->host = host;
+	ch->u.ompr.rate = SPEED_100;
+	ch->u.ompr.bcast_channel_base = 63;
+	ch->u.ompr.nplugs = 2;
+	reset_plugs(ch);
+
+	spin_lock_irq(&host_list_lock);
+	list_add_tail(&ch->link, &host_list);
+	spin_unlock_irq(&host_list_lock);
+}
+
+static void cmp_host_reset(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+
+	ch = lookup_cmp_host(host);
+	if (ch == NULL) BUG();
+	reset_plugs(ch);
+}
+
+static void cmp_remove_host(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+
+	ch = lookup_cmp_host(host);
+	if (ch == NULL) BUG();
+
+	spin_lock_irq(&host_list_lock);
+	list_del(&ch->link);
+	spin_unlock_irq(&host_list_lock);
+
+	kfree(ch);
+}
+
+static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
+		    u64 addr, unsigned int length)
+{
+	int csraddr = addr - CSR_REGISTER_BASE;
+	int plug;
+	struct cmp_host *ch;
+	
+	if (length != 4)
+		return RCODE_TYPE_ERROR;
+
+	ch = lookup_cmp_host(host);
+	if (csraddr == 0x900) {
+		*buf = cpu_to_be32(ch->u.ompr_quadlet);
+		return RCODE_COMPLETE;   
+	}
+	else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
+		plug = (csraddr - 0x904) / 4;
+		*buf = cpu_to_be32(ch->opcr[plug].u.quadlet);
+		return RCODE_COMPLETE;
+	}
+	else if (csraddr < 0x980) {
+		return RCODE_ADDRESS_ERROR;
+	}
+	else if (csraddr == 0x980) {
+		*buf = cpu_to_be32(ch->v.impr_quadlet);
+		return RCODE_COMPLETE;   
+	}
+	else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
+		plug = (csraddr - 0x984) / 4;
+		*buf = cpu_to_be32(ch->ipcr[plug].u.quadlet);
+		return RCODE_COMPLETE;
+	}
+	else
+		return RCODE_ADDRESS_ERROR;
+}
+
+static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+{
+	int csraddr = addr - CSR_REGISTER_BASE;
+	int plug;
+	struct cmp_host *ch;
+
+	ch = lookup_cmp_host(host);
+	
+	if (extcode != EXTCODE_COMPARE_SWAP) 
+		return RCODE_TYPE_ERROR;
+	
+	if (csraddr == 0x900) {
+		/* FIXME: Ignore writes to bits 30-31 and 0-7 */
+		*store = cpu_to_be32(ch->u.ompr_quadlet);
+		if (arg == cpu_to_be32(ch->u.ompr_quadlet))
+			ch->u.ompr_quadlet = be32_to_cpu(data);
+
+		return RCODE_COMPLETE;
+	}
+	if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
+		plug = (csraddr - 0x904) / 4;
+		*store = cpu_to_be32(ch->opcr[plug].u.quadlet);
+
+		if (arg == *store)
+			ch->opcr[plug].u.quadlet = be32_to_cpu(data);
+
+		if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet &&
+		    ch->opcr[plug].update != NULL)
+			ch->opcr[plug].update(&ch->opcr[plug].u.pcr,
+					      ch->opcr[plug].data);
+
+		return RCODE_COMPLETE;
+	}
+	else if (csraddr < 0x980) {
+		return RCODE_ADDRESS_ERROR;
+	}
+	else if (csraddr == 0x980) {
+		/* FIXME: Ignore writes to bits 24-31 and 0-7 */
+		*store = cpu_to_be32(ch->u.ompr_quadlet);
+		if (arg == cpu_to_be32(ch->u.ompr_quadlet))
+			ch->u.ompr_quadlet = be32_to_cpu(data);
+
+		return RCODE_COMPLETE;
+	}
+	else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
+		plug = (csraddr - 0x984) / 4;
+		*store = cpu_to_be32(ch->ipcr[plug].u.quadlet);
+
+		if (arg == *store)
+			ch->ipcr[plug].u.quadlet = be32_to_cpu(data);
+
+		if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet &&
+		    ch->ipcr[plug].update != NULL)
+			ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr,
+					      ch->ipcr[plug].data);
+
+		return RCODE_COMPLETE;
+	}
+	else
+		return RCODE_ADDRESS_ERROR;
+}
+
+
+static struct hpsb_highlevel_ops cmp_highlevel_ops = {
+	add_host:	cmp_add_host,
+	remove_host:	cmp_remove_host,
+        host_reset:	cmp_host_reset,
+};
+
+static struct hpsb_address_ops pcr_ops = {
+        read: pcr_read,
+        lock: pcr_lock,
+};
+
+/* Module interface */
+
+MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
+MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
+MODULE_SUPPORTED_DEVICE("cmp");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cmp_register_opcr);
+EXPORT_SYMBOL(cmp_unregister_opcr);
+
+static int __init cmp_init_module (void)
+{
+	cmp_highlevel = hpsb_register_highlevel ("cmp",
+						 &cmp_highlevel_ops);
+	if (cmp_highlevel == NULL) {
+		HPSB_ERR("cmp: unable to register highlevel ops");
+		return -EIO;
+	}
+
+	hpsb_register_addrspace(cmp_highlevel, &pcr_ops,
+				CSR_REGISTER_BASE + CSR_PCR_MAP,
+				CSR_REGISTER_BASE + CSR_PCR_MAP_END);
+
+	HPSB_INFO("Loaded CMP driver");
+
+	return 0;
+}
+
+static void __exit cmp_exit_module (void)
+{
+        hpsb_unregister_highlevel(cmp_highlevel);
+
+	HPSB_INFO("Unloaded CMP driver");
+}
+
+module_init(cmp_init_module);
+module_exit(cmp_exit_module);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/cmp.h linux-2.4.19-pre5/drivers/ieee1394/cmp.h
--- linux-2.4.19-pre4/drivers/ieee1394/cmp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/cmp.h	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,31 @@
+#ifndef __CMP_H
+#define __CMP_H
+
+struct cmp_mpr {
+	u32 nplugs:5;
+	u32 reserved:3;
+	u32 persistent_ext:8;
+	u32 non_persistent_ext:8;
+	u32 bcast_channel_base:6;
+	u32 rate:2;
+} __attribute__((packed));
+
+struct cmp_pcr {
+	u32 payload:10;
+	u32 overhead:4;
+	u32 speed:2;
+	u32 channel:6;
+	u32 reserved:2;
+	u32 p2p_count:6;
+	u32 bcast_count:1;
+	u32 online:1;
+} __attribute__((packed));
+
+struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug,
+				  int payload,
+				  void (*update)(struct cmp_pcr *plug,
+						 void *data),
+				  void *data);
+void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug);
+
+#endif /* __CMP_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/csr.c linux-2.4.19-pre5/drivers/ieee1394/csr.c
--- linux-2.4.19-pre4/drivers/ieee1394/csr.c	Thu Jul 19 17:48:15 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/csr.c	Fri Mar 29 14:49:31 2002
@@ -70,7 +70,7 @@
 {
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
-        host->csr.rom_size = host->template->get_rom(host, &host->csr.rom);
+        host->csr.rom_size = host->ops->get_rom(host, &host->csr.rom);
 
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
@@ -152,7 +152,7 @@
         case CSR_CYCLE_TIME:
                 oldcycle = host->csr.cycle_time;
                 host->csr.cycle_time =
-                        host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+                        host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
 
                 if (oldcycle > host->csr.cycle_time) {
                         /* cycle time wrapped around */
@@ -163,7 +163,7 @@
         case CSR_BUS_TIME:
                 oldcycle = host->csr.cycle_time;
                 host->csr.cycle_time =
-                        host->template->devctl(host, GET_CYCLE_COUNTER, 0);
+                        host->ops->devctl(host, GET_CYCLE_COUNTER, 0);
 
                 if (oldcycle > host->csr.cycle_time) {
                         /* cycle time wrapped around */
@@ -181,32 +181,32 @@
                 return RCODE_ADDRESS_ERROR;
 
         case CSR_BUS_MANAGER_ID:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 0, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 0, 0, 0);
                 else
                         ret = host->csr.bus_manager_id;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_BANDWIDTH_AVAILABLE:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 1, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 1, 0, 0);
                 else
                         ret = host->csr.bandwidth_available;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_CHANNELS_AVAILABLE_HI:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 2, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 2, 0, 0);
                 else
                         ret = host->csr.channels_available_hi;
 
                 *(buf++) = cpu_to_be32(ret);
                 out;
         case CSR_CHANNELS_AVAILABLE_LO:
-                if (host->template->hw_csr_reg)
-                        ret = host->template->hw_csr_reg(host, 3, 0, 0);
+                if (host->ops->hw_csr_reg)
+                        ret = host->ops->hw_csr_reg(host, 3, 0, 0);
                 else
                         ret = host->csr.channels_available_lo;
 
@@ -244,7 +244,7 @@
                 host->csr.node_ids &= NODE_MASK << 16;
                 host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
                 host->node_id = host->csr.node_ids >> 16;
-                host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
+                host->ops->devctl(host, SET_BUS_ID, host->node_id >> 6);
                 out;
 
         case CSR_RESET_START:
@@ -269,7 +269,7 @@
         case CSR_CYCLE_TIME:
                 /* should only be set by cycle start packet, automatically */
                 host->csr.cycle_time = be32_to_cpu(*data);
-                host->template->devctl(host, SET_CYCLE_COUNTER,
+                host->ops->devctl(host, SET_CYCLE_COUNTER,
                                        be32_to_cpu(*(data++)));
                 out;
         case CSR_BUS_TIME:
@@ -318,10 +318,10 @@
         data = be32_to_cpu(data);
         arg = be32_to_cpu(arg);
 
-        if (host->template->hw_csr_reg) {
+        if (host->ops->hw_csr_reg) {
                 quadlet_t old;
 
-                old = host->template->
+                old = host->ops->
                         hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
                                    data, arg);
 
diff -urN linux-2.4.19-pre4/drivers/ieee1394/dv1394-private.h linux-2.4.19-pre5/drivers/ieee1394/dv1394-private.h
--- linux-2.4.19-pre4/drivers/ieee1394/dv1394-private.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/dv1394-private.h	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,611 @@
+/*
+ * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
+ *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ *     receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ *   video1394.h - driver for OHCI 1394 boards
+ *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_1394_PRIVATE_H
+#define _DV_1394_PRIVATE_H
+
+#include "ieee1394.h"
+#include <linux/pci.h>
+#include <asm/scatterlist.h>
+
+/* data structures private to the dv1394 driver */
+/* none of this is exposed to user-space */
+
+
+/* 
+   the 8-byte CIP (Common Isochronous Packet) header that precedes
+   each packet of DV data.
+
+   See the IEC 61883 standard. 
+*/
+
+struct CIP_header { unsigned char b[8]; };
+
+static inline void fill_cip_header(struct CIP_header *cip,
+				   unsigned char source_node_id,
+				   unsigned long counter,
+				   enum pal_or_ntsc format,
+				   unsigned long timestamp)
+{
+	cip->b[0] = source_node_id;
+	cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
+	cip->b[2] = 0x00;
+	cip->b[3] = counter;
+
+	cip->b[4] = 0x80; /* const */
+
+	switch(format) {
+	case DV1394_PAL:
+		cip->b[5] = 0x80;
+		break;
+	case DV1394_NTSC:
+		cip->b[5] = 0x00;
+		break;
+	}
+
+	cip->b[6] = timestamp >> 8;
+	cip->b[7] = timestamp & 0xFF;
+}
+
+
+
+/* 
+   DMA commands used to program the OHCI's DMA engine
+
+   See the Texas Instruments OHCI 1394 chipset documentation. 
+*/
+
+struct output_more_immediate { u32 q[8]; };
+struct output_more { u32 q[4]; };
+struct output_last { u32 q[4]; };
+struct input_more { u32 q[4]; };
+struct input_last { u32 q[4]; };
+
+/* outputs */
+
+static inline void fill_output_more_immediate(struct output_more_immediate *omi,
+					      unsigned char tag,
+					      unsigned char channel,
+					      unsigned char sync_tag,
+					      unsigned int  payload_size)
+{
+	omi->q[0] = 0x02000000 | 8 ; /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
+	omi->q[1] = 0;
+	omi->q[2] = 0;
+	omi->q[3] = 0;
+	
+	/* IT packet header */
+	omi->q[4] = (0x0 << 16)  /* DMA_SPEED_100 */
+			| (tag << 14)
+			| (channel << 8)
+			| (TCODE_ISO_DATA << 4) 
+			| (sync_tag);
+
+	omi->q[5] = payload_size << 16;
+	omi->q[5] |= (0x7F << 8) | 0xA0; /* reserved field; mimic behavior of my Sony DSR-40 */
+	
+	omi->q[6] = 0;
+	omi->q[7] = 0;
+}
+
+static inline void fill_output_more(struct output_more *om,
+				    unsigned int data_size,
+				    unsigned long data_phys_addr)
+{
+	om->q[0] = 0; /* OUTPUT_MORE */
+	om->q[0] |= data_size;
+
+	om->q[1] = data_phys_addr;
+	om->q[2] = 0;
+	om->q[3] = 0;
+}
+
+static inline void fill_output_last(struct output_last *ol,
+				    int want_timestamp,
+				    int want_interrupt,
+				    unsigned int data_size,
+				    unsigned long data_phys_addr)
+{
+	ol->q[0] = 0;
+	ol->q[0] |= 1 << 28; /* OUTPUT_LAST */
+
+	if(want_timestamp) /* controller will update timestamp at DMA time */
+		ol->q[0] |= 1 << 27;
+
+	if(want_interrupt)
+		ol->q[0] |= 3 << 20;
+
+	ol->q[0] |= 3 << 18; /* must take branch */
+	ol->q[0] |= data_size;
+	
+	ol->q[1] = data_phys_addr;
+	ol->q[2] = 0;
+	ol->q[3] = 0;
+}
+
+/* inputs */
+
+static inline void fill_input_more(struct input_more *im,
+				   int want_interrupt,
+				   unsigned int data_size,
+				   unsigned long data_phys_addr)
+{
+	im->q[0] =  2 << 28; /* INPUT_MORE */
+	im->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+	if (want_interrupt)
+		im->q[0] |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
+	im->q[0] |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
+	                       /* disable wait on sync field, not used in DV :-( */
+       	im->q[0] |= data_size;
+
+	im->q[1] = data_phys_addr;
+	im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */
+	im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */
+}
+ 
+static inline void fill_input_last(struct input_last *il,
+				    unsigned int data_size,
+				    unsigned long data_phys_addr)
+{
+	il->q[0] =  3 << 28; /* INPUT_LAST */
+	il->q[0] |= 8 << 24; /* s = 1, update xferStatus and resCount */
+	il->q[0] |= 3 << 20; /* enable interrupts */
+	il->q[0] |= 0xC << 16; /* enable branch to address */
+	                       /* disable wait on sync field, not used in DV :-( */
+	il->q[0] |= data_size;
+
+	il->q[1] = data_phys_addr;
+	il->q[2] = 1; /* branchAddress (filled in later) and Z = 1 descriptor in next block */
+	il->q[3] = data_size; /* xferStatus & resCount, resCount must be initialize to data_size */
+}
+
+
+
+/* 
+   A "DMA descriptor block" consists of several contiguous DMA commands.
+   struct DMA_descriptor_block encapsulates all of the commands necessary 
+   to send one packet of DV data. 
+   
+   There are three different types of these blocks:
+
+        1) command to send an empty packet (CIP header only, no DV data):
+
+	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
+	    OUTPUT_LAST           <-- points to the CIP header
+
+	2) command to send a full packet when the DV data payload does NOT
+	   cross a page boundary:
+
+	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
+	    OUTPUT_MORE           <-- points to the CIP header
+	    OUTPUT_LAST           <-- points to entire DV data payload
+
+	3) command to send a full packet when the DV payload DOES cross
+	   a page boundary:
+
+	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
+	    OUTPUT_MORE           <-- points to the CIP header
+	    OUTPUT_MORE           <-- points to first part of DV data payload
+	    OUTPUT_LAST           <-- points to second part of DV data payload
+
+   This struct describes all three block types using unions.
+
+   !!! It is vital that an even number of these descriptor blocks fit on one
+   page of memory, since a block cannot cross a page boundary !!!
+
+ */
+
+struct DMA_descriptor_block {
+
+	union {
+		struct {
+			/*  iso header, common to all output block types */
+			struct output_more_immediate omi; 
+			
+			union {
+				/* empty packet */
+				struct {
+					struct output_last ol;  /* CIP header */
+				} empty;
+			
+				/* full packet */
+				struct {
+					struct output_more om;  /* CIP header */
+					
+					union {
+				               /* payload does not cross page boundary */
+						struct {
+							struct output_last ol;  /* data payload */
+						} nocross;
+						
+				               /* payload crosses page boundary */
+						struct {
+							struct output_more om;  /* data payload */
+							struct output_last ol;  /* data payload */
+						} cross;
+					} u;
+					
+				} full;
+			} u;
+		} out;
+
+		struct {
+			struct input_last il; 
+		} in;
+
+	} u;
+
+	/* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0 
+	   by padding out to 128 bytes */
+	u32 __pad__[12]; 
+};
+
+
+/* struct frame contains all data associated with one frame in the
+   ringbuffer these are allocated when the DMA context is initialized
+   do_dv1394_init().  They are re-used after the card finishes
+   transmitting the frame. */
+
+struct video_card; /* forward declaration */
+
+struct frame {
+
+	/* points to the struct video_card that owns this frame */
+	struct video_card *video;
+
+	/* index of this frame in video_card->frames[] */
+	unsigned int frame_num;
+
+	/* FRAME_CLEAR - DMA program not set up, waiting for data 
+	   FRAME_READY - DMA program written, ready to transmit
+
+	   Changes to these should be locked against the interrupt
+	*/
+	enum {
+		FRAME_CLEAR = 0,
+		FRAME_READY
+	} state;
+	
+	/* whether this frame has been DMA'ed already; used only from
+	   the IRQ handler to determine whether the frame can be reset */
+	int done;
+
+
+	/* kernel virtual pointer to the start of this frame's data in
+	   the user ringbuffer. Use only for CPU access; to get the DMA
+	   bus address you must go through the video->user_dma mapping */
+	unsigned long data; 
+
+	/* Max # of packets per frame */
+        #define MAX_PACKETS 320
+
+
+	/* a PAGE_SIZE memory pool for allocating CIP headers
+	   !header_pool must be aligned to PAGE_SIZE! */
+	struct CIP_header *header_pool;
+	dma_addr_t         header_pool_dma;
+
+	
+	/* a physically contiguous memory pool for allocating DMA
+	   descriptor blocks; usually around 64KB in size
+	   !descriptor_pool must be aligned to PAGE_SIZE! */
+	struct DMA_descriptor_block *descriptor_pool;
+	dma_addr_t                   descriptor_pool_dma;
+	unsigned long                descriptor_pool_size;
+
+
+	/* # of packets allocated for this frame */
+	unsigned int n_packets;
+
+
+	/* below are several pointers (kernel virtual addresses, not
+	   DMA bus addresses) to parts of the DMA program.  These are
+	   set each time the DMA program is written in
+	   frame_prepare(). They are used later on, e.g. from the
+	   interrupt handler, to check the status of the frame */
+
+	/* points to status/timestamp field of first DMA packet */
+	/* (we'll check it later to monitor timestamp accuracy) */
+	u32 *frame_begin_timestamp;
+
+	/* the timestamp we assigned to the first packet in the frame */
+	u32 assigned_timestamp;
+
+	/* pointer to the first packet's CIP header (where the timestamp goes) */
+	struct CIP_header *cip_syt1;
+	
+	/* pointer to the second packet's CIP header
+	   (only set if the first packet was empty) */
+	struct CIP_header *cip_syt2;
+
+	/* in order to figure out what caused an interrupt,
+	   store pointers to the status fields of the two packets
+	   that can cause interrupts. We'll check these from the
+	   interrupt handler.
+	*/
+	u32 *mid_frame_timestamp;
+	u32 *frame_end_timestamp;
+
+	/* branch address field of final packet. This is effectively
+	   the "tail" in the chain of DMA descriptor blocks.
+	   We will fill it with the address of the first DMA descriptor
+	   block in the subsequent frame, once it is ready.
+	*/
+	u32 *frame_end_branch;
+
+	/* the number of descriptors in the first descriptor block
+	   of the frame. Needed to start DMA */
+	int first_n_descriptors;
+};
+
+
+struct packet {
+	u16	timestamp;
+	u16	invalid;
+	u16	iso_header;
+	u16	data_length;
+	u32	cip_h1;
+	u32	cip_h2;
+	unsigned char data[480];
+	unsigned char padding[16]; /* force struct size =512 for page alignment */
+};
+
+
+/* allocate/free a frame */
+static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
+static void frame_delete(struct frame *f);
+
+/* reset f so that it can be used again */
+static void frame_reset(struct frame *f);
+
+
+/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */
+
+struct dma_region {
+	unsigned int n_pages;
+	unsigned int n_dma_pages;
+	struct scatterlist *sglist;
+};
+
+/* return the DMA bus address of the byte with the given offset
+   relative to the beginning of the dma_region */
+
+static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset)
+{
+	int i;
+	struct scatterlist *sg;
+	
+	for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) {
+		if(offset < sg_dma_len(sg)) {
+			return sg_dma_address(sg) + offset;
+		} 
+		offset -= sg_dma_len(sg);
+	}
+	
+	printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset);
+	return 0;
+}
+
+
+/* struct video_card contains all data associated with one instance
+   of the dv1394 driver 
+*/
+enum modes {
+	MODE_RECEIVE,
+	MODE_TRANSMIT
+};
+
+struct video_card {
+
+	/* ohci card to which this instance corresponds */
+	struct ti_ohci *ohci;
+
+	/* OHCI card id; the link between the VFS inode and a specific video_card
+	   (essentially the device minor number) */
+	int id;
+
+	/* entry in dv1394_cards */
+	struct list_head list;
+
+	/* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */
+	devfs_handle_t devfs_handle;
+
+	/* OHCI card IT DMA context number, -1 if not in use */
+	int ohci_it_ctx;
+
+	/* register offsets for current IT DMA context, 0 if not in use */
+	u32 ohci_IsoXmitContextControlSet;
+	u32 ohci_IsoXmitContextControlClear;
+	u32 ohci_IsoXmitCommandPtr;
+	
+	/* OHCI card IR DMA context number, -1 if not in use */
+	int ohci_ir_ctx;
+
+	/* register offsets for current IR DMA context, 0 if not in use */
+	u32 ohci_IsoRcvContextControlSet;
+	u32 ohci_IsoRcvContextControlClear;
+	u32 ohci_IsoRcvCommandPtr;
+	u32 ohci_IsoRcvContextMatch;
+	
+	
+	/* CONCURRENCY CONTROL */
+	
+	/* there are THREE levels of locking associated with video_card. */
+
+	/*
+	   1) the 'open' flag - this prevents more than one process from
+	   opening the device. (the driver currently assumes only one opener).
+	   This is a regular int, but use test_and_set_bit() (on bit zero) 
+	   for atomicity.
+	 */
+	int open;
+
+	/* 
+	   2) the spinlock - this provides mutual exclusion between the interrupt
+	   handler and process-context operations. Generally you must take the
+	   spinlock under the following conditions:
+	     1) DMA (and hence the interrupt handler) may be running
+	     AND
+	     2) you need to operate on the video_card, especially active_frame
+
+	     It is OK to play with video_card without taking the spinlock if
+	     you are certain that DMA is not running. Even if DMA is running,
+	     it is OK to *read* active_frame with the lock, then drop it
+	     immediately. This is safe because the interrupt handler will never
+	     advance active_frame onto a frame that is not READY (and the spinlock
+	     must be held while marking a frame READY).
+	 */
+	spinlock_t spinlock;
+
+	/*
+	  3) the sleeping semaphore 'sem' - this is used from process context only,
+	  to serialize various operations on the video_card. Even though only one
+	  open() is allowed, we still need to prevent multiple threads of execution
+	  from entering calls like read, write, ioctl, etc.
+
+	  I honestly can't think of a good reason to use dv1394 from several threads
+	  at once, but we need to serialize anyway to prevent oopses =).
+
+	  NOTE: if you need both spinlock and sem, take sem first to avoid deadlock!
+	 */
+	struct semaphore sem;
+
+	/* people waiting for buffer space, please form a line here... */
+	wait_queue_head_t waitq;
+
+	/* support asynchronous I/O signals (SIGIO) */
+	struct fasync_struct *fasync;
+	
+	/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
+           data, exposed to user-space via mmap() */
+	unsigned char     *user_buf;
+	unsigned long      user_buf_size;
+	struct dma_region  user_dma;
+	
+	/* next byte in the ringbuffer that a write() call will fill */
+	size_t write_off;
+
+	struct frame *frames[DV1394_MAX_FRAMES];
+	
+	/* n_frames also serves as an indicator that this struct video_card is
+	   intialized and ready to run DMA buffers */
+
+	int n_frames;
+
+	/* this is the frame that is currently "owned" by the OHCI DMA controller
+	   (set to -1 iff DMA is not running) 
+
+	   ! must lock against the interrupt handler when accessing it !
+
+	   RULES:
+
+	       Only the interrupt handler may change active_frame if DMA
+	          is running; if not, process may change it
+
+	       If the next frame is READY, the interrupt handler will advance
+	       active_frame when the current frame is finished.
+
+	       If the next frame is CLEAR, the interrupt handler will re-transmit
+	       the current frame, and the dropped_frames counter will be  incremented.
+
+	       The interrupt handler will NEVER advance active_frame to a
+	       frame that is not READY.
+	       
+	*/
+	int active_frame;
+	int first_run;
+
+	/* the same locking rules apply to these three fields also: */
+
+	/* altered ONLY from process context. Must check first_clear_frame->state;
+	   if it's READY, that means the ringbuffer is full with READY frames;
+	   if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
+	unsigned int first_clear_frame; 
+
+	/* altered both by process and interrupt */
+	unsigned int n_clear_frames;   
+
+	/* only altered by the interrupt */
+	unsigned int dropped_frames;
+
+
+
+	/* the CIP accumulator and continuity counter are properties
+	   of the DMA stream as a whole (not a single frame), so they
+	   are stored here in the video_card */
+
+	unsigned long cip_accum;
+	unsigned long cip_n, cip_d;
+	unsigned int syt_offset;
+	unsigned int continuity_counter;
+
+	enum pal_or_ntsc pal_or_ntsc;
+
+	/* redundant, but simplifies the code somewhat */
+	unsigned int frame_size; /* in bytes */
+
+	/* the isochronous channel to use, -1 if video card is inactive */
+	int channel;
+
+	
+	/* physically contiguous packet ringbuffer for receive */
+#define MAX_PACKET_BUFFER 30
+	struct packet *packet_buffer;
+	dma_addr_t     packet_buffer_dma;
+	unsigned long  packet_buffer_size;
+	
+	unsigned int current_packet;
+	int first_frame; 	/* received first start frame marker? */
+	enum modes mode;
+};
+
+/* 
+   if the video_card is not initialized, then the ONLY fields that are valid are:
+   ohci
+   open
+   n_frames
+*/
+
+static inline int video_card_initialized(struct video_card *v)
+{
+	return v->n_frames > 0;
+}
+
+static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
+static int do_dv1394_init_default(struct video_card *video);
+static int do_dv1394_shutdown(struct video_card *video, int free_user_buf);
+
+
+/* NTSC empty packet rate accurate to within 0.01%, 
+   calibrated against a Sony DSR-40 DVCAM deck */
+
+#define CIP_N_NTSC   68000000
+#define CIP_D_NTSC 1000000000
+
+#define CIP_N_PAL  1
+#define CIP_D_PAL 16
+
+#endif /* _DV_1394_PRIVATE_H */
+
diff -urN linux-2.4.19-pre4/drivers/ieee1394/dv1394.c linux-2.4.19-pre5/drivers/ieee1394/dv1394.c
--- linux-2.4.19-pre4/drivers/ieee1394/dv1394.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/dv1394.c	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,3002 @@
+/*
+ * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
+ *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ *     receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ *  video1394.c - video driver for OHCI 1394 boards
+ *  Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+  OVERVIEW
+
+  I designed dv1394 as a "pipe" that you can use to shoot DV onto a
+  FireWire bus. In transmission mode, dv1394 does the following:
+
+   1. accepts contiguous frames of DV data from user-space, via write()
+      or mmap() (see dv1394.h for the complete API)
+   2. wraps IEC 61883 packets around the DV data, inserting
+      empty synchronization packets as necessary
+   3. assigns accurate SYT timestamps to the outgoing packets
+   4. shoots them out using the OHCI card's IT DMA engine
+
+   Thanks to Dan Dennedy, we now have a receive mode that does the following:
+
+   1. accepts raw IEC 61883 packets from the OHCI card
+   2. re-assembles the DV data payloads into contiguous frames,
+      discarding empty packets
+   3. sends the DV data to user-space via read() or mmap()
+*/
+
+/*
+  TODO:
+
+  - tunable frame-drop behavior: either loop last frame, or halt transmission
+  
+  - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
+    so that we don't rely on allocating 64KB of contiguous kernel memory
+    via pci_alloc_consistent()
+    
+  DONE:
+  - safely obtain and release ISO Tx channels in cooperation with OHCI driver
+  - map received DIF blocks to their proper location in DV frame (ensure
+    recovery if dropped packet)
+  - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
+  - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
+  - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
+  - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
+  - set video->id correctly
+  - store video_cards in an array indexed by OHCI card ID, rather than a list
+  - implement DMA context allocation to cooperate with other users of the OHCI
+  - fix all XXX showstoppers
+  - disable IR/IT DMA interrupts on shutdown
+  - flush pci writes to the card by issuing a read
+  - devfs and character device dispatching (* needs testing with Linux 2.2.x)
+  - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
+  - keep all video_cards in a list (for open() via chardev), set file->private_data = video
+  - dv1394_poll should indicate POLLIN when receiving buffers are available
+  - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
+  - expose xmit and recv as separate devices (not exclusive)
+  - expose NTSC and PAL as separate devices (can be overridden)
+  - read/edit channel in procfs
+
+*/
+     
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "highlevel.h"	
+#include "dv1394.h"
+#include "dv1394-private.h"
+
+#include "ohci1394.h"
+
+#ifndef virt_to_page
+#define virt_to_page(x) MAP_NR(x)
+#endif
+
+#ifndef vmalloc_32
+#define vmalloc_32(x) vmalloc(x)
+#endif
+
+
+/* DEBUG LEVELS:
+   0 - no debugging messages
+   1 - some debugging messages, but none during DMA frame transmission
+   2 - lots of messages, including during DMA frame transmission
+       (will cause undeflows if your machine is too slow!)
+*/
+
+#define DV1394_DEBUG_LEVEL 0
+
+/* for debugging use ONLY: allow more than one open() of the device */
+/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
+
+#if DV1394_DEBUG_LEVEL >= 2
+#define irq_printk( args... ) printk( args )
+#else
+#define irq_printk( args... )
+#endif
+
+#if DV1394_DEBUG_LEVEL >= 1
+#define debug_printk( args... ) printk( args)
+#else
+#define debug_printk( args... )
+#endif
+
+/* issue a dummy PCI read to force the preceding write
+   to be posted to the PCI bus immediately */
+
+static inline void flush_pci_write(struct ti_ohci *ohci)
+{
+	mb();
+	reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+}
+
+static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
+			quadlet_t isoXmitIntEvent, void *data);
+
+
+/* GLOBAL DATA */
+
+/* list of all video_cards */
+static LIST_HEAD(dv1394_cards);
+static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
+
+static struct hpsb_highlevel *hl_handle; /* = NULL; */
+
+static LIST_HEAD(dv1394_devfs);
+struct dv1394_devfs_entry {
+	struct list_head list;
+    devfs_handle_t devfs;
+	char name[32];
+	struct dv1394_devfs_entry *parent;
+};
+static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED;
+
+/* translate from a struct file* to the corresponding struct video_card* */
+
+static inline struct video_card* file_to_video_card(struct file *file)
+{
+	return (struct video_card*) file->private_data;
+}
+
+
+/* Taken from bttv.c */
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr)
+{
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+	struct page *ret = NULL;
+	
+	if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte))
+				ret = pte_page(pte);
+                }
+        }
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved, and for
+ * handling page faults on the rvmalloc()ed buffer
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
+{
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+	kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+        return ret;
+}
+
+static void * rvmalloc(unsigned long size)
+{
+	void * mem;
+	unsigned long adr, page;
+        
+	mem=vmalloc_32(size);
+	if (mem) {
+		memset(mem, 0, size); /* Clear the ram out, 
+					 no junk to the user */
+	        adr=(unsigned long) mem;
+		while (size > 0) {
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+        unsigned long adr, page;
+        
+	if (mem) {
+	        adr=(unsigned long) mem;
+		while (size > 0) {
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/***********************************/
+/* END Memory management functions */
+/***********************************/
+
+
+/*** FRAME METHODS *********************************************************/
+
+static void frame_reset(struct frame *f)
+{
+	f->state = FRAME_CLEAR;
+	f->done = 0;
+	f->n_packets = 0;
+	f->frame_begin_timestamp = NULL;
+	f->assigned_timestamp = 0;
+	f->cip_syt1 = NULL;
+	f->cip_syt2 = NULL;
+	f->mid_frame_timestamp = NULL;
+	f->frame_end_timestamp = NULL;
+	f->frame_end_branch = NULL;
+}
+
+static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
+{
+	struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
+	if(!f)
+		return NULL;
+
+	f->video = video;
+	f->frame_num = frame_num;
+
+	f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
+	if(!f->header_pool) {
+		printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
+		kfree(f);
+		return NULL;
+	}
+
+	debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
+		     (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
+	
+	f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
+	/* make it an even # of pages */
+	f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
+
+	f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
+						  f->descriptor_pool_size,
+						  &f->descriptor_pool_dma);
+	if(!f->descriptor_pool) {
+		pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
+		kfree(f);
+		return NULL;
+	}
+	
+	debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
+		     (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
+	
+	f->data = 0;
+	frame_reset(f);
+
+	return f;
+}
+
+static void frame_delete(struct frame *f)
+{
+	pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
+	pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
+	kfree(f);
+}
+
+
+
+
+/* 
+   frame_prepare() - build the DMA program for transmitting
+   
+   Frame_prepare() must be called OUTSIDE the video->spinlock.
+   However, frame_prepare() must still be serialized, so
+   it should be called WITH the video->sem taken.
+ */
+
+static void frame_prepare(struct video_card *video, unsigned int this_frame)
+{
+	struct frame *f = video->frames[this_frame];
+	int last_frame;
+
+	struct DMA_descriptor_block *block;
+	dma_addr_t block_dma;
+	struct CIP_header *cip;
+	dma_addr_t cip_dma;
+	
+	unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
+
+	/* these flags denote packets that need special attention */
+	int empty_packet, first_packet, last_packet, mid_packet;
+
+	u32 *branch_address, *last_branch_address = NULL;
+	unsigned long data_p;
+	int first_packet_empty = 0;
+	u32 cycleTimer, ct_sec, ct_cyc, ct_off;
+	unsigned long irq_flags;
+
+	irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
+	
+	full_packets = 0;
+
+
+
+	if(video->pal_or_ntsc == DV1394_PAL)
+		packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
+	else
+		packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
+
+	while( full_packets < packets_per_frame ) {
+		empty_packet = first_packet = last_packet = mid_packet = 0;
+
+		data_p = f->data + full_packets * 480;
+
+		/************************************************/
+		/* allocate a descriptor block and a CIP header */
+		/************************************************/
+
+		/* note: these should NOT cross a page boundary (DMA restriction) */
+
+		if(f->n_packets >= MAX_PACKETS) {
+			printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
+			return;
+		}
+
+		/* the block surely won't cross a page boundary, 
+		   since an even number of descriptor_blocks fit on a page */
+		block = &(f->descriptor_pool[f->n_packets]);
+
+		/* DMA address of the block = offset of block relative
+		    to the kernel base address of the descriptor pool
+		    + DMA base address of the descriptor pool */
+		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+		
+
+		/* the whole CIP pool fits on one page, so no worries about boundaries */
+		if( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool) 
+		    > PAGE_SIZE) {
+			printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
+			return;
+		}
+
+		cip = &(f->header_pool[f->n_packets]);
+		
+		/* DMA address of the CIP header = offset of cip
+		   relative to kernel base address of the header pool
+		   + DMA base address of the header pool */
+		cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
+		
+		/* is this an empty packet? */
+
+		if(video->cip_accum > video->cip_d) {
+			empty_packet = 1;
+			payload_size = 8;
+			video->cip_accum -= video->cip_d;
+		} else {
+			payload_size = 488;
+			video->cip_accum += video->cip_n;
+		}
+
+		/* there are three important packets each frame:
+
+		   the first packet in the frame - we ask the card to record the timestamp when
+		                                   this packet is actually sent, so we can monitor
+						   how accurate our timestamps are. Also, the first
+						   packet serves as a semaphore to let us know that
+						   it's OK to free the *previous* frame's DMA buffer
+
+		   the last packet in the frame -  this packet is used to detect buffer underflows.
+		                                   if this is the last ready frame, the last DMA block
+						   will have a branch back to the beginning of the frame
+						   (so that the card will re-send the frame on underflow).
+						   if this branch gets taken, we know that at least one
+						   frame has been dropped. When the next frame is ready,
+						   the branch is pointed to its first packet, and the
+						   semaphore is disabled.
+
+		   a "mid" packet slightly before the end of the frame - this packet should trigger
+		                   an interrupt so we can go and assign a timestamp to the first packet
+				   in the next frame. We don't use the very last packet in the frame
+				   for this purpose, because that would leave very little time to set
+				   the timestamp before DMA starts on the next frame.
+		*/
+		
+		if(f->n_packets == 0) {
+			first_packet = 1;
+		} else if ( full_packets == (packets_per_frame-1) ) {
+			last_packet = 1;
+		} else if (f->n_packets == packets_per_frame) {
+			mid_packet = 1;
+		}
+		
+
+		/********************/
+		/* setup CIP header */
+		/********************/
+
+		/* the timestamp will be written later from the
+		   mid-frame interrupt handler. For now we just
+		   store the address of the CIP header(s) that
+		   need a timestamp. */
+
+		/* first packet in the frame needs a timestamp */
+		if(first_packet) {
+			f->cip_syt1 = cip;
+			if(empty_packet)
+				first_packet_empty = 1;
+
+		} else if(first_packet_empty && (f->n_packets == 1) ) {
+			/* if the first packet was empty, the second
+			   packet's CIP header also needs a timestamp */
+			f->cip_syt2 = cip;
+		}
+
+		fill_cip_header(cip,
+				/* the node ID number of the OHCI card */
+				reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
+				video->continuity_counter, 
+				video->pal_or_ntsc,
+				0xFFFF /* the timestamp is filled in later */);
+		
+		/* advance counter, only for full packets */
+		if( ! empty_packet )
+			video->continuity_counter++;
+
+		/******************************/
+		/* setup DMA descriptor block */
+		/******************************/
+
+		/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
+		fill_output_more_immediate( &(block->u.out.omi),
+					    /* tag - what is this??? */ 1,
+					    video->channel,
+					    /* sync tag - what is this??? */ 0,
+					    payload_size);
+
+		if(empty_packet) {
+			/* second descriptor - OUTPUT_LAST for CIP header */
+			fill_output_last( &(block->u.out.u.empty.ol),
+
+					  /* want completion status on all interesting packets */
+					  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+					  /* want interrupts on all interesting packets */
+					  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+					  sizeof(struct CIP_header), /* data size */
+					  cip_dma);
+			
+			if(first_packet)
+				f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
+			else if(mid_packet)
+				f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
+			else if(last_packet) {
+				f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
+				f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
+			}
+
+			branch_address = &(block->u.out.u.empty.ol.q[2]);
+			n_descriptors = 3;
+			if(first_packet)
+				f->first_n_descriptors = n_descriptors;
+
+		} else { /* full packet */
+
+			/* second descriptor - OUTPUT_MORE for CIP header */
+			fill_output_more( &(block->u.out.u.full.om),
+					  sizeof(struct CIP_header), /* data size */
+					  cip_dma);
+
+			
+			/* third (and possibly fourth) descriptor - for DV data */
+			/* the 480-byte payload can cross a page boundary; if so,
+			   we need to split it into two DMA descriptors */
+
+			/* does the 480-byte data payload cross a page boundary? */
+			if( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
+
+				/* page boundary crossed */
+
+				fill_output_more( &(block->u.out.u.full.u.cross.om),
+						  /* data size - how much of data_p fits on the first page */
+						  PAGE_SIZE - (data_p % PAGE_SIZE),
+
+						  /* DMA address of data_p */
+						  dma_offset_to_bus(&f->video->user_dma,
+								    data_p - (unsigned long) f->video->user_buf));
+
+				fill_output_last( &(block->u.out.u.full.u.cross.ol),
+					  
+						  /* want completion status on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0, 
+
+						  /* want interrupt on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+						  /* data size - remaining portion of data_p */
+						  480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
+
+						  /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
+						  dma_offset_to_bus(&f->video->user_dma,
+								    data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+
+				if(first_packet)
+					f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+				else if(mid_packet)
+					f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+				else if(last_packet) {
+					f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
+					f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
+				}
+
+				branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
+
+				n_descriptors = 5;
+				if(first_packet)
+					f->first_n_descriptors = n_descriptors;
+				
+				full_packets++;
+
+			} else {
+				/* fits on one page */
+
+				fill_output_last( &(block->u.out.u.full.u.nocross.ol),
+					  
+						  /* want completion status on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+						  /* want interrupt on all interesting packets */
+						  (first_packet || mid_packet || last_packet) ? 1 : 0,
+
+						  480, /* data size (480 bytes of DV data) */
+
+						  
+						  /* DMA address of data_p */
+						  dma_offset_to_bus(&f->video->user_dma,
+								    data_p - (unsigned long) f->video->user_buf));
+				
+				if(first_packet)
+					f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+				else if(mid_packet)
+					f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+				else if(last_packet) {
+					f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
+					f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
+				}
+
+				branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
+
+				n_descriptors = 4;
+				if(first_packet)
+					f->first_n_descriptors = n_descriptors;
+
+				full_packets++;
+			}
+		}
+		
+		/* link this descriptor block into the DMA program by filling in 
+		   the branch address of the previous block */
+
+		/* note: we are not linked into the active DMA chain yet */
+
+		if(last_branch_address) {
+			*(last_branch_address) = block_dma | n_descriptors; 
+		}
+
+		last_branch_address = branch_address;
+
+
+		f->n_packets++;
+		
+	}
+
+	/* when we first assemble a new frame, set the final branch 
+	   to loop back up to the top */
+	*(f->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors;
+
+
+	/* make the latest version of the frame buffer visible to the PCI card */
+	/* could optimize this by only syncing the pages associated with this frame */
+	pci_dma_sync_sg(video->ohci->dev,
+			&video->user_dma.sglist[0],
+			video->user_dma.n_dma_pages,
+			PCI_DMA_TODEVICE);
+
+	/* lock against DMA interrupt */
+	spin_lock_irqsave(&video->spinlock, irq_flags);
+
+	f->state = FRAME_READY;
+
+	video->n_clear_frames--;
+
+	last_frame = video->first_clear_frame - 1;
+	if(last_frame == -1)
+		last_frame = video->n_frames-1;
+
+	video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+
+	irq_printk("   frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
+		   this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
+
+	irq_printk("   begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
+		   (unsigned long) f->frame_begin_timestamp, 
+		   (unsigned long) f->mid_frame_timestamp, 
+		   (unsigned long) f->frame_end_timestamp, 
+		   (unsigned long) f->frame_end_branch);
+	
+	if(video->active_frame != -1) {
+
+		/* if DMA is already active, we are almost done */
+		/* just link us onto the active DMA chain */
+		if(video->frames[last_frame]->frame_end_branch) {
+
+			/* point the previous frame's tail to this frame's head */
+			*(video->frames[last_frame]->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors; 
+
+			/* this write MUST precede the next one, or we could silently drop frames */
+			wmb();
+			
+			/* disable the want_status semaphore on the last packet */
+			*(video->frames[last_frame]->frame_end_branch - 2) &= 0xF7CFFFFF;
+
+			/* flush these writes to memory ASAP */
+			flush_pci_write(video->ohci);
+
+			/* NOTE:
+			   ideally the writes should be "atomic": if
+			   the OHCI card reads the want_status flag in
+			   between them, we'll falsely report a
+			   dropped frame. Hopefully this window is too
+			   small to really matter, and the consequence
+			   is rather harmless. */
+			
+
+			irq_printk("     new frame %d linked onto DMA chain\n", this_frame);
+
+		} else {
+			printk(KERN_ERR "dv1394: last frame not ready???\n");
+		}
+
+	} else {
+		
+		u32 transmit_sec, transmit_cyc;
+		u32 ts_cyc, ts_off;
+
+		/* DMA is stopped, so this is the very first frame */
+		video->active_frame = this_frame;
+		
+	        /* set CommandPtr to address and size of first descriptor block */
+		reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
+			  video->frames[video->active_frame]->descriptor_pool_dma |
+			  f->first_n_descriptors);
+
+		/* assign a timestamp based on the current cycle time...
+		   We'll tell the card to begin DMA 100 cycles from now,
+		   and assign a timestamp 103 cycles from now */
+
+		cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
+
+		ct_sec = cycleTimer >> 25;
+		ct_cyc = (cycleTimer >> 12) & 0x1FFF;
+		ct_off = cycleTimer & 0xFFF;
+
+		transmit_sec = ct_sec;
+		transmit_cyc = ct_cyc + 100;
+
+		transmit_sec += transmit_cyc/8000;
+		transmit_cyc %= 8000;
+		
+		ts_off = ct_off;
+		ts_cyc = transmit_cyc + 3;
+		ts_cyc %= 8000;
+
+		f->assigned_timestamp = (ts_cyc&0xF) << 12;
+
+		/* now actually write the timestamp into the appropriate CIP headers */
+		if(f->cip_syt1) {
+			f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
+			f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
+		}
+		if(f->cip_syt2) {
+			f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
+			f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
+		}
+		
+		/* --- start DMA --- */
+
+		/* clear all bits in ContextControl register */
+
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
+		wmb();
+
+		/* the OHCI card has the ability to start ISO transmission on a
+		   particular cycle (start-on-cycle). This way we can ensure that
+		   the first DV frame will have an accurate timestamp.
+		   
+		   However, start-on-cycle only appears to work if the OHCI card 
+		   is cycle master! Since the consequences of messing up the first
+		   timestamp are minimal*, just disable start-on-cycle for now.
+
+		   * my DV deck drops the first few frames before it "locks in;"
+		     so the first frame having an incorrect timestamp is inconsequential.
+		*/
+
+#if 0
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
+			  (1 << 31) /* enable start-on-cycle */
+			  | ( (transmit_sec & 0x3) << 29)
+			  | (transmit_cyc << 16));
+		wmb();
+#endif
+
+		
+
+		/* set the 'run' bit */
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
+		flush_pci_write(video->ohci);
+		
+		/* --- DMA should be running now --- */
+
+		debug_printk("    Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
+			     (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
+			     reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+			     reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
+
+		debug_printk("    DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
+			     ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
+
+#if DV1394_DEBUG_LEVEL >= 2
+		{
+			/* check if DMA is really running */
+			int i = 0;
+			while(i < 20) {
+				mb();
+				mdelay(1);
+				if(reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
+					printk("DMA ACTIVE after %d msec\n", i);
+					break;
+				}
+				i++;
+			}
+
+			printk("set = %08x, cmdPtr = %08x\n", 
+			       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+			       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
+			       );
+			
+			if( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) &  (1 << 10)) ) {
+				printk("DMA did NOT go active after 20ms, event = %x\n", 
+				       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
+			} else
+				printk("DMA is RUNNING!\n");
+		}
+#endif
+		
+	}
+
+
+	spin_unlock_irqrestore(&video->spinlock, irq_flags);
+}
+
+
+
+/*** RECEIVE FUNCTIONS *****************************************************/
+
+/* 
+	frame method put_packet
+
+	map and copy the packet data to its location in the frame 
+	based upon DIF section and sequence 
+*/
+
+static void inline
+frame_put_packet (struct frame *f, struct packet *p)
+{
+	int section_type = p->data[0] >> 5;           /* section type is in bits 5 - 7 */
+	int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
+	int dif_block = p->data[2];
+
+	switch (section_type) {
+	case 0:           /* 1 Header block */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
+	        break;
+	
+	case 1:           /* 2 Subcode blocks */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
+	        break;
+	
+	case 2:           /* 3 VAUX blocks */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
+	        break;
+	
+	case 3:           /* 9 Audio blocks interleaved with video */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
+	        break;
+	
+	case 4:           /* 135 Video blocks interleaved with audio */
+	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
+	        break;
+	
+	default:           /* we can not handle any other data */
+	        break;
+	}
+}
+
+
+static void start_dma_receive(struct video_card *video, struct frame *frame)
+{
+	/* reset iso recv control register */
+	reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+	wmb();
+	
+	/* clear bufferFill, set isochHeader and speed (0=100) */
+	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+
+	/* match on all tags, listen on channel */
+	reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+	
+	/* address and first descriptor block + Z=1 */
+	reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
+		  frame->descriptor_pool_dma | 1); /* Z=1 */
+	wmb();
+	
+	/* run */
+	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+	flush_pci_write(video->ohci);
+	
+	debug_printk("dv1394: DMA started\n");
+
+#if DV1394_DEBUG_LEVEL >= 2
+	{
+		int i;
+	
+		for(i = 0; i < 1000; ++i) {
+			mdelay(1);
+			if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+				printk("DMA ACTIVE after %d msec\n", i);
+				break;
+			}
+		}
+		if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+			printk("DEAD, event = %x\n", 
+			       reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+		} else
+			printk("RUNNING!\n");
+	}
+#endif
+}
+
+
+/* 
+   receive_packets() - build the DMA program for receiving
+*/
+
+static void receive_packets(struct video_card *video, struct frame *f)
+{
+	struct DMA_descriptor_block *block = NULL;
+	dma_addr_t block_dma = 0;
+	struct packet *data = NULL;
+	dma_addr_t data_dma = 0;
+	u32 *last_branch_address = NULL;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&video->spinlock, irq_flags);
+
+	video->n_clear_frames = 0;
+	video->first_clear_frame = -1;
+
+	for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
+		/* locate a descriptor block and packet from the buffer */
+		block = &(f->descriptor_pool[video->current_packet]);
+		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+		
+		data = &(video->packet_buffer[video->current_packet]);
+		data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
+		
+		/* setup DMA descriptor block */
+		fill_input_last( &(block->u.in.il), 512, data_dma);
+
+		/* link descriptors */
+		last_branch_address = f->frame_end_branch;
+
+		if (last_branch_address)
+			*(last_branch_address) = block_dma | 1; /* set Z=1 */
+
+		f->frame_end_branch = &(block->u.in.il.q[2]);
+	}
+	
+	/* loop tail to head */
+	if (f->frame_end_branch)
+		*(f->frame_end_branch) =  f->descriptor_pool_dma | 1; /* set Z=1 */
+
+	spin_unlock_irqrestore(&video->spinlock, irq_flags);
+
+	if (video->first_run) {
+		/* start DMA once all of the frames are READY */
+		video->first_run = 0;
+		video->current_packet = 0;
+		video->active_frame = f->frame_num;
+		start_dma_receive(video, f);
+	} 
+	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+		debug_printk("DEAD, event = %x\n", 
+			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+		/* wake */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+	}
+}
+
+
+
+/*** MANAGEMENT FUNCTIONS **************************************************/
+
+static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
+{
+	unsigned long flags, new_buf_size;
+	int i;
+	u64 chan_mask;
+	int retval = -EINVAL;
+
+	if(init->api_version != DV1394_API_VERSION)
+		goto err;
+	
+	/* first sanitize all the parameters */
+	if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
+		goto err;
+
+	if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
+		goto err;
+
+	if( (init->syt_offset == 0) || (init->syt_offset > 50) )
+		/* default SYT offset is 3 cycles */
+		init->syt_offset = 3;
+
+	if( (init->channel > 63) || (init->channel < 0) )
+		init->channel = 63;
+
+	chan_mask = (u64)1 << init->channel;
+
+	/* calculate what size DMA buffer is needed */
+	if(init->format == DV1394_NTSC)
+		new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
+	else
+		new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
+
+	/* round up to PAGE_SIZE */
+	if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
+
+	/* don't allow the user to allocate the DMA buffer more than once */
+	if( (video->user_buf) &&
+	    (video->user_buf_size != new_buf_size) ) {
+		goto err;
+	}
+	
+	/* shutdown the card if it's currently active */
+	/* (the card should not be reset if the parameters are screwy) */
+	if( video_card_initialized(video) )
+		do_dv1394_shutdown(video, 0);
+
+
+	/* try to claim the ISO channel */
+	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+	if(video->ohci->ISO_channel_usage & chan_mask) {
+		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+		retval = -EBUSY;
+		goto err;
+	}
+	video->ohci->ISO_channel_usage |= chan_mask;
+	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+
+	video->channel = init->channel;
+
+	
+	/* find and claim DMA contexts on the OHCI card */
+	
+	if(video->ohci_it_ctx == -1) {
+
+		for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) {
+
+			if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) {
+				video->ohci_it_ctx = i;
+				debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+				break;
+			}
+		}
+				
+		if(i == video->ohci->nb_iso_xmit_ctx) {
+			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
+			retval = -EBUSY;
+			goto err_ctx;
+		}
+	}
+	
+
+	if(video->ohci_ir_ctx == -1) {
+		for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) {
+
+			if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) {
+				video->ohci_ir_ctx = i;
+				debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+				break;
+			}
+		}
+				
+		if(i == video->ohci->nb_iso_rcv_ctx) {
+			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
+			retval = -EBUSY;
+			goto err_ctx;
+		}
+	}
+
+	
+	/* allocate struct frames */
+	for(i = 0; i < init->n_frames; i++) {
+		video->frames[i] = frame_new(i, video);
+
+		if(!video->frames[i]) {
+			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
+			retval = -ENOMEM;
+			goto err_frames;
+		}
+	}
+
+	/* initialize misc. fields of video */
+	video->n_frames = init->n_frames;
+	video->pal_or_ntsc = init->format;
+	
+
+	video->cip_accum = 0;
+	video->continuity_counter = 0;
+
+	video->active_frame = -1;
+	video->first_clear_frame = 0;
+	video->n_clear_frames = video->n_frames;
+	video->dropped_frames = 0;
+
+	video->write_off = 0;
+
+	video->first_run = 1;
+	video->current_packet = -1;
+	video->first_frame = 0;
+
+
+	if(video->pal_or_ntsc == DV1394_NTSC) {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
+		video->frame_size = DV1394_NTSC_FRAME_SIZE;
+	} else {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
+		video->frame_size = DV1394_PAL_FRAME_SIZE;
+	}
+
+	video->syt_offset = init->syt_offset;
+
+	if(video->user_buf == NULL) {
+		unsigned int i;
+		
+		/* allocate the ringbuffer */
+		video->user_buf = rvmalloc(new_buf_size);
+		if(!video->user_buf) {
+			printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
+			goto err_frames;
+		}
+		video->user_buf_size = new_buf_size;
+
+		/* allocate the sglist to hold the DMA addresses */
+		video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
+		video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
+		if(!video->user_dma.sglist) {
+			printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
+			goto err_user_buf;
+		}
+
+		/* initialize all fields of all sglist entries to zero
+		   (new requirement due to PCI changes in 2.4.13) */
+
+		memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+
+		
+		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
+		for(i = 0; i < video->user_dma.n_pages; i++) {
+			unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE );
+			
+			video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va);
+			video->user_dma.sglist[i].length = PAGE_SIZE;
+		}
+		
+		/* map the buffer in the IOMMU */
+		/* the user_data buffer only allows DMA *to* the card for transmission;
+		   incoming DV data comes through the packet_buffer first, and then is copied to user_data */
+		video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
+							 &video->user_dma.sglist[0],
+							 video->user_dma.n_pages,
+							 PCI_DMA_TODEVICE);
+		if(video->user_dma.n_dma_pages == 0) {
+			printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
+			goto err_user_buf;
+		}
+		
+		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
+			     video->n_frames, video->user_dma.n_pages,
+			     video->user_dma.n_dma_pages, video->user_buf_size);
+	}
+	
+	/* set up the frame->data pointers */
+	for(i = 0; i < video->n_frames; i++)
+		video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+
+	/* allocate packet buffers */
+	video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
+	if (video->packet_buffer_size % PAGE_SIZE)
+		video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
+
+	
+	video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
+	
+	if(!video->packet_buffer) {
+		printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
+		retval = -ENOMEM;
+		goto err_user_buf;
+	}
+
+	/* map the packet buffer into the IOMMU */
+	video->packet_buffer_dma = pci_map_single(video->ohci->dev,
+						  video->packet_buffer,
+						  video->packet_buffer_size,
+						  PCI_DMA_FROMDEVICE);
+	if(!video->packet_buffer_dma) {
+		printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
+		kfree(video->packet_buffer);
+		video->packet_buffer = NULL;
+		retval = -ENOMEM;
+		goto err_user_buf;
+	}
+
+	debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", 
+		     MAX_PACKET_BUFFER, video->packet_buffer_size);
+
+
+	/* set up register offsets for IT context */
+	/* IT DMA context registers are spaced 16 bytes apart */
+	video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
+	video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
+	video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
+
+	/* enable interrupts for IT context */
+	reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
+	debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
+
+	/* set up register offsets for IR context */
+	/* IR DMA context registers are spaced 32 bytes apart */
+	video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
+	video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
+	video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
+	video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
+
+	/* enable interrupts for IR context */
+	reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
+	debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
+	
+	return 0;
+
+ err_user_buf:
+	if(video->user_buf) {
+		if(video->user_dma.sglist) {
+			if(video->user_dma.n_dma_pages > 0) {
+				/* unmap it from the IOMMU */
+				pci_unmap_sg(video->ohci->dev,
+					     video->user_dma.sglist,
+					     video->user_dma.n_pages,
+					     PCI_DMA_TODEVICE);
+				video->user_dma.n_dma_pages = 0;
+			}
+			kfree(video->user_dma.sglist);
+			video->user_dma.sglist = NULL;
+			video->user_dma.n_pages = 0;
+		}
+		rvfree(video->user_buf, video->user_buf_size);
+		video->user_buf = NULL;
+		video->user_buf_size = 0;
+	}
+		
+ err_frames:
+	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
+		if(video->frames[i])
+			frame_delete(video->frames[i]);
+	}	
+	video->n_frames = 0;
+
+ err_ctx:
+	if(video->ohci_it_ctx != -1) {
+		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		video->ohci_it_ctx = -1;
+	}
+	if(video->ohci_ir_ctx != -1) {
+		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		video->ohci_ir_ctx = -1;
+	}
+	
+	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+	video->ohci->ISO_channel_usage &= ~chan_mask;
+	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+ err:
+	return retval;
+}
+
+/* if the user doesn't bother to call ioctl(INIT) before starting
+   mmap() or read()/write(), just give him some default values */
+
+static int do_dv1394_init_default(struct video_card *video)
+{
+	struct dv1394_init init;
+
+	init.api_version = DV1394_API_VERSION;
+	init.n_frames = 2;
+	/* the following are now set via proc_fs or devfs */
+	init.channel = video->channel;
+	init.format = video->pal_or_ntsc;
+	init.cip_n = video->cip_n; 
+	init.cip_d = video->cip_d;
+	init.syt_offset = video->syt_offset;
+
+	return do_dv1394_init(video, &init);
+}
+
+/* do NOT call from interrupt context */
+static void stop_dma(struct video_card *video)
+{
+	unsigned long flags;
+	int i;
+	
+	/* no interrupts */
+	spin_lock_irqsave(&video->spinlock, flags);
+
+	/* stop DMA if in progress */
+	if( (video->active_frame != -1) ||
+	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
+	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) &  (1 << 10)) ) {
+
+		/* clear the .run bits */
+		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
+		flush_pci_write(video->ohci);
+		
+		video->active_frame = -1;
+		video->first_run = 1;
+
+		
+		/* wait until DMA really stops */
+		i = 0;
+		while(i < 1000) {
+				
+			/* wait 0.1 millisecond */
+			udelay(100); 
+			
+			if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
+			    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {
+				/* still active */
+				mb();
+			} else {
+				debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
+				break;
+			}
+				
+			i++;
+		}
+			
+		if(i == 1000) {
+			printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
+		}
+	}
+
+	spin_unlock_irqrestore(&video->spinlock, flags);
+}
+
+
+
+static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
+{
+	int i;
+
+	debug_printk("dv1394: shutdown...\n");
+
+	/* stop DMA if in progress */
+	stop_dma(video);
+	
+	/* release the ISO channel */
+	if(video->channel != -1) {
+		u64 chan_mask;
+		unsigned long flags;
+		
+		chan_mask = (u64)1 << video->channel;
+		
+		spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
+		video->ohci->ISO_channel_usage &= ~(chan_mask);
+		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
+		
+		video->channel = -1;
+	}
+
+	/* release the DMA contexts */
+	if(video->ohci_it_ctx != -1) {
+		video->ohci_IsoXmitContextControlSet = 0;
+		video->ohci_IsoXmitContextControlClear = 0;
+		video->ohci_IsoXmitCommandPtr = 0;
+
+		/* disable interrupts for IT context */
+		reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
+		
+		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
+		video->ohci_it_ctx = -1;
+	}
+
+	if(video->ohci_ir_ctx != -1) {
+		video->ohci_IsoRcvContextControlSet = 0;
+		video->ohci_IsoRcvContextControlClear = 0;
+		video->ohci_IsoRcvCommandPtr = 0;
+		video->ohci_IsoRcvContextMatch = 0;
+
+		/* disable interrupts for IR context */
+		reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
+
+		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
+		video->ohci_ir_ctx = -1;
+	}
+
+	/* free the frame structs */
+	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
+		if(video->frames[i])
+			frame_delete(video->frames[i]);
+		video->frames[i] = NULL;
+	}
+
+	video->n_frames = 0;
+		
+	/* we can't free the DMA buffer unless it is guaranteed that
+	   no more user-space mappings exist */
+	
+	if(free_user_buf && video->user_buf) {
+		if(video->user_dma.sglist) {
+			if(video->user_dma.n_dma_pages > 0) {
+				/* unmap it from the IOMMU */
+				pci_unmap_sg(video->ohci->dev,
+					     video->user_dma.sglist,
+					     video->user_dma.n_pages,
+					     PCI_DMA_TODEVICE);
+				video->user_dma.n_dma_pages = 0;
+			}
+			kfree(video->user_dma.sglist);
+			video->user_dma.sglist = NULL;
+			video->user_dma.n_pages = 0;
+		}
+		rvfree(video->user_buf, video->user_buf_size);
+		video->user_buf = NULL;
+		video->user_buf_size = 0;
+	}
+	
+	if (video->packet_buffer) {
+		pci_unmap_single(video->ohci->dev,
+				 video->packet_buffer_dma,
+				 video->packet_buffer_size,
+				 PCI_DMA_FROMDEVICE);
+		kfree(video->packet_buffer);
+		video->packet_buffer = NULL;
+		video->packet_buffer_size = 0;
+	}
+
+	debug_printk("dv1394: shutdown complete\n");
+
+	return 0;
+}
+
+
+
+/*
+       **********************************
+       *** MMAP() THEORY OF OPERATION ***
+       **********************************
+
+        The ringbuffer cannot be re-allocated or freed while
+        a user program maintains a mapping of it. (note that a mapping
+	can persist even after the device fd is closed!)
+
+	So, only let the user process allocate the DMA buffer once.
+	To resize or deallocate it, you must close the device file
+	and open it again.
+
+	Previously Dan M. hacked out a scheme that allowed the DMA
+	buffer to change by forcefully unmapping it from the user's
+	address space. It was prone to error because it's very hard to
+	track all the places the buffer could have been mapped (we
+	would have had to walk the vma list of every process in the
+	system to be sure we found all the mappings!). Instead, we
+	force the user to choose one buffer size and stick with
+	it. This small sacrifice is worth the huge reduction in
+	error-prone code in dv1394.
+
+	Note: dv1394_mmap does no page table manipulation. The page
+	table entries are created by the dv1394_nopage() handler as
+	page faults are taken by the user.
+*/
+
+static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
+{
+	unsigned long offset;
+	unsigned long page, kernel_virt_addr;
+	struct page *ret = NOPAGE_SIGBUS;
+
+	struct video_card *video = (struct video_card*) area->vm_private_data;
+	
+	/* guard against process-context operations and the interrupt */
+	/* (by definition page faults are taken in interrupt context) */
+	spin_lock(&video->spinlock);
+
+	if(!video->user_buf)
+		goto out;
+
+	if( (address < (unsigned long) area->vm_start) ||
+	    (address > (unsigned long) area->vm_start + video->user_buf_size) )
+		goto out;
+
+	offset = address - area->vm_start;
+	kernel_virt_addr = (unsigned long) video->user_buf + offset;
+
+	page = kvirt_to_pa(kernel_virt_addr);
+	
+	ret = virt_to_page(__va(page));
+	get_page(ret);
+
+ out:
+	spin_unlock(&video->spinlock);
+	return ret;
+}
+
+static struct vm_operations_struct dv1394_vm_ops = {
+	nopage: dv1394_nopage
+};
+
+/*
+  dv1394_mmap does no page table manipulation. The page table entries
+  are created by the dv1394_nopage() handler as page faults are taken
+  by the user.
+*/
+
+int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_card *video = file_to_video_card(file);
+	unsigned long size;
+	int res = -EINVAL;
+
+	/* serialize mmap */
+	down(&video->sem);
+
+	if( ! video_card_initialized(video) ) {
+		res = do_dv1394_init_default(video);
+		if(res)
+			goto err;
+	}
+
+	/* region must be page-aligned */
+	if(vma->vm_pgoff != 0)
+		goto err;
+	
+	/* check the size the user is trying to map */
+	size = vma->vm_end - vma->vm_start;
+	if(size > video->user_buf_size)
+		goto err;
+
+	/* 
+	   we don't actually mess with the page tables here.
+	   (nopage() takes care of that from the page fault handler)
+	   Just set up the vma->vm_ops.
+	*/
+
+        vma->vm_ops = &dv1394_vm_ops;
+	vma->vm_private_data = video;
+	vma->vm_file = file;
+
+	/* don't try to swap this out =) */
+	vma->vm_flags |= VM_RESERVED;
+
+	up(&video->sem);
+	return 0;
+ err:
+	up(&video->sem);
+	return res;
+}
+
+
+/*** DEVICE FILE INTERFACE *************************************************/
+
+/* no need to serialize, multiple threads OK */
+static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_card *video = file_to_video_card(file);
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	poll_wait(file, &video->waitq, wait);
+
+	spin_lock_irqsave(&video->spinlock, flags);
+	if( video->n_frames == 0 ) {
+
+	} else if( video->active_frame == -1 ) {
+		/* nothing going on */
+		mask |= POLLOUT;
+	} else {
+		/* any clear/ready buffers? */
+		if(video->n_clear_frames >0)
+			mask |= POLLOUT | POLLIN;
+	}
+	spin_unlock_irqrestore(&video->spinlock, flags);
+
+	return mask;
+}
+
+static int dv1394_fasync(int fd, struct file *file, int on)
+{
+	/* I just copied this code verbatim from Alan Cox's mouse driver example
+	   (linux/Documentation/DocBook/) */
+	
+	struct video_card *video = file_to_video_card(file);
+	
+	int retval = fasync_helper(fd, file, on, &video->fasync);
+	 
+	if (retval < 0)
+		return retval;
+        return 0;
+}
+
+static ssize_t dv1394_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct video_card *video = file_to_video_card(file);
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret;
+	size_t cnt;
+	unsigned long flags;
+	int target_frame;
+
+	/* serialize this to prevent multi-threaded mayhem */
+	if(file->f_flags & O_NONBLOCK) {
+		if(down_trylock(&video->sem))
+			return -EAGAIN;
+	} else {
+		if(down_interruptible(&video->sem))
+			return -ERESTARTSYS;
+	}
+
+	if( !video_card_initialized(video) ) {
+		ret = do_dv1394_init_default(video);
+		if(ret) {
+			up(&video->sem);
+			return ret;
+		}
+	}
+
+	ret = 0;
+	add_wait_queue(&video->waitq, &wait);
+	
+	while(count > 0) {
+
+		/* must set TASK_INTERRUPTIBLE *before* checking for free
+		   buffers; otherwise we could miss a wakeup if the interrupt
+		   fires between the check and the schedule() */
+		
+		set_current_state(TASK_INTERRUPTIBLE);
+		
+		spin_lock_irqsave(&video->spinlock, flags);
+		
+		target_frame = video->first_clear_frame;
+		
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		if(video->frames[target_frame]->state == FRAME_CLEAR) {
+
+			/* how much room is left in the target frame buffer */
+			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
+
+		} else {
+			/* buffer is already used */
+			cnt = 0;
+		}
+
+		if(cnt > count)
+			cnt = count;
+
+		if (cnt <= 0) { 
+			/* no room left, gotta wait */
+			if(file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+			
+			continue; /* start over from 'while(count > 0)...' */
+		}
+
+		if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) {
+			if(!ret)
+				ret = -EFAULT;
+			break;
+		}
+
+		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
+				frame_prepare(video, target_frame);
+	}
+	
+	remove_wait_queue(&video->waitq, &wait);
+	set_current_state(TASK_RUNNING);
+	up(&video->sem);
+	return ret;
+}
+
+
+static ssize_t dv1394_read(struct file *file,  char *buffer, size_t count, loff_t *ppos)
+{
+	struct video_card *video = file_to_video_card(file);
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret;
+	size_t cnt;
+	unsigned long flags;
+	int target_frame;
+
+	/* serialize this to prevent multi-threaded mayhem */
+	if(file->f_flags & O_NONBLOCK) {
+		if(down_trylock(&video->sem))
+			return -EAGAIN;
+	} else {
+		if(down_interruptible(&video->sem))
+			return -ERESTARTSYS;
+	}
+
+	if( !video_card_initialized(video) ) {
+		ret = do_dv1394_init_default(video);
+		if(ret) {
+			up(&video->sem);
+			return ret;
+		}
+		receive_packets(video, video->frames[video->first_clear_frame]);
+	}
+
+	ret = 0;
+	add_wait_queue(&video->waitq, &wait);
+
+	while(count > 0) {
+
+		/* must set TASK_INTERRUPTIBLE *before* checking for free
+		   buffers; otherwise we could miss a wakeup if the interrupt
+		   fires between the check and the schedule() */
+		
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		target_frame = video->first_clear_frame;
+
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		if(target_frame >= 0 &&
+			video->n_clear_frames > 0 &&
+			video->frames[target_frame]->state == FRAME_CLEAR) {
+
+			/* how much room is left in the target frame buffer */
+			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
+
+		} else {
+			/* buffer is already used */
+			cnt = 0;
+		}
+
+		if(cnt > count)
+			cnt = count;
+
+		if (cnt <= 0) { 
+			/* no room left, gotta wait */
+			if(file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+			
+			continue; /* start over from 'while(count > 0)...' */
+		}
+
+		if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) {
+				if(!ret)
+					ret = -EFAULT;
+				break;
+		}
+
+		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if(video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
+			spin_lock_irqsave(&video->spinlock, flags);
+			video->n_clear_frames--;
+			video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+			spin_unlock_irqrestore(&video->spinlock, flags);
+		}
+	}
+	
+	remove_wait_queue(&video->waitq, &wait);
+	set_current_state(TASK_RUNNING);
+	up(&video->sem);
+	return ret;
+}
+
+
+/*** DEVICE IOCTL INTERFACE ************************************************/
+
+/* I *think* the VFS serializes ioctl() for us, so we don't have to worry
+   about situations like having two threads in here at once... */
+
+static int dv1394_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct video_card *video = file_to_video_card(file);
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* serialize this to prevent multi-threaded mayhem */
+	if(file->f_flags & O_NONBLOCK) {
+		if(down_trylock(&video->sem))
+			return -EAGAIN;
+	} else {
+		if(down_interruptible(&video->sem))
+			return -ERESTARTSYS;
+	}
+
+	switch(cmd)
+	{
+	case DV1394_SUBMIT_FRAMES: {
+		unsigned int n_submit;
+
+		if( !video_card_initialized(video) ) {
+			ret = do_dv1394_init_default(video);
+			if(ret)
+				goto out;
+		}
+
+		n_submit = (unsigned int) arg;
+
+		if(n_submit > video->n_frames) {
+			ret = -EINVAL;
+			goto out;
+		}
+			
+		while(n_submit > 0) {
+
+			add_wait_queue(&video->waitq, &wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+				
+			spin_lock_irqsave(&video->spinlock, flags);
+
+			/* wait until video->first_clear_frame is really CLEAR */
+			while(video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
+
+				spin_unlock_irqrestore(&video->spinlock, flags);
+					
+				if(signal_pending(current)) {
+					remove_wait_queue(&video->waitq, &wait);
+					set_current_state(TASK_RUNNING);
+					ret = -EINTR;
+					goto out;
+				}
+
+				schedule();
+				set_current_state(TASK_INTERRUPTIBLE);
+				
+				spin_lock_irqsave(&video->spinlock, flags);
+			}
+			spin_unlock_irqrestore(&video->spinlock, flags);
+
+			remove_wait_queue(&video->waitq, &wait);
+			set_current_state(TASK_RUNNING);
+				
+			frame_prepare(video, video->first_clear_frame);
+
+			n_submit--;
+		}
+
+		ret = 0;
+		break;
+	}
+
+	case DV1394_WAIT_FRAMES: {
+		unsigned int n_wait;
+
+		if( !video_card_initialized(video) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		n_wait = (unsigned int) arg;
+
+		/* since we re-run the last frame on underflow, we will
+		   never actually have n_frames clear frames; at most only
+		   n_frames - 1 */
+
+		if(n_wait > (video->n_frames-1) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+			
+		add_wait_queue(&video->waitq, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		while(video->n_clear_frames < n_wait) {
+			
+			spin_unlock_irqrestore(&video->spinlock, flags);
+					
+			if(signal_pending(current)) {
+				remove_wait_queue(&video->waitq, &wait);
+				set_current_state(TASK_RUNNING);
+				ret = -EINTR;
+				goto out;
+			}
+
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+			
+			spin_lock_irqsave(&video->spinlock, flags);
+		}
+
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		remove_wait_queue(&video->waitq, &wait);
+		set_current_state(TASK_RUNNING);
+		ret = 0;
+		break;
+	}
+
+	case DV1394_RECEIVE_FRAMES: {
+		unsigned int n_recv;
+
+		if( !video_card_initialized(video) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		n_recv = (unsigned int) arg;
+
+		/* at least one frame must be active */
+		if(n_recv > (video->n_frames-1) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+			
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		/* release the clear frames */
+		video->n_clear_frames -= n_recv;
+
+		/* advance the clear frame cursor */
+		video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
+
+		/* reset dropped_frames */
+		video->dropped_frames = 0;
+			
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		ret = 0;
+		break;
+	}
+
+	case DV1394_START_RECEIVE: {
+
+		if( !video_card_initialized(video) ) {
+			ret = do_dv1394_init_default(video);
+			if(ret)
+				goto out;
+		}
+	
+		receive_packets(video, video->frames[video->first_clear_frame]);
+
+		ret = 0;
+		break;
+	}
+
+	case DV1394_INIT: {
+		struct dv1394_init init;
+		if(arg == (unsigned long) NULL) {
+			ret = do_dv1394_init_default(video);
+		} else {
+			if(copy_from_user(&init, (void*)arg, sizeof(init))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			ret = do_dv1394_init(video, &init);
+		}
+		break;
+	}
+
+	case DV1394_SHUTDOWN:
+		ret = do_dv1394_shutdown(video, 0);
+		break;
+
+
+        case DV1394_GET_STATUS: {
+		struct dv1394_status status;
+
+		if( !video_card_initialized(video) ) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		status.init.api_version = DV1394_API_VERSION;
+		status.init.channel = video->channel;
+		status.init.n_frames = video->n_frames;
+		status.init.format = video->pal_or_ntsc;
+		status.init.cip_n = video->cip_n;
+		status.init.cip_d = video->cip_d;
+		status.init.syt_offset = video->syt_offset;
+
+		status.first_clear_frame = video->first_clear_frame;
+
+		/* the rest of the fields need to be locked against the interrupt */
+		spin_lock_irqsave(&video->spinlock, flags);
+
+		status.active_frame = video->active_frame;
+		status.n_clear_frames = video->n_clear_frames;
+
+		status.dropped_frames = video->dropped_frames;
+
+		/* reset dropped_frames */
+		video->dropped_frames = 0;
+			
+		spin_unlock_irqrestore(&video->spinlock, flags);
+
+		if(copy_to_user((void*)arg, &status, sizeof(status))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		ret = 0;
+		break;
+	}
+
+	default:
+		break;
+	}
+
+ out:
+	up(&video->sem);
+	return ret;
+}
+
+
+
+/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
+
+static int dv1394_open(struct inode *inode, struct file *file)
+{
+	struct video_card *video = NULL;
+
+	/* if the device was opened through devfs, then file->private_data
+	   has already been set to video by devfs */
+	if(file->private_data) {
+		video = (struct video_card*) file->private_data;
+		
+	} else {
+		/* look up the card by ID */
+		
+		struct list_head *lh;
+		unsigned long flags;
+		
+		spin_lock_irqsave(&dv1394_cards_lock, flags);
+		if(!list_empty(&dv1394_cards)) {
+			struct video_card *p;
+			list_for_each(lh, &dv1394_cards) {
+				p = list_entry(lh, struct video_card, list);
+				if((p->id >> 2) == ieee1394_file_to_instance(file)) {
+					video = p;
+					break;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+		if(!video) {
+			debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file));
+			return -ENODEV;
+		}
+		
+		file->private_data = (void*) video;
+	}
+	
+#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
+
+	if( test_and_set_bit(0, &video->open) ) {
+		/* video is already open by someone else */
+		return -EBUSY;
+ 	}
+
+#endif
+
+	return 0;
+}
+
+
+static int dv1394_release(struct inode *inode, struct file *file)
+{
+	struct video_card *video = file_to_video_card(file);
+
+	/* OK to free the DMA buffer, no more mappings can exist */
+	do_dv1394_shutdown(video, 1);
+
+	/* clean up async I/O users */
+	dv1394_fasync(-1, file, 0);
+	
+	/* give someone else a turn */
+	clear_bit(0, &video->open);
+
+	return 0;
+}
+
+
+/*** PROC_FS INTERFACE ******************************************************/
+#ifdef CONFIG_PROC_FS
+static LIST_HEAD(dv1394_procfs);
+struct dv1394_procfs_entry {
+	struct list_head list;
+    struct proc_dir_entry *procfs;
+	char name[32];
+	struct dv1394_procfs_entry *parent;
+};
+static spinlock_t dv1394_procfs_lock = SPIN_LOCK_UNLOCKED;
+
+static int dv1394_procfs_read( char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	struct video_card *video = (struct video_card*) data;
+
+	snprintf( page, count, 
+		"\
+format=%s\n\
+channel=%d\n\
+cip_n=%lu\n\
+cip_d=%lu\n\
+syt_offset=%u\n",
+		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+		video->channel,
+		video->cip_n, video->cip_d, video->syt_offset );
+	return strlen(page);
+}
+
+/* lifted from the stallion.c driver */
+#undef  TOLOWER
+#define TOLOWER(x)      ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
+static unsigned long atol(char *str)
+{
+	unsigned long   val;
+	int             base, c;
+	char            *sp;
+
+	val = 0;
+	sp = str;
+	if ((*sp == '0') && (*(sp+1) == 'x')) {
+		base = 16;
+		sp += 2;
+	} else if (*sp == '0') {
+		base = 8;
+		sp++;
+	} else {
+		base = 10;
+	}
+
+	for (; (*sp != 0); sp++) {
+		c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
+		if ((c < 0) || (c >= base)) {
+			printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str);
+			val = 0;
+			break;
+		}
+		val = (val * base) + c;
+	}
+	return(val);
+}
+
+static int dv1394_procfs_write( struct file *file,
+			const char *buffer, unsigned long count, void *data)
+{
+	int len = 0;
+	char new_value[64];
+	char *pos;
+	struct video_card *video = (struct video_card*) data;
+	
+	if (count > 64)
+		len = 64;
+	else
+		len = count;
+				
+	if (copy_from_user( new_value, buffer, len))
+		return -EFAULT;
+	
+	pos = strchr(new_value, '=');
+	if (pos != NULL) {
+		int val_len = len - (pos-new_value) - 1;
+		char buf[64];
+		memset(buf, 0, 64);
+		strncpy(buf, pos+1, val_len);
+		if (buf[val_len-1] == '\n') buf[val_len-1] = 0;
+		
+		if (strnicmp( new_value, "format", (pos-new_value)) == 0) {
+			if (strnicmp( buf, "NTSC", val_len) == 0)
+				video->pal_or_ntsc = DV1394_NTSC;
+			else if (strnicmp( buf, "PAL", val_len) == 0)
+				video->pal_or_ntsc = DV1394_PAL;
+				
+		} else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) {
+			video->cip_n = atol(buf);
+		} else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) {
+			video->cip_d = atol(buf);
+		} else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) {
+			video->syt_offset = atol(buf);
+		} else if (strnicmp( new_value, "channel", (pos-new_value)) == 0) {
+			video->channel = atol(buf);
+		}
+	}
+	
+	return len;
+}
+
+struct dv1394_procfs_entry *
+dv1394_procfs_find( char *name)
+{
+	struct list_head *lh;
+	struct dv1394_procfs_entry *p;
+		
+	spin_lock( &dv1394_procfs_lock);
+	if(!list_empty(&dv1394_procfs)) {
+		list_for_each(lh, &dv1394_procfs) {
+			p = list_entry(lh, struct dv1394_procfs_entry, list);
+			if(!strncmp(p->name, name, sizeof(p->name))) {
+				spin_unlock( &dv1394_procfs_lock);
+				return p;
+			}
+		}
+	}
+	spin_unlock( &dv1394_procfs_lock);
+	return NULL;
+}
+
+static int dv1394_procfs_add_entry(struct video_card *video)
+{
+	char buf[32];
+	struct dv1394_procfs_entry *p;
+	struct dv1394_procfs_entry *parent;
+
+	p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_procfs_entry));
+	
+	snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2),
+						(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"));
+		
+	parent = dv1394_procfs_find(buf);
+	if (parent == NULL) {
+		printk(KERN_ERR "dv1394: unable to locate parent procfs of %s\n", buf);
+		goto err_free;
+	}
+	
+	p->procfs = create_proc_entry( 
+						(video->mode == MODE_RECEIVE ? "in" : "out"),
+						0666, parent->procfs);
+
+	if (p->procfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s/%s\n",
+			parent->name,
+			(video->mode == MODE_RECEIVE ? "in" : "out"));
+		goto err_free;
+	}
+	
+	p->procfs->owner = THIS_MODULE;
+	p->procfs->data = video;
+	p->procfs->read_proc = dv1394_procfs_read;
+	p->procfs->write_proc = dv1394_procfs_write;
+
+	spin_lock( &dv1394_procfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_procfs);
+	spin_unlock( &dv1394_procfs_lock);
+	
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+static int
+dv1394_procfs_add_dir( char *name,
+					struct dv1394_procfs_entry *parent, 
+					struct dv1394_procfs_entry **out)
+{
+	struct dv1394_procfs_entry *p;
+
+	p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_procfs_entry));
+	
+	if (parent == NULL) {
+		snprintf(p->name, sizeof(p->name), "%s", name);
+		p->procfs = proc_mkdir( name, ieee1394_procfs_entry);
+	} else {
+		snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name);
+		p->procfs = proc_mkdir( name, parent->procfs);
+	}
+	if (p->procfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s\n", p->name);
+		goto err_free;
+	}
+
+	p->procfs->owner = THIS_MODULE;
+	p->parent = parent;
+	if (out != NULL) *out = p;
+
+	spin_lock( &dv1394_procfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_procfs);
+	spin_unlock( &dv1394_procfs_lock);
+
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+void dv1394_procfs_del( char *name)
+{
+	struct dv1394_procfs_entry *p = dv1394_procfs_find(name);
+	if (p != NULL) {
+		if (p->parent == NULL)
+			remove_proc_entry(p->name, ieee1394_procfs_entry);
+		else
+			remove_proc_entry(p->name, p->parent->procfs);
+		
+		spin_lock( &dv1394_procfs_lock);
+		list_del(&p->list);
+		spin_unlock( &dv1394_procfs_lock);
+		kfree(p);
+	}
+}
+#endif /* CONFIG_PROC_FS */
+
+/*** DEVICE DRIVER HANDLERS ************************************************/
+
+static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
+			quadlet_t isoXmitIntEvent, void *data)
+{
+	int wake = 0;
+	struct video_card *video = (struct video_card*) data;
+
+	irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
+		   (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
+	irq_printk("ContextControl = %08x, CommandPtr = %08x\n", 
+	       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
+	       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
+	       );
+
+	
+	if( (video->ohci_it_ctx != -1) &&
+	    (isoXmitIntEvent & (1 << video->ohci_it_ctx)) &&
+	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
+
+		struct frame *f;
+		unsigned int frame, i;
+
+		spin_lock(&video->spinlock);
+		if(video->active_frame == -1)
+			frame = 0;
+		else
+			frame = video->active_frame;
+
+		/* check all the DMA-able frames */
+		for(i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
+
+			irq_printk("IRQ checking frame %d...", frame);
+			f = video->frames[frame];
+			if(f->state != FRAME_READY) {
+				irq_printk("clear, skipping\n");
+				/* we don't own this frame */
+				continue;
+			}
+
+			irq_printk("DMA\n");
+
+			/* check the frame begin semaphore to see if we can free the previous frame */
+			if( *(f->frame_begin_timestamp) ) {
+				int prev_frame;
+				struct frame *prev_f;
+
+				
+
+				/* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
+				irq_printk("  BEGIN\n");
+
+				prev_frame = frame - 1;
+				if(prev_frame == -1)
+					prev_frame += video->n_frames;
+				prev_f = video->frames[prev_frame];
+				
+				/* make sure we can actually garbage collect
+				   this frame */
+				if( (prev_f->state == FRAME_READY) &&
+				    prev_f->done && (!f->done) ) 
+				{
+					frame_reset(prev_f);
+					video->n_clear_frames++;
+					wake = 1;
+					video->active_frame = frame;
+
+					irq_printk("  BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
+				} else {
+					irq_printk("  BEGIN - can't free yet\n");
+				}
+
+				f->done = 1;
+			}
+
+		     
+			/* see if we need to set the timestamp for the next frame */
+			if( *(f->mid_frame_timestamp) ) {
+				struct frame *next_frame;
+				u32 ts_cyc, ts_off;
+
+				*(f->mid_frame_timestamp) = 0;
+
+				irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
+				       *(f->frame_begin_timestamp) & 0x1FFF, *(f->frame_begin_timestamp) & 0xF,
+				       f->assigned_timestamp >> 12,       f->assigned_timestamp & 0xFFF);
+
+				/* prepare next frame and assign timestamp */
+				next_frame = video->frames[ (frame+1) % video->n_frames ];
+
+				if(next_frame->state == FRAME_READY) {
+					irq_printk("  MIDDLE - next frame is ready, good\n");
+				} else {
+					debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
+					next_frame = f;
+				}
+
+				/* set the timestamp to the timestamp of the last frame sent,
+				   plus the length of the last frame sent, plus the syt latency */
+				ts_cyc = *(f->frame_begin_timestamp) & 0xF;
+				/* advance one frame, plus syt latency (typically 2-3) */
+				ts_cyc += f->n_packets + video->syt_offset ; 
+
+				ts_off = 0; 
+
+				ts_cyc += ts_off/3072;
+				ts_off %= 3072;
+
+				next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
+				if(next_frame->cip_syt1) {
+					next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
+					next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
+				}
+				if(next_frame->cip_syt2) {
+					next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
+					next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
+				}
+
+			}
+
+			/* see if the frame looped */
+			if( *(f->frame_end_timestamp) ) {
+
+				*(f->frame_end_timestamp) = 0;
+
+				debug_printk("  END - the frame looped at least once\n");
+
+				video->dropped_frames++;
+			}
+
+
+		
+		} /* for(each frame) */
+
+		spin_unlock(&video->spinlock);
+		
+	} /* end XMIT portion */
+
+	/***** RECEIVE INTERRUPT and DMA ACTIVE *****/
+
+	else if( (video->ohci_ir_ctx != -1) &&
+		 (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) &&
+		 (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
+
+		int sof=0; /* start-of-frame flag */
+		struct frame *f;
+
+		spin_lock(&video->spinlock);
+
+		irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
+			   video->packet_buffer[video->current_packet].timestamp, video->packet_buffer[video->current_packet].data_length, 
+			   video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
+		
+		f = video->frames[video->active_frame];
+
+		/* exclude empty packet */
+		if (video->packet_buffer[video->current_packet].data_length > 8) {
+		
+			/* check for start of frame */
+			sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
+				video->packet_buffer[video->current_packet].data[1] == 0x07);
+
+			if (!video->first_frame) {
+				if (sof) {
+					video->first_frame = 1;
+				}
+
+			} else if (sof) {
+				/* close current frame */
+				frame_reset(f);  /* f->state = STATE_CLEAR */
+				video->n_clear_frames++;
+				if (video->n_clear_frames > video->n_frames) {
+					video->n_clear_frames = video->n_frames;
+					video->dropped_frames++;
+				}
+				if (video->first_clear_frame == -1)
+					video->first_clear_frame = video->active_frame;
+
+				/* get the next frame */
+				video->active_frame = (video->active_frame + 1) % video->n_frames;
+				f = video->frames[video->active_frame];
+			
+				irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
+					   video->active_frame, video->n_clear_frames, video->first_clear_frame);
+ 			}
+			if (video->first_frame) {
+				if (sof) {
+					/* open next frame */
+					f->state = FRAME_READY;
+				}
+				
+				/* copy to buffer */
+				if (f->n_packets > (video->frame_size / 480)) {
+					printk(KERN_ERR "frame buffer overflow during receive\n");
+				}
+
+				/* make sure we are seeing the latest changes to packet_buffer */
+				pci_dma_sync_single(video->ohci->dev,
+						    video->packet_buffer_dma,
+						    video->packet_buffer_size,
+						    PCI_DMA_FROMDEVICE);
+				
+				frame_put_packet( f, &video->packet_buffer[video->current_packet]);
+				
+			} /* first_frame */
+ 
+		} /* not empty packet */
+ 
+		/* advance packet_buffer cursor */
+		video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
+ 
+ 		spin_unlock(&video->spinlock);
+
+		wake = 1; /* why the hell not? */
+
+	} /* receive interrupt */
+
+	if(wake) {
+		
+		/* send SIGIO */
+		
+		if(isoRecvIntEvent & (1))
+			kill_fasync(&video->fasync, SIGIO, POLL_IN);
+		
+		if(isoXmitIntEvent & (1))
+			kill_fasync(&video->fasync, SIGIO, POLL_OUT);
+		
+		/* wake readers/writers/ioctl'ers */
+		wake_up_interruptible(&video->waitq);
+	}
+}
+
+static struct file_operations dv1394_fops=
+{
+	owner:		THIS_MODULE,
+	poll:           dv1394_poll,
+	ioctl:		dv1394_ioctl,
+	mmap:		dv1394_mmap,
+	open:		dv1394_open,
+	write:          dv1394_write,
+	read:           dv1394_read,
+	release:	dv1394_release,
+	fasync:         dv1394_fasync,
+};
+
+
+/*** DEVFS HELPERS *********************************************************/
+
+struct dv1394_devfs_entry *
+dv1394_devfs_find( char *name)
+{
+	struct list_head *lh;
+	struct dv1394_devfs_entry *p;
+
+	spin_lock( &dv1394_devfs_lock);
+	if(!list_empty(&dv1394_devfs)) {
+		list_for_each(lh, &dv1394_devfs) {
+			p = list_entry(lh, struct dv1394_devfs_entry, list);
+			if(!strncmp(p->name, name, sizeof(p->name))) {
+				spin_unlock( &dv1394_devfs_lock);
+				return p;
+			}
+		}
+	}
+	return NULL;
+}
+
+static int dv1394_devfs_add_entry(struct video_card *video)
+{
+	char buf[32];
+	struct dv1394_devfs_entry *p;
+	struct dv1394_devfs_entry *parent;
+
+	p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_devfs_entry));
+	
+	snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2),
+						(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"));
+		
+	parent = dv1394_devfs_find(buf);
+	if (parent == NULL) {
+		printk(KERN_ERR "dv1394: unable to locate parent devfs of %s\n", buf);
+		goto err_free;
+	}
+	
+	video->devfs_handle = devfs_register(
+						 parent->devfs,
+					     (video->mode == MODE_RECEIVE ? "in" : "out"),
+						 DEVFS_FL_NONE,
+					     IEEE1394_MAJOR,
+					     IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
+					     S_IFCHR | S_IRUGO | S_IWUGO,
+					     &dv1394_fops,
+					     (void*) video);
+	p->devfs = video->devfs_handle;
+
+	if (p->devfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s/%s\n",
+			parent->name,
+			(video->mode == MODE_RECEIVE ? "in" : "out"));
+		goto err_free;
+	}
+	
+	spin_lock( &dv1394_devfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_devfs);
+	spin_unlock( &dv1394_devfs_lock);
+	
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+static int
+dv1394_devfs_add_dir( char *name,
+					struct dv1394_devfs_entry *parent, 
+					struct dv1394_devfs_entry **out)
+{
+	struct dv1394_devfs_entry *p;
+
+	p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_devfs_entry));
+	
+	if (parent == NULL) {
+		snprintf(p->name, sizeof(p->name), "%s", name);
+		p->devfs = devfs_mk_dir(ieee1394_devfs_handle, name, NULL);
+	} else {
+		snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name);
+		p->devfs = devfs_mk_dir(parent->devfs, name, NULL);
+	}
+	if (p->devfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s\n", p->name);
+		goto err_free;
+	}
+
+	p->parent = parent;
+	if (out != NULL) *out = p;
+
+	spin_lock( &dv1394_devfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_devfs);
+	spin_unlock( &dv1394_devfs_lock);
+
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+void dv1394_devfs_del( char *name)
+{
+	struct dv1394_devfs_entry *p = dv1394_devfs_find(name);
+	if (p != NULL) {
+		devfs_unregister(p->devfs);
+		
+		spin_lock( &dv1394_devfs_lock);
+		list_del(&p->list);
+		spin_unlock( &dv1394_devfs_lock);
+		kfree(p);
+	}
+}
+
+/*** IEEE1394 HPSB CALLBACKS ***********************************************/
+
+static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
+{
+	struct video_card *video;
+	unsigned long flags;
+	int i;
+
+	video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
+	if(!video) {
+		printk(KERN_ERR "dv1394: cannot allocate video_card\n");
+		goto err;
+	}
+	
+	memset(video, 0, sizeof(struct video_card));
+	
+	if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
+		printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n");
+		goto err_free;
+	}
+
+	
+	video->ohci = ohci;
+	/* lower 2 bits of id indicate which of four "plugs"
+	   per host */
+	video->id = ohci->id << 2; 
+
+	video->ohci_it_ctx = -1;
+	video->ohci_ir_ctx = -1;
+
+	video->ohci_IsoXmitContextControlSet = 0;
+	video->ohci_IsoXmitContextControlClear = 0;
+	video->ohci_IsoXmitCommandPtr = 0;
+	
+	video->ohci_IsoRcvContextControlSet = 0;
+	video->ohci_IsoRcvContextControlClear = 0;
+	video->ohci_IsoRcvCommandPtr = 0;
+	video->ohci_IsoRcvContextMatch = 0;
+		
+	video->n_frames = 0; /* flag that video is not initialized */
+	video->channel = 63; /* default to broadcast channel */
+	video->active_frame = -1;
+	
+	/* initialize the following for proc_fs */
+	video->pal_or_ntsc = format;
+	video->cip_n = 0; /* 0 = use builtin default */
+	video->cip_d = 0;
+	video->syt_offset = 0;
+	video->mode = mode;
+
+#ifdef CONFIG_PROC_FS
+	if ( dv1394_procfs_add_entry(video) < 0 )
+		goto err_free;
+#endif
+
+	for(i = 0; i < DV1394_MAX_FRAMES; i++)
+		video->frames[i] = NULL;
+
+	video->user_buf = NULL;
+	video->user_buf_size = 0;
+
+	clear_bit(0, &video->open);
+	spin_lock_init(&video->spinlock);
+	init_MUTEX(&video->sem);
+	init_waitqueue_head(&video->waitq);
+	video->fasync = NULL;
+
+	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	INIT_LIST_HEAD(&video->list);
+	list_add_tail(&video->list, &dv1394_cards);
+	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+	
+	if (format == DV1394_NTSC)
+		video->id |= mode;
+	else video->id |= 2 + mode;
+	
+	if (dv1394_devfs_add_entry(video) < 0)
+			goto err_free;
+
+	debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
+	
+	return 0;
+
+ err_free:
+	kfree(video);
+ err:
+	return -1;
+}
+
+static void dv1394_un_init(struct video_card *video)
+{
+	char buf[32];
+	
+	/* obviously nobody has the driver open at this point */
+	do_dv1394_shutdown(video, 1);
+	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
+	snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
+		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+		(video->mode == MODE_RECEIVE ? "in" : "out")
+		);
+	dv1394_devfs_del(buf);
+#ifdef CONFIG_PROC_FS
+	dv1394_procfs_del(buf);
+#endif
+	list_del(&video->list);
+	kfree(video);
+}
+
+	
+static void dv1394_remove_host (struct hpsb_host *host)
+{
+	struct ti_ohci *ohci;
+	struct video_card *video = NULL;
+	unsigned long flags;
+	struct list_head *lh;
+	char buf[32];
+	int	n;
+	
+	/* We only work with the OHCI-1394 driver */
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+		return;
+
+	ohci = (struct ti_ohci *)host->hostdata;
+
+
+	/* find the corresponding video_cards */
+	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	if(!list_empty(&dv1394_cards)) {
+		list_for_each(lh, &dv1394_cards) {
+			video = list_entry(lh, struct video_card, list);
+			if((video->id >> 2) == ohci->id)
+				dv1394_un_init(video);
+		}
+	}
+	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
+	n = (video->id >> 2);
+	snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n);
+	dv1394_devfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d/PAL", n);
+	dv1394_devfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d", n);
+	dv1394_devfs_del(buf);
+
+#ifdef CONFIG_PROC_FS
+	snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n);
+	dv1394_procfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d/PAL", n);
+	dv1394_procfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d", n);
+	dv1394_procfs_del(buf);
+#endif	
+}
+
+static void dv1394_add_host (struct hpsb_host *host)
+{
+	struct ti_ohci *ohci;
+	char buf[16];
+	struct dv1394_devfs_entry *devfs_entry;
+
+	/* We only work with the OHCI-1394 driver */
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+		return;
+
+	ohci = (struct ti_ohci *)host->hostdata;
+
+#ifdef CONFIG_PROC_FS
+{
+	struct dv1394_procfs_entry *p;
+	p = dv1394_procfs_find("dv");
+	if (p != NULL) {
+		snprintf(buf, sizeof(buf), "host%d", ohci->id);
+		dv1394_procfs_add_dir(buf, p, &p);
+		dv1394_procfs_add_dir("NTSC", p, NULL);
+		dv1394_procfs_add_dir("PAL", p, NULL);
+	}
+}
+#endif
+
+	devfs_entry = dv1394_devfs_find("dv");
+	if (devfs_entry != NULL) {
+		snprintf(buf, sizeof(buf), "host%d", ohci->id);
+		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
+		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
+		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
+	}
+	
+	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
+	dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
+	dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE);
+	dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
+}
+
+static struct hpsb_highlevel_ops hl_ops = {
+	add_host:	dv1394_add_host,
+	remove_host:	dv1394_remove_host,
+};
+
+
+/*** KERNEL MODULE HANDLERS ************************************************/
+
+MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
+MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
+MODULE_SUPPORTED_DEVICE("dv1394");
+MODULE_LICENSE("GPL");
+
+static void __exit dv1394_exit_module(void)
+{
+	hpsb_unregister_highlevel (hl_handle);
+	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+	dv1394_devfs_del("dv");
+#ifdef CONFIG_PROC_FS
+	dv1394_procfs_del("dv");
+#endif
+}
+
+static int __init dv1394_init_module(void)
+{
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
+				      THIS_MODULE, &dv1394_fops)) {
+		printk(KERN_ERR "dv1394: unable to register character device\n");
+		return -EIO;
+	}
+
+	if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) {
+		printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+		return -ENOMEM;
+	}
+
+#ifdef CONFIG_PROC_FS
+	if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+		dv1394_devfs_del("dv");
+		return -ENOMEM;
+	}
+#endif
+
+	hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops);
+	if (hl_handle == NULL) {
+		printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+		dv1394_devfs_del("dv");
+#ifdef CONFIG_PROC_FS
+		dv1394_procfs_del("dv");
+#endif
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+module_init(dv1394_init_module);
+module_exit(dv1394_exit_module);
+
diff -urN linux-2.4.19-pre4/drivers/ieee1394/dv1394.h linux-2.4.19-pre5/drivers/ieee1394/dv1394.h
--- linux-2.4.19-pre4/drivers/ieee1394/dv1394.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/dv1394.h	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,277 @@
+/*
+ * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
+ *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
+ *     receive, proc_fs by Dan Dennedy <dan@dennedy.org>
+ *
+ * based on:
+ *   video1394.h - driver for OHCI 1394 boards
+ *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DV_1394_H
+#define _DV_1394_H
+
+/* This is the public user-space interface. Try not to break it. */
+
+#define DV1394_API_VERSION 0x20011127
+
+/* ********************
+   **                **
+   **   DV1394 API   **
+   **                **
+   ********************
+
+   There are two methods of operating the DV1394 DV output device.
+
+   1)
+
+   The simplest is an interface based on write(): simply write
+   full DV frames of data to the device, and they will be transmitted
+   as quickly as possible. The FD may be set for non-blocking I/O,
+   in which case you can use select() or poll() to wait for output
+   buffer space.
+
+   To set the DV output parameters (e.g. whether you want NTSC or PAL
+   video), use the DV1394_INIT ioctl, passing in the parameters you
+   want in a struct dv1394_init.
+ 
+   Example 1:
+         To play a raw .DV file:   cat foo.DV > /dev/dv1394
+	 (cat will use write() internally)
+
+   Example 2:
+           static struct dv1394_init init = {
+	      0x63,        (broadcast channel)
+              4,           (four-frame ringbuffer)
+	      DV1394_NTSC, (send NTSC video)
+	      0, 0         (default empty packet rate)
+           }
+
+	   ioctl(fd, DV1394_INIT, &init);
+
+	   while(1) {
+	          read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
+		  write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
+           }
+
+   2)
+
+   For more control over buffering, and to avoid unnecessary copies
+   of the DV data, you can use the more sophisticated the mmap() interface. 
+   First, call the DV1394_INIT ioctl to specify your parameters, 
+   including the number of frames in the ringbuffer. Then, calling mmap() 
+   on the dv1394 device will give you direct access to the ringbuffer
+   from which the DV card reads your frame data.
+
+   The ringbuffer is simply one large, contiguous region of memory
+   containing two or more frames of packed DV data. Each frame of DV data
+   is 120000 bytes (NTSC) or 144000 bytes (PAL).
+
+   Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
+   ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
+   or select()/poll() to wait until the frames are transmitted. Next, you'll
+   need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
+   frames are clear (ready to be filled with new DV data). Finally, use
+   DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
+
+
+   Example: here is what a four-frame ringbuffer might look like
+            during DV transmission:
+
+
+         frame 0   frame 1   frame 2   frame 3
+
+	*--------------------------------------*
+        | CLEAR   | DV data | DV data | CLEAR  |
+        *--------------------------------------*
+                   <ACTIVE> 
+
+	transmission goes in this direction --->>>
+
+
+   The DV hardware is currently transmitting the data in frame 1.
+   Once frame 1 is finished, it will automatically transmit frame 2.
+   (if frame 2 finishes before frame 3 is submitted, the device
+   will continue to transmit frame 2, and will increase the dropped_frames
+   counter each time it repeats the transmission).
+
+ 
+   If you called DV1394_GET_STATUS at this instant, you would
+   receive the following values:
+   
+                  n_frames          = 4
+		  active_frame      = 1
+		  first_clear_frame = 3
+		  n_clear_frames    = 2
+
+   At this point, you should write new DV data into frame 3 and optionally
+   frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
+   it may transmit the new frames.
+
+*/
+
+
+/* maximum number of frames in the ringbuffer */
+#define DV1394_MAX_FRAMES 32
+
+/* number of *full* isochronous packets per DV frame */
+#define DV1394_NTSC_PACKETS_PER_FRAME 250
+#define DV1394_PAL_PACKETS_PER_FRAME  300
+
+/* size of one frame's worth of DV data, in bytes */
+#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
+#define DV1394_PAL_FRAME_SIZE  (480 * DV1394_PAL_PACKETS_PER_FRAME)
+
+
+/* ioctl() commands */
+
+enum {
+	/* I don't like using 0 as a valid ioctl() */
+	DV1394_INVALID = 0,
+
+
+	/* get the driver ready to transmit video.
+	   pass a struct dv1394_init* as the parameter (see below),
+	   or NULL to get default parameters */
+	DV1394_INIT,
+
+
+	/* stop transmitting video and free the ringbuffer */
+	DV1394_SHUTDOWN,
+
+
+	/* submit N new frames to be transmitted, where
+	   the index of the first new frame is first_clear_buffer,
+	   and the index of the last new frame is
+	   (first_clear_buffer + N) % n_frames */
+	DV1394_SUBMIT_FRAMES,
+
+
+	/* block until N buffers are clear (pass N as the parameter)
+	   Because we re-transmit the last frame on underrun, there
+	   will at most be n_frames - 1 clear frames at any time */
+	DV1394_WAIT_FRAMES,
+
+	/* capture new frames that have been received, where
+	   the index of the first new frame is first_clear_buffer,
+	   and the index of the last new frame is
+	   (first_clear_buffer + N) % n_frames */
+	DV1394_RECEIVE_FRAMES,
+
+
+	DV1394_START_RECEIVE,
+
+
+	/* pass a struct dv1394_status* as the parameter (see below) */
+	DV1394_GET_STATUS,
+};
+
+
+
+enum pal_or_ntsc {
+	DV1394_NTSC = 0,
+	DV1394_PAL
+};
+
+
+
+
+/* this is the argument to DV1394_INIT */
+struct dv1394_init {
+	/* DV1394_API_VERSION */
+	unsigned int api_version;
+	
+	/* isochronous transmission channel to use */
+	unsigned int channel;
+
+	/* number of frames in the ringbuffer. Must be at least 2
+	   and at most DV1394_MAX_FRAMES. */
+	unsigned int n_frames;
+
+	/* send/receive PAL or NTSC video format */
+	enum pal_or_ntsc format;
+
+	/* the following are used only for transmission */
+ 
+	/* set these to zero unless you want a
+	   non-default empty packet rate (see below) */
+	unsigned long cip_n;
+	unsigned long cip_d;
+
+	/* set this to zero unless you want a
+	   non-default SYT cycle offset (default = 3 cycles) */
+	unsigned int syt_offset;
+};
+
+/* Q: What are cip_n and cip_d? */
+
+/*
+  A: DV video streams do not utilize 100% of the potential bandwidth offered
+  by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
+  DV devices must periodically insert empty packets into the 1394 data stream.
+  Typically there is one empty packet per 14-16 data-carrying packets.
+
+  Some DV devices will accept a wide range of empty packet rates, while others
+  require a precise rate. If the dv1394 driver produces empty packets at
+  a rate that your device does not accept, you may see ugly patterns on the
+  DV output, or even no output at all.
+
+  The default empty packet insertion rate seems to work for many people; if
+  your DV output is stable, you can simply ignore this discussion. However,
+  we have exposed the empty packet rate as a parameter to support devices that
+  do not work with the default rate. 
+
+  The decision to insert an empty packet is made with a numerator/denominator
+  algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
+  You can alter the empty packet rate by passing non-zero values for cip_n
+  and cip_d to the INIT ioctl.
+  
+ */
+
+
+
+struct dv1394_status {
+	/* this embedded init struct returns the current dv1394
+	   parameters in use */
+	struct dv1394_init init;
+
+	/* the ringbuffer frame that is currently being
+	   displayed. (-1 if the device is not transmitting anything) */
+	int active_frame;
+
+	/* index of the first buffer (ahead of active_frame) that
+	   is ready to be filled with data */
+	unsigned int first_clear_frame;
+
+	/* how many buffers, including first_clear_buffer, are
+	   ready to be filled with data */
+	unsigned int n_clear_frames;
+
+	/* how many times the DV output has underflowed
+	   since the last call to DV1394_GET_STATUS */
+	unsigned int dropped_frames;
+
+	/* N.B. The dropped_frames counter is only a lower bound on the actual
+	   number of dropped frames, with the special case that if dropped_frames
+	   is zero, then it is guaranteed that NO frames have been dropped
+	   since the last call to DV1394_GET_STATUS.
+	*/
+};
+
+
+#endif /* _DV_1394_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/eth1394.c linux-2.4.19-pre5/drivers/ieee1394/eth1394.c
--- linux-2.4.19-pre4/drivers/ieee1394/eth1394.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/eth1394.c	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,741 @@
+/*
+ * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem
+ * 
+ * Copyright (C) 2001 Ben Collins <bcollins@debian.org>
+ *               2000 Bonin Franck <boninf@free.fr>
+ *
+ * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* State of this driver:
+ *
+ * This driver intends to support RFC 2734, which describes a method for
+ * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver
+ * will ultimately support that method, but currently falls short in
+ * several areas. A few issues are:
+ *
+ *   - Does not support send/recv over Async streams using GASP
+ *     packet formats, as per the RFC for ARP requests.
+ *   - Does not yet support fragmented packets.
+ *   - Relies on hardware address being equal to the nodeid for some things.
+ *   - Does not support multicast
+ *   - Hardcoded address for sending packets, instead of using discovery
+ *     (ARP, see first item)
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <asm/delay.h>
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <net/arp.h>
+
+#include "ieee1394_types.h"
+#include "ieee1394_core.h"
+#include "ieee1394_transactions.h"
+#include "ieee1394.h"
+#include "highlevel.h"
+#include "eth1394.h"
+
+#define ETH1394_PRINT_G(level, fmt, args...) \
+	printk(level ETHER1394_DRIVER_NAME": "fmt, ## args)
+
+#define ETH1394_PRINT(level, dev_name, fmt, args...) \
+	printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args)
+
+#define DEBUG(fmt, args...) \
+	printk(KERN_ERR fmt, ## args)
+
+static char version[] __devinitdata =
+	"eth1394.c:v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>";
+
+/* Our ieee1394 highlevel driver */
+#define ETHER1394_DRIVER_NAME "ether1394"
+
+static kmem_cache_t *packet_task_cache;
+static struct hpsb_highlevel *hl_handle = NULL;
+
+/* Card handling */
+static LIST_HEAD (host_info_list);
+static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
+
+/* Use common.lf to determine header len */
+static int hdr_type_len[] = {
+	sizeof (struct eth1394_uf_hdr),
+	sizeof (struct eth1394_ff_hdr),
+	sizeof (struct eth1394_sf_hdr),
+	sizeof (struct eth1394_sf_hdr)
+};
+
+MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
+MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
+
+/* Find our host_info struct for a given host pointer. Must be called
+ * under spinlock.  */
+static inline struct host_info *find_host_info (struct hpsb_host *host)
+{
+	struct list_head *lh;
+	struct host_info *hi;
+
+	lh = host_info_list.next;
+	while (lh != &host_info_list) {
+		hi = list_entry (lh, struct host_info, list);
+
+		if (hi->host == host)
+			return hi;
+
+		lh = lh->next;
+	}
+	return NULL;
+}
+
+/* Find the network device for our host */
+static inline struct net_device *ether1394_find_dev (struct hpsb_host *host)
+{
+	struct host_info *hi;
+
+	spin_lock_irq (&host_info_lock);
+	hi = find_host_info (host);
+	spin_unlock_irq (&host_info_lock);
+
+	if (hi == NULL)
+		return NULL;
+
+	return hi->dev;
+}
+
+/* This is called after an "ifup" */
+static int ether1394_open (struct net_device *dev)
+{
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+
+	/* Set the spinlock before grabbing IRQ! */
+	priv->lock = SPIN_LOCK_UNLOCKED;
+
+	netif_start_queue (dev);
+	return 0;
+}
+
+/* This is called after an "ifdown" */
+static int ether1394_stop (struct net_device *dev)
+{
+	netif_stop_queue (dev);
+	return 0;
+}
+
+/* Return statistics to the caller */
+static struct net_device_stats *ether1394_stats (struct net_device *dev)
+{
+	return &(((struct eth1394_priv *)dev->priv)->stats);
+}
+
+/* What to do if we timeout. I think a host reset is probably in order, so
+ * that's what we do. Should we increment the stat counters too?  */
+static void ether1394_tx_timeout (struct net_device *dev)
+{
+	ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n",
+		       ((struct eth1394_priv *)(dev->priv))->host->driver->name);
+
+	highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host);
+
+	netif_wake_queue (dev);
+}
+
+/* We need to encapsulate the standard header with our own. We use the
+ * ethernet header's proto for our own.
+ *
+ * XXX: This is where we need to create a list of skb's for fragmented
+ * packets.  */
+static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev,
+			    int proto)
+{
+	union eth1394_hdr *hdr =
+		(union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]);
+
+	hdr->common.lf = ETH1394_HDR_LF_UF;
+	hdr->words.word1 = htons(hdr->words.word1);
+	hdr->uf.ether_type = proto;
+
+	return;
+}
+
+/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the
+ * entire arphdr) is the same format as the ip1394 header, so they
+ * overlap. The rest needs to be munged a bit. The remainder of the
+ * arphdr is formatted based on hwaddr len and ipaddr len. We know what
+ * they'll be, so it's easy to judge.  */
+static inline void ether1394_arp_to_1394arp (struct sk_buff *skb, struct net_device *dev)
+{
+	struct eth1394_priv *priv =
+		(struct eth1394_priv *)(dev->priv);
+	u16 phy_id = priv->host->node_id & NODE_MASK;
+
+	unsigned char *arp_ptr = (unsigned char *)skb->data;
+	struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
+	unsigned char arp_data[2*(dev->addr_len+4)];
+
+	/* Copy the main data that we need */
+	arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data));
+
+	/* Extend the buffer enough for our new header */
+	skb_put (skb, sizeof (struct eth1394_arp) -
+		 (sizeof (arp_data) + sizeof (struct arphdr)));
+
+#define PROCESS_MEMBER(ptr,val,len) \
+  memcpy (val, ptr, len); ptr += len
+	arp_ptr += arp1394->hw_addr_len;
+	PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len);
+	arp_ptr += arp1394->hw_addr_len;
+	PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len);
+#undef PROCESS_MEMBER
+
+	/* Now add our own flavor of arp header fields to the orig one */
+	arp1394->hw_addr_len	= IP1394_HW_ADDR_LEN;
+	arp1394->hw_type	= __constant_htons (ARPHRD_IEEE1394);
+	arp1394->s_uniq_id	= cpu_to_le64 (priv->eui[phy_id]);
+	arp1394->max_rec	= priv->max_rec[phy_id];
+	arp1394->sspd		= priv->sspd[phy_id];
+	arp1394->fifo_hi	= htons (priv->fifo_hi[phy_id]);
+	arp1394->fifo_lo	= htonl (priv->fifo_lo[phy_id]);
+
+	return;
+}
+
+static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > ETHER1394_REGION_ADDR_LEN))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static inline void ether1394_register_limits (int nodeid, unsigned char max_rec,
+				       unsigned char sspd, u64 eui, u16 fifo_hi,
+				       u32 fifo_lo, struct eth1394_priv *priv)
+{
+	int i;
+
+	if (nodeid < 0 || nodeid >= ALL_NODES) {
+		ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid);
+		return;
+	}
+
+	priv->max_rec[nodeid]	= max_rec;
+	priv->sspd[nodeid]	= sspd;
+	priv->fifo_hi[nodeid]	= fifo_hi;
+	priv->fifo_lo[nodeid]	= fifo_lo;
+	priv->eui[nodeid]	= eui;
+
+	/* 63 is used for broadcasts to all hosts. It is equal to the
+	 * minimum of all registered nodes. A registered node is one with
+	 * a nonzero offset. Set the values rediculously high to start. We
+	 * know we have atleast one to change the default to.  */
+	sspd = 0xff;
+	max_rec = 0xff;
+	for (i = 0; i < ALL_NODES; i++) {
+		if (!priv->fifo_hi && !priv->fifo_lo) continue; /* Unregistered */
+		if (priv->max_rec[i] < max_rec) max_rec = priv->max_rec[i];
+		if (priv->sspd[i] < sspd) sspd = priv->sspd[i];
+	}
+
+	priv->max_rec[ALL_NODES] = max_rec;
+	priv->sspd[ALL_NODES] = sspd;
+
+	return;
+}
+
+static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
+{
+	int flags;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	int phy_id = priv->host->node_id & NODE_MASK;
+
+	spin_lock_irqsave (&priv->lock, flags);
+
+	/* Clear the speed/payload/offset tables */
+	memset (priv->max_rec, 0, sizeof (priv->max_rec));
+	memset (priv->sspd, 0, sizeof (priv->sspd));
+	memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi));
+	memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo));
+
+	/* Register our limits now */
+	ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf,
+				   priv->host->speed_map[(phy_id << 6) + phy_id],
+				   (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) |
+				   be32_to_cpu(priv->host->csr.rom[4])),
+				   ETHER1394_REGION_ADDR >> 32,
+				   ETHER1394_REGION_ADDR & 0xffffffff, priv);
+
+	/* We'll use our max_rec as the default mtu */
+	if (set_mtu)
+		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr);
+
+	/* Set our hardware address while we're at it */
+	*(nodeid_t *)dev->dev_addr = htons (priv->host->node_id);
+
+	spin_unlock_irqrestore (&priv->lock, flags);
+}
+
+static int ether1394_tx (struct sk_buff *skb, struct net_device *dev);
+
+/* This function is called by register_netdev */
+static int ether1394_init_dev (struct net_device *dev)
+{
+	/* Our functions */
+	dev->open		= ether1394_open;
+	dev->stop		= ether1394_stop;
+	dev->hard_start_xmit	= ether1394_tx;
+	dev->get_stats		= ether1394_stats;
+	dev->tx_timeout		= ether1394_tx_timeout;
+	dev->change_mtu		= ether1394_change_mtu;
+
+	/* Some constants */
+	dev->watchdog_timeo	= ETHER1394_TIMEOUT;
+	dev->flags		= IFF_BROADCAST; /* TODO: Support MCAP */
+	dev->features		= NETIF_F_NO_CSUM|NETIF_F_SG|NETIF_F_HIGHDMA|NETIF_F_FRAGLIST;
+	dev->addr_len		= 2;
+
+	ether1394_reset_priv (dev, 1);
+
+	return 0;
+}
+
+/*
+ * This function is called every time a card is found. It is generally called
+ * when the module is installed. This is where we add all of our ethernet
+ * devices. One for each host.
+ */
+static void ether1394_add_host (struct hpsb_host *host)
+{
+	struct host_info *hi = NULL;
+	struct net_device *dev = NULL;
+	struct eth1394_priv *priv;
+	static int version_printed = 0;
+
+	if (version_printed++ == 0)
+		ETH1394_PRINT_G (KERN_INFO, "%s\n", version);
+
+	dev = alloc_etherdev(sizeof (struct eth1394_priv));
+
+	if (dev == NULL)
+		goto out;
+
+	SET_MODULE_OWNER(dev);
+
+	dev->init = ether1394_init_dev;
+
+	priv = (struct eth1394_priv *)dev->priv;
+
+	priv->host = host;
+
+	hi = (struct host_info *)kmalloc (sizeof (struct host_info),
+					  GFP_KERNEL);
+
+	if (hi == NULL)
+		goto out;
+
+	if (register_netdev (dev)) {
+		ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
+		kfree (dev);
+		return;
+	}
+
+	ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n",
+		       host->driver->name);
+
+	INIT_LIST_HEAD (&hi->list);
+	hi->host = host;
+	hi->dev = dev;
+
+	spin_lock_irq (&host_info_lock);
+	list_add_tail (&hi->list, &host_info_list);
+	spin_unlock_irq (&host_info_lock);
+
+	return;
+
+out:
+	if (dev != NULL)
+		kfree (dev);
+	ETH1394_PRINT_G (KERN_ERR, "Out of memory\n");
+
+	return;
+}
+
+/* Remove a card from our list */
+static void ether1394_remove_host (struct hpsb_host *host)
+{
+	struct host_info *hi;
+
+	spin_lock_irq (&host_info_lock);
+	hi = find_host_info (host);
+	if (hi != NULL) {
+		unregister_netdev (hi->dev);
+		kfree (hi->dev);
+		list_del (&hi->list);
+		kfree (hi);
+	}
+	spin_unlock_irq (&host_info_lock);
+
+	return;
+}
+
+/* A reset has just arisen */
+static void ether1394_host_reset (struct hpsb_host *host)
+{
+	struct net_device *dev = ether1394_find_dev(host);
+
+	/* This can happen for hosts that we don't use */
+	if (dev == NULL)
+		return;
+
+	/* Reset our private host data, but not our mtu */
+	netif_stop_queue (dev);
+	ether1394_reset_priv (dev, 0);
+	netif_wake_queue (dev);
+}
+
+/* Copied from net/ethernet/eth.c */
+static inline unsigned short ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ethhdr *eth;
+	unsigned char *rawp;
+
+	skb->mac.raw = skb->data;
+	skb_pull (skb, ETH_HLEN);
+	eth = skb->mac.ethernet;
+#if 0
+	if(*eth->h_dest & 1) {
+		if(memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	} else {
+		if(memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
+			skb->pkt_type = PACKET_OTHERHOST;
+        }
+#endif
+	if (ntohs (eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+        if (*(unsigned short *)rawp == 0xFFFF)
+		return htons (ETH_P_802_3);
+
+        return htons (ETH_P_802_2);
+}
+
+/* Parse an encapsulated IP1394 header into an ethernet frame packet.
+ * We also perform ARP translation here, if need be.  */
+static inline unsigned short ether1394_parse_encap (struct sk_buff *skb, struct net_device *dev,
+					     nodeid_t srcid, nodeid_t destid)
+{
+	union eth1394_hdr *hdr = (union eth1394_hdr *)skb->data;
+	unsigned char src_hw[ETH_ALEN], dest_hw[ETH_ALEN];
+	unsigned short ret = 0;
+
+	/* Setup our hw addresses. We use these to build the
+	 * ethernet header.  */
+	*(u16 *)dest_hw = htons(destid);
+	*(u16 *)src_hw = htons(srcid);
+
+	/* Remove the encapsulation header */
+	hdr->words.word1 = ntohs(hdr->words.word1);
+	skb_pull (skb, hdr_type_len[hdr->common.lf]);
+
+	/* If this is an ARP packet, convert it. First, we want to make
+	 * use of some of the fields, since they tell us a little bit
+	 * about the sending machine.  */
+	if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
+		int flags;
+		u16 phy_id = srcid & NODE_MASK;
+		struct eth1394_priv *priv =
+			(struct eth1394_priv *)dev->priv;
+		struct eth1394_arp arp1394;
+		struct arphdr *arp = (struct arphdr *)skb->data;
+		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+
+		memcpy (&arp1394, arp, sizeof (struct eth1394_arp));
+
+		/* Update our speed/payload/fifo_offset table */
+		spin_lock_irqsave (&priv->lock, flags);
+		ether1394_register_limits (phy_id, arp1394.max_rec, arp1394.sspd,
+					   le64_to_cpu (arp1394.s_uniq_id),
+					   ntohs (arp1394.fifo_hi),
+					   ntohl (arp1394.fifo_lo), priv);
+		spin_unlock_irqrestore (&priv->lock, flags);
+
+#define PROCESS_MEMBER(ptr,val,len) \
+  ptr = memcpy (ptr, val, len) + len
+                PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len);
+                PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4);
+                PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len);
+                PROCESS_MEMBER (arp_ptr, &arp1394.tip, 4);
+#undef PROCESS_MEMBER
+
+		arp->ar_hln = dev->addr_len;
+		arp->ar_hrd = __constant_htons (ARPHRD_ETHER);
+
+		skb_trim (skb, sizeof (struct arphdr) + 2*(dev->addr_len+4));
+	}
+
+	/* Now add the ethernet header. */
+	if (dev->hard_header (skb, dev, __constant_ntohs (hdr->uf.ether_type),
+			      dest_hw, src_hw, skb->len) >= 0)
+		ret = ether1394_type_trans(skb, dev);
+
+	return ret;
+}
+
+/* Packet reception. We convert the IP1394 encapsulation header to an
+ * ethernet header, and fill it with some of our other fields. This is
+ * an incoming packet from the 1394 bus.  */
+static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
+			    quadlet_t *data, u64 addr, unsigned int len)
+{
+	struct sk_buff *skb;
+	char *buf = (char *)data;
+	int flags;
+	struct net_device *dev = ether1394_find_dev (host);
+	struct eth1394_priv *priv;
+
+	if (dev == NULL) {
+		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n",
+				 host);
+		return RCODE_ADDRESS_ERROR;
+	}
+
+	priv = (struct eth1394_priv *)dev->priv;
+
+	/* A packet has been received by the ieee1394 bus. Build an skbuff
+	 * around it so we can pass it to the high level network layer. */
+
+	skb = dev_alloc_skb (len + dev->hard_header_len + 15);
+	if (!skb) {
+		HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+		priv->stats.rx_dropped++;
+		return RCODE_ADDRESS_ERROR;
+	}
+
+	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+	memcpy (skb_put (skb, len), buf, len);
+
+	/* Write metadata, and then pass to the receive level */
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;	/* don't check it */
+
+	/* Parse the encapsulation header. This actually does the job of
+	 * converting to an ethernet frame header, aswell as arp
+	 * conversion if needed. ARP conversion is easier in this
+	 * direction, since we are using ethernet as our backend.  */
+	skb->protocol = ether1394_parse_encap (skb, dev, srcid, destid);
+
+	spin_lock_irqsave (&priv->lock, flags);
+	if (!skb->protocol) {
+		priv->stats.rx_errors++;
+		priv->stats.rx_dropped++;
+		dev_kfree_skb_any(skb);
+		goto bad_proto;
+	}
+
+	netif_stop_queue(dev);
+	if (netif_rx (skb) == NET_RX_DROP) {
+		priv->stats.rx_errors++;
+		priv->stats.rx_dropped++;
+		goto bad_proto;
+	}
+
+	/* Statistics */
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += skb->len;
+
+bad_proto:
+	netif_start_queue(dev);
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	dev->last_rx = jiffies;
+
+	return RCODE_COMPLETE;
+}
+
+/* This function is our scheduled write */
+static void hpsb_write_sched (void *__ptask)
+{
+	struct packet_task *ptask = (struct packet_task *)__ptask;
+	struct sk_buff *skb = ptask->skb;
+	struct net_device *dev = ptask->skb->dev;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	int flags;
+
+	/* Statistics */
+	spin_lock_irqsave (&priv->lock, flags);
+	if (!hpsb_write(priv->host, ptask->dest_node,
+			get_hpsb_generation(priv->host),
+			ptask->addr, (quadlet_t *)skb->data, skb->len)) {
+		priv->stats.tx_bytes += skb->len;
+		priv->stats.tx_packets++;
+	} else {
+		//printk("Failed in hpsb_write_sched\n");
+		priv->stats.tx_dropped++;
+		priv->stats.tx_errors++;
+		if (netif_queue_stopped (dev))
+			netif_wake_queue (dev);
+	}
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	dev->trans_start = jiffies;
+	dev_kfree_skb(skb);
+	kmem_cache_free(packet_task_cache, ptask);
+
+	return;
+}
+
+/* Transmit a packet (called by kernel) */
+static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
+{
+	int kmflags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+	struct ethhdr *eth;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	int proto, flags;
+	nodeid_t dest_node;
+	u64 addr;
+	struct packet_task *ptask = NULL;
+	int ret = 0;
+
+	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* Get rid of the ethernet header, but save a pointer */
+	eth = (struct ethhdr *)skb->data;
+	skb_pull (skb, ETH_HLEN);
+
+	/* Save the destination id, and proto for our encapsulation, then
+	 * toss the ethernet header aside like the cheap whore it is.  */
+	dest_node = ntohs (*(nodeid_t *)(eth->h_dest));
+	proto = eth->h_proto;
+
+	/* If this is an ARP packet, convert it */
+	if (proto == __constant_htons (ETH_P_ARP))
+		ether1394_arp_to_1394arp (skb, dev);
+
+	/* Now add our encapsulation header */
+	ether1394_encapsulate (skb, dev, proto);
+
+	/* TODO: The above encapsulate function needs to recognize when a
+	 * packet needs to be split for a specified node. It should create
+	 * a list of skb's that we could then iterate over for the below
+	 * call to schedule our writes.  */
+
+	/* XXX: Right now we accept that we don't exactly follow RFC. When
+	 * we do, we will send ARP requests via GASP format, and so we wont
+	 * need this hack.  */
+
+	spin_lock_irqsave (&priv->lock, flags);
+	addr = (u64)priv->fifo_hi[dest_node & NODE_MASK] << 32 |
+		priv->fifo_lo[dest_node & NODE_MASK];
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	if (!addr)
+		addr = ETHER1394_REGION_ADDR;
+
+	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
+	if (ptask == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	ptask->skb = skb;
+	ptask->addr = addr;
+	ptask->dest_node = dest_node;
+	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
+	schedule_task(&ptask->tq);
+
+	return 0;
+fail:
+	printk("Failed in ether1394_tx\n");
+
+	if (skb != NULL)
+		dev_kfree_skb (skb);
+
+	spin_lock_irqsave (&priv->lock, flags);
+	priv->stats.tx_dropped++;
+	priv->stats.tx_errors++;
+	if (netif_queue_stopped (dev))
+		netif_wake_queue (dev);
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	return ret;
+}
+
+/* Function for incoming 1394 packets */
+static struct hpsb_address_ops addr_ops = {
+	write:		ether1394_write,
+};
+
+/* Ieee1394 highlevel driver functions */
+static struct hpsb_highlevel_ops hl_ops = {
+	add_host:	ether1394_add_host,
+	remove_host:	ether1394_remove_host,
+	host_reset:	ether1394_host_reset,
+};
+
+static int __init ether1394_init_module (void)
+{
+	packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task),
+					      0, 0, NULL, NULL);
+
+	/* Register ourselves as a highlevel driver */
+	hl_handle = hpsb_register_highlevel (ETHER1394_DRIVER_NAME, &hl_ops);
+
+	if (hl_handle == NULL) {
+		ETH1394_PRINT_G (KERN_ERR, "No more memory for driver\n");
+		return -ENOMEM;
+	}
+
+	hpsb_register_addrspace (hl_handle, &addr_ops, ETHER1394_REGION_ADDR,
+				 ETHER1394_REGION_ADDR_END);
+
+	return 0;
+}
+
+static void __exit ether1394_exit_module (void)
+{
+	hpsb_unregister_highlevel (hl_handle);
+	kmem_cache_destroy(packet_task_cache);
+}
+
+module_init(ether1394_init_module);
+module_exit(ether1394_exit_module);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/eth1394.h linux-2.4.19-pre5/drivers/ieee1394/eth1394.h
--- linux-2.4.19-pre4/drivers/ieee1394/eth1394.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/ieee1394/eth1394.h	Fri Mar 29 14:49:31 2002
@@ -0,0 +1,190 @@
+/*
+ * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
+ *
+ * Copyright (C) 2000 Bonin Franck <boninf@free.fr>
+ *           (C) 2001 Ben Collins <bcollins@debian.org>
+ *
+ * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ETH1394_H
+#define __ETH1394_H
+
+/* Register for incoming packets. This is 8192 bytes, which supports up to
+ * 1600mbs. We'll need to change this if that ever becomes "small" :)  */
+#define ETHER1394_REGION_ADDR_LEN	8192
+#define ETHER1394_REGION_ADDR		0xfffff0200000ULL
+#define ETHER1394_REGION_ADDR_END	(ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
+
+/* Node set == 64 */
+#define NODE_SET			(ALL_NODES + 1)
+
+/* Private structure for our ethernet driver */
+struct eth1394_priv {
+	struct net_device_stats stats;	/* Device stats			 */
+	struct hpsb_host *host;		/* The card for this dev	 */
+	unsigned char max_rec[NODE_SET];/* Max payload per node		 */
+	unsigned char sspd[NODE_SET];	/* Max speed per node		 */
+	u16 fifo_hi[ALL_NODES];		/* 16bit hi fifo offset per node */
+	u32 fifo_lo[ALL_NODES];		/* 32bit lo fifo offset per node */
+	u64 eui[ALL_NODES];		/* EUI-64 per node		 */
+	spinlock_t lock;		/* Private lock			 */
+};
+
+struct host_info {
+	struct list_head list;
+	struct hpsb_host *host;
+	struct net_device *dev;
+};
+
+/* This is our task struct. It's used for the complete_tq callback.  */
+struct packet_task {
+	struct sk_buff *skb;	/* Socket buffer we are sending */
+	nodeid_t dest_node;	/* Destination of the packet */
+	u64 addr;		/* Address */
+	struct tq_struct tq;	/* The task */
+};
+
+/* IP1394 headers */
+#include <asm/byteorder.h>
+
+/* Unfragmented */
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_uf_hdr {
+	u8 lf:2;
+	u16 res:14;
+	u16 ether_type;		/* Ethernet packet type */
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_uf_hdr {
+	u16 res:14;
+	u8 lf:2;
+	u16 ether_type;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+/* First fragment */
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_ff_hdr {
+	u8 lf:2;
+	u8 res1:2;
+	u16 dg_size:12;		/* Datagram size */
+	u16 ether_type;		/* Ethernet packet type */
+	u16 dgl;		/* Datagram label */
+	u16 res2;
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_ff_hdr {
+	u16 dg_size:12;
+	u8 res1:2;
+	u8 lf:2;
+	u16 ether_type;
+	u16 dgl;
+	u16 res2;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+/* XXX: Subsequent fragments, including last */
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_sf_hdr {
+	u8 lf:2;
+	u8 res1:2;
+	u16 dg_size:12;		/* Datagram size */
+	u8 res2:6;
+	u16 fg_off:10;		/* Fragment offset */
+	u16 dgl;		/* Datagram label */
+	u16 res3;
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_sf_hdr {
+	u16 dg_size:12;
+	u8 res1:2;
+	u8 lf:2;
+	u16 fg_off:10;
+	u8 res2:6;
+	u16 dgl;
+	u16 res3;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_common_hdr {
+	u8 lf:2;
+	u16 pad1:14;
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_common_hdr {
+	u16 pad1:14;
+	u8 lf:2;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+struct eth1394_hdr_words {
+	u16 word1;
+	u16 word2;
+	u16 word3;
+	u16 word4;
+};
+
+union eth1394_hdr {
+	struct eth1394_common_hdr common;
+	struct eth1394_uf_hdr uf;
+	struct eth1394_ff_hdr ff;
+	struct eth1394_sf_hdr sf;
+	struct eth1394_hdr_words words;
+};
+
+/* End of IP1394 headers */
+
+/* Fragment types */
+#define ETH1394_HDR_LF_UF	0	/* unfragmented		*/
+#define ETH1394_HDR_LF_FF	1	/* first fragment	*/
+#define ETH1394_HDR_LF_LF	2	/* last fragment	*/
+#define ETH1394_HDR_LF_IF	3	/* interior fragment	*/
+
+#define IP1394_HW_ADDR_LEN	16	/* As per RFC		*/
+
+/* Our arp packet (ARPHRD_IEEE1394) */
+struct eth1394_arp {
+	u16 hw_type;		/* 0x0018	*/
+	u16 proto_type;		/* 0x0806	*/
+	u8 hw_addr_len;		/* 16 		*/
+	u8 ip_addr_len;		/* 4		*/
+	u16 opcode;		/* ARP Opcode	*/
+	/* Above is exactly the same format as struct arphdr */
+
+	u64 s_uniq_id;		/* Sender's 64bit EUI			*/
+	u8 max_rec;		/* Sender's max packet size		*/
+	u8 sspd;		/* Sender's max speed			*/
+	u16 fifo_hi;		/* hi 16bits of sender's FIFO addr	*/
+	u32 fifo_lo;		/* lo 32bits of sender's FIFO addr	*/
+	u32 sip;		/* Sender's IP Address			*/
+	u32 tip;		/* IP Address of requested hw addr	*/
+};
+
+/* Network timeout */
+#define ETHER1394_TIMEOUT	100000
+
+#endif /* __ETH1394_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/highlevel.c linux-2.4.19-pre5/drivers/ieee1394/highlevel.c
--- linux-2.4.19-pre4/drivers/ieee1394/highlevel.c	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/highlevel.c	Fri Mar 29 14:49:31 2002
@@ -44,10 +44,11 @@
         hl->op = ops;
 
         write_lock_irq(&hl_drivers_lock);
-        hl_all_hosts(hl, 1);
         list_add_tail(&hl->hl_list, &hl_drivers);
         write_unlock_irq(&hl_drivers_lock);
 
+        hl_all_hosts(hl->op->add_host);
+
         return hl;
 }
 
@@ -73,9 +74,11 @@
 
         write_lock_irq(&hl_drivers_lock);
         list_del(&hl->hl_list);
-        hl_all_hosts(hl, 0);
         write_unlock_irq(&hl_drivers_lock);
 
+        if (hl->op->remove_host)
+		hl_all_hosts(hl->op->remove_host);
+
         kfree(hl);
 }
 
@@ -87,7 +90,7 @@
         int retval = 0;
 
         if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
-                HPSB_ERR(__FUNCTION__ " called with invalid addresses");
+                HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
                 return 0;
         }
 
@@ -131,12 +134,12 @@
                          unsigned int channel)
 {
         if (channel > 63) {
-                HPSB_ERR(__FUNCTION__ " called with invalid channel");
+                HPSB_ERR("%s called with invalid channel", __FUNCTION__);
                 return;
         }
 
         if (host->iso_listen_count[channel]++ == 0) {
-                host->template->devctl(host, ISO_LISTEN_CHANNEL, channel);
+                host->ops->devctl(host, ISO_LISTEN_CHANNEL, channel);
         }
 }
 
@@ -144,46 +147,58 @@
                            unsigned int channel)
 {
         if (channel > 63) {
-                HPSB_ERR(__FUNCTION__ " called with invalid channel");
+                HPSB_ERR("%s called with invalid channel", __FUNCTION__);
                 return;
         }
 
         if (--host->iso_listen_count[channel] == 0) {
-                host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
+                host->ops->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
         }
 }
 
 
-#define DEFINE_MULTIPLEXER(Function)			\
-void highlevel_##Function(struct hpsb_host *host)	\
-{							\
-	struct list_head *lh;				\
-	void (*funcptr)(struct hpsb_host*);		\
-	read_lock(&hl_drivers_lock);			\
-	list_for_each(lh, &hl_drivers) {		\
-		funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) \
-				->op->Function;		\
-		if (funcptr) funcptr(host);		\
-	}						\
-	read_unlock(&hl_drivers_lock);			\
-}
-
-DEFINE_MULTIPLEXER(add_host)
-DEFINE_MULTIPLEXER(remove_host)
-DEFINE_MULTIPLEXER(host_reset)
-#undef DEFINE_MULTIPLEXER
-
-/* Add one host to our list */
-void highlevel_add_one_host (struct hpsb_host *host)
-{
-	if (host->template->initialize_host)
-		if (!host->template->initialize_host(host))
-			goto fail;
-	host->initialized = 1;
-	highlevel_add_host (host);
-	hpsb_reset_bus (host, LONG_RESET);
-fail:
-	host->template->number_of_hosts++;
+void highlevel_add_host(struct hpsb_host *host)
+{
+        struct list_head *entry;
+        struct hpsb_highlevel *hl;
+
+        read_lock(&hl_drivers_lock);
+        list_for_each(entry, &hl_drivers) {
+                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+		hl->op->add_host(host);
+        }
+        read_unlock(&hl_drivers_lock);
+}
+
+void highlevel_remove_host(struct hpsb_host *host)
+{
+        struct list_head *entry;
+        struct hpsb_highlevel *hl;
+
+        write_lock_irq(&hl_drivers_lock);
+	list_for_each(entry, &hl_drivers) {
+                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+		if (hl->op->remove_host)
+			hl->op->remove_host(host);
+        }
+        write_unlock_irq(&hl_drivers_lock);
+}
+
+void highlevel_host_reset(struct hpsb_host *host)
+{
+        struct list_head *entry;
+        struct hpsb_highlevel *hl;
+
+	read_lock(&hl_drivers_lock);
+	list_for_each(entry, &hl_drivers) {
+                hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+
+                if (hl->op->host_reset)
+                        hl->op->host_reset(host);
+        }
+	read_unlock(&hl_drivers_lock);
 }
 
 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
@@ -242,12 +257,11 @@
 
         while (as->start <= addr) {
                 if (as->end > addr) {
-                        partlength = MIN((unsigned int)(as->end - addr),
-                                         length);
+                        partlength = min(as->end - addr, (u64) length);
 
                         if (as->op->read != NULL) {
-                                rcode = as->op->read(host, nodeid, buffer, addr,
-                                                     partlength);
+                                rcode = as->op->read(host, nodeid, buffer,
+						     addr, partlength);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -288,12 +302,11 @@
 
         while (as->start <= addr) {
                 if (as->end > addr) {
-                        partlength = MIN((unsigned int)(as->end - addr),
-                                         length);
+                        partlength = min(as->end - addr, (u64) length);
 
                         if (as->op->write != NULL) {
-                                rcode = as->op->write(host, nodeid, destid, data,
-						      addr, partlength);
+                                rcode = as->op->write(host, nodeid, destid,
+						      data, addr, partlength);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
diff -urN linux-2.4.19-pre4/drivers/ieee1394/highlevel.h linux-2.4.19-pre5/drivers/ieee1394/highlevel.h
--- linux-2.4.19-pre4/drivers/ieee1394/highlevel.h	Thu Jul 19 17:48:15 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/highlevel.h	Fri Mar 29 14:49:31 2002
@@ -91,7 +91,6 @@
 void init_hpsb_highlevel(void);
 
 void highlevel_add_host(struct hpsb_host *host);
-void highlevel_add_one_host(struct hpsb_host *host);
 void highlevel_remove_host(struct hpsb_host *host);
 void highlevel_host_reset(struct hpsb_host *host);
 
diff -urN linux-2.4.19-pre4/drivers/ieee1394/hosts.c linux-2.4.19-pre5/drivers/ieee1394/hosts.c
--- linux-2.4.19-pre4/drivers/ieee1394/hosts.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/hosts.c	Fri Mar 29 14:49:31 2002
@@ -11,101 +11,125 @@
  */
 
 #include <linux/config.h>
-
 #include <linux/types.h>
+#include <linux/list.h>
 #include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
+#include <linux/slab.h>
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"
 
+static struct list_head hosts = LIST_HEAD_INIT(hosts);
+static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers);
 
-static LIST_HEAD(templates);
-static spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * This function calls the add_host/remove_host hooks for every host currently
- * registered.  Init == TRUE means add_host.
- */
-void hl_all_hosts(struct hpsb_highlevel *hl, int init)
-{
-	struct list_head *tlh, *hlh;
-        struct hpsb_host_template *tmpl;
-        struct hpsb_host *host;
+spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED;
 
-        spin_lock(&templates_lock);
 
-	list_for_each(tlh, &templates) {
-                tmpl = list_entry(tlh, struct hpsb_host_template, list);
-		list_for_each(hlh, &tmpl->hosts) {
-			host = list_entry(hlh, struct hpsb_host, list);
-                        if (host->initialized) {
-                                if (init) {
-                                        if (hl->op->add_host) {
-                                                hl->op->add_host(host);
-                                        }
-                                } else {
-                                        if (hl->op->remove_host) {
-                                                hl->op->remove_host(host);
-                                        }
-                                }
-                        }
-                }
-        }
+static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
+{
+        return 0;
+}
 
-        spin_unlock(&templates_lock);
+static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
+{
+        return -1;
 }
 
-int hpsb_inc_host_usage(struct hpsb_host *host)
+static struct hpsb_host_operations dummy_ops = {
+        transmit_packet:  dummy_transmit_packet,
+        devctl:           dummy_devctl
+};
+
+/**
+ * hpsb_ref_host - increase reference count for host controller.
+ * @host: the host controller
+ *
+ * Increase the reference count for the specified host controller.
+ * When holding a reference to a host, the memory allocated for the
+ * host struct will not be freed and the host is guaranteed to be in a
+ * consistent state.  The driver may be unloaded or the controller may
+ * be removed (PCMCIA), but the host struct will remain valid.
+ */
+
+int hpsb_ref_host(struct hpsb_host *host)
 {
-	struct list_head *tlh, *hlh;
-        struct hpsb_host_template *tmpl;
-        int retval = 0;
+        struct list_head *lh;
 	unsigned long flags;
+        int retval = 0;
 
-        spin_lock_irqsave(&templates_lock, flags);
-
-	list_for_each(tlh, &templates) {
-                tmpl = list_entry(tlh, struct hpsb_host_template, list);
-		list_for_each(hlh, &tmpl->hosts) {
-			if (host == list_entry(hlh, struct hpsb_host, list)) {
-                                tmpl->devctl(host, MODIFY_USAGE, 1);
-                                retval = 1;
-                                break;
-                        }
-                }
-		if (retval)
+        spin_lock_irqsave(&hosts_lock, flags);
+        list_for_each(lh, &hosts) {
+                if (host == list_entry(lh, struct hpsb_host, host_list)) {
+                        host->ops->devctl(host, MODIFY_USAGE, 1);
+			host->refcount++;
+                        retval = 1;
 			break;
+        	}
         }
-
-        spin_unlock_irqrestore(&templates_lock, flags);
+        spin_unlock_irqrestore(&hosts_lock, flags);
 
         return retval;
 }
 
-void hpsb_dec_host_usage(struct hpsb_host *host)
+/**
+ * hpsb_unref_host - decrease reference count for host controller.
+ * @host: the host controller
+ *
+ * Decrease the reference count for the specified host controller.
+ * When the reference count reaches zero, the memory allocated for the
+ * &hpsb_host will be freed.
+ */
+
+void hpsb_unref_host(struct hpsb_host *host)
 {
-        host->template->devctl(host, MODIFY_USAGE, 0);
-}
+        unsigned long flags;
 
-/*
- * The following function is exported for module usage.  It will be called from
- * the detect function of a adapter driver.
+        host->ops->devctl(host, MODIFY_USAGE, 0);
+
+        spin_lock_irqsave(&hosts_lock, flags);
+        host->refcount--;
+
+        if (!host->refcount && host->is_shutdown)
+                kfree(host);
+        spin_unlock_irqrestore(&hosts_lock, flags);
+}
+
+/**
+ * hpsb_alloc_host - allocate a new host controller.
+ * @drv: the driver that will manage the host controller
+ * @extra: number of extra bytes to allocate for the driver
+ *
+ * Allocate a &hpsb_host and initialize the general subsystem specific
+ * fields.  If the driver needs to store per host data, as drivers
+ * usually do, the amount of memory required can be specified by the
+ * @extra parameter.  Once allocated, the driver should initialize the
+ * driver specific parts, enable the controller and make it available
+ * to the general subsystem using hpsb_add_host().
+ *
+ * The &hpsb_host is allocated with an single initial reference
+ * belonging to the driver.  Once the driver is done with the struct,
+ * for example, when the driver is unloaded, it should release this
+ * reference using hpsb_unref_host().
+ *
+ * Return Value: a pointer to the &hpsb_host if succesful, %NULL if
+ * no memory was available.
  */
-struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, 
-                                size_t hd_size)
+
+struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
 {
         struct hpsb_host *h;
 
-        h = vmalloc(sizeof(struct hpsb_host) + hd_size);
+        h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
         if (!h) return NULL;
+        memset(h, 0, sizeof(struct hpsb_host));
 
-        memset(h, 0, sizeof(struct hpsb_host) + hd_size);
-
-        atomic_set(&h->generation, 0);
+	h->hostdata = h + 1;
+        h->driver = drv;
+        h->ops = drv->ops;
+	h->refcount = 1;
 
         INIT_LIST_HEAD(&h->pending_packets);
         spin_lock_init(&h->pending_pkt_lock);
@@ -113,113 +137,90 @@
         sema_init(&h->tlabel_count, 64);
         spin_lock_init(&h->tlabel_lock);
 
+	atomic_set(&h->generation, 0);
+
 	INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
 
         h->topology_map = h->csr.topology_map + 3;
         h->speed_map = (u8 *)(h->csr.speed_map + 2);
 
-        h->template = tmpl;
-        if (hd_size)
-                h->hostdata = &h->embedded_hostdata[0];
+	return h;
+}
+
+void hpsb_add_host(struct hpsb_host *host)
+{
+        unsigned long flags;
 
-	list_add_tail(&h->list, &tmpl->hosts);
+        spin_lock_irqsave(&hosts_lock, flags);
+        host->driver->number_of_hosts++;
+        list_add_tail(&host->driver_list, &host->driver->hosts);
+        list_add_tail(&host->host_list, &hosts);
+        spin_unlock_irqrestore(&hosts_lock, flags);
 
-        return h;
+        highlevel_add_host(host);
+        host->ops->devctl(host, RESET_BUS, 0);
 }
 
-static void free_all_hosts(struct hpsb_host_template *tmpl)
+void hpsb_remove_host(struct hpsb_host *host)
 {
-	struct list_head *hlh, *next;
-        struct hpsb_host *host;
+        struct hpsb_host_driver *drv = host->driver;
+        unsigned long flags;
 
-	list_for_each_safe(hlh, next, &tmpl->hosts) {
-		host = list_entry(hlh, struct hpsb_host, list);
-                vfree(host);
-        }
+        host->is_shutdown = 1;
+        host->ops = &dummy_ops;
+        highlevel_remove_host(host);
+
+        spin_lock_irqsave(&hosts_lock, flags);
+        list_del(&host->driver_list);
+        list_del(&host->host_list);
+        drv->number_of_hosts--;
+        spin_unlock_irqrestore(&hosts_lock, flags);
 }
 
 
-static void init_hosts(struct hpsb_host_template *tmpl)
+struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
+                                                const char *name)
 {
-        int count;
-	struct list_head *hlh;
-        struct hpsb_host *host;
+        struct hpsb_host_driver *drv;
 
-        count = tmpl->detect_hosts(tmpl);
+        drv = kmalloc(sizeof(struct hpsb_host_driver), SLAB_KERNEL);
+        if (!drv) return NULL;
 
-	list_for_each(hlh, &tmpl->hosts) {
-		host = list_entry(hlh, struct hpsb_host, list);
-                if (tmpl->initialize_host(host)) {
-                        host->initialized = 1;
-
-                        highlevel_add_host(host);
-                        hpsb_reset_bus(host, LONG_RESET);
-                }
-        }
+        INIT_LIST_HEAD(&drv->list);
+        INIT_LIST_HEAD(&drv->hosts);
+        drv->number_of_hosts = 0;
+        drv->name = name;
+        drv->ops = op;
+
+        spin_lock(&host_drivers_lock);
+        list_add_tail(&drv->list, &host_drivers);
+        spin_unlock(&host_drivers_lock);
 
-        tmpl->number_of_hosts = count;
-        HPSB_INFO("detected %d %s adapter%s", count, tmpl->name,
-                  (count != 1 ? "s" : ""));
+        return drv;
 }
 
-static void shutdown_hosts(struct hpsb_host_template *tmpl)
+void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv)
 {
-	struct list_head *hlh;
-        struct hpsb_host *host;
-
-	list_for_each(hlh, &tmpl->hosts) {
-		host = list_entry(hlh, struct hpsb_host, list);
-                if (host->initialized) {
-                        highlevel_remove_host(host);
-
-                        host->initialized = 0;
-                        abort_requests(host);
-
-                        tmpl->release_host(host);
-                        while (test_bit(0, &host->timeout_tq.sync)) {
-                                schedule();
-                        }
-                }
-        }
-        free_all_hosts(tmpl);
-        tmpl->release_host(NULL);
+        spin_lock(&host_drivers_lock);
+        list_del(&drv->list);
+        spin_unlock(&host_drivers_lock);
 
-        tmpl->number_of_hosts = 0;
+        kfree(drv);
 }
 
 
 /*
- * The following two functions are exported symbols for module usage.
+ * This function calls the given function for every host currently registered.
  */
-int hpsb_register_lowlevel(struct hpsb_host_template *tmpl)
+void hl_all_hosts(void (*function)(struct hpsb_host*))
 {
-	INIT_LIST_HEAD(&tmpl->hosts);
-	tmpl->number_of_hosts = 0;
-
-        spin_lock(&templates_lock);
-	list_add_tail(&tmpl->list, &templates);
-        spin_unlock(&templates_lock);
-
-	/* PCI cards should be smart and use the PCI detection layer, and
-	 * not this one shot deal. detect_hosts() will be obsoleted soon. */
-	if (tmpl->detect_hosts != NULL) {
-		HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name);
-		init_hosts(tmpl);
-	}
-
-        return 0;
-}
-
-void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl)
-{
-        shutdown_hosts(tmpl);
+        struct list_head *lh;
+        struct hpsb_host *host;
 
-        if (tmpl->number_of_hosts)
-                HPSB_PANIC("attempted to remove busy host template "
-			   "of %s at address 0x%p", tmpl->name, tmpl);
-	else {
-		spin_lock(&templates_lock);
-		list_del(&tmpl->list);
-		spin_unlock(&templates_lock);
+        spin_lock_irq(&hosts_lock);
+        list_for_each (lh, &hosts) {
+                host = list_entry(lh, struct hpsb_host, host_list);
+                function(host);
 	}
+        spin_unlock_irq(&hosts_lock);
 }
diff -urN linux-2.4.19-pre4/drivers/ieee1394/hosts.h linux-2.4.19-pre5/drivers/ieee1394/hosts.h
--- linux-2.4.19-pre4/drivers/ieee1394/hosts.h	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/hosts.h	Fri Mar 29 14:49:31 2002
@@ -13,11 +13,15 @@
 struct hpsb_packet;
 
 struct hpsb_host {
-/* private fields (hosts, do not use them) */
-	struct list_head list;
+        struct list_head host_list;
+
+        struct hpsb_host_operations *ops;
+        void *hostdata;
 
         atomic_t generation;
 
+        int refcount;
+
         struct list_head pending_packets;
         spinlock_t pending_pkt_lock;
         struct tq_struct timeout_tq;
@@ -28,26 +32,19 @@
         struct semaphore tlabel_count;
         spinlock_t tlabel_lock;
 
-        int reset_retries;
-        quadlet_t *topology_map;
-        u8 *speed_map;
-        struct csr_control csr;
-
         unsigned char iso_listen_count[64];
 
-/* readonly fields for hosts */
-        struct hpsb_host_template *template;
-
         int node_count; /* number of identified nodes on this bus */
         int selfid_count; /* total number of SelfIDs received */
+	int nodes_active; /* number of nodes that are actually active */
 
         nodeid_t node_id; /* node ID of this host */
         nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
         nodeid_t busmgr_id; /* ID of this bus' bus manager */
 
-        unsigned initialized:1; /* initialized and usable */
-        unsigned in_bus_reset:1; /* in bus reset / SelfID stage */
-        unsigned attempt_root:1; /* attempt to become root during next reset */
+        /* this nodes state */
+        unsigned in_bus_reset:1;
+        unsigned is_shutdown:1;
 
         /* this nodes' duties on the bus */
         unsigned is_root:1;
@@ -55,11 +52,15 @@
         unsigned is_irm:1;
         unsigned is_busmgr:1;
 
-/* fields readable and writeable by the hosts */
+        int reset_retries;
+        quadlet_t *topology_map;
+        u8 *speed_map;
+        struct csr_control csr;
+
+        struct hpsb_host_driver *driver;
+        struct list_head driver_list;
 
-        void *hostdata;
 	struct pci_dev *pdev;
-        int embedded_hostdata[0];
 };
 
 
@@ -88,8 +89,10 @@
          * Return void. */
         CANCEL_REQUESTS,
 
-        /* Decrease module usage count if arg == 0, increase otherwise.  Return
-         * void. */
+        /* Decrease host usage count if arg == 0, increase otherwise.  Return
+         * 1 for success, 0 for failure.  Increase usage may fail if the driver
+         * is in the process of shutting itself down.  Decrease usage can not
+         * fail. */
         MODIFY_USAGE,
 
         /* Start or stop receiving isochronous channel in arg.  Return void.
@@ -109,37 +112,7 @@
         SHORT_RESET
 };
 
-struct hpsb_host_template {
-	struct list_head list;
-
-        struct list_head hosts;
-        int number_of_hosts;
-
-        /* fields above will be ignored and overwritten after registering */
-
-        /* This should be the name of the driver (single word) and must not be
-         * NULL. */
-        const char *name;
-
-        /* This function shall detect all available adapters of this type and
-         * call hpsb_get_host for each one.  The initialize_host function will
-         * be called to actually set up these adapters.  The number of detected
-         * adapters or zero if there are none must be returned.
-         */
-        int (*detect_hosts) (struct hpsb_host_template *template);
-
-        /* After detecting and registering hosts, this function will be called
-         * for every registered host.  It shall set up the host to be fully
-         * functional for bus operations and return 0 for failure.
-         */
-        int (*initialize_host) (struct hpsb_host *host);
-
-        /* To unload modules, this function is provided.  It shall free all
-         * resources this host is using (if host is not NULL) or free all
-         * resources globally allocated by the driver (if host is NULL).
-         */
-        void (*release_host) (struct hpsb_host *host); 
-
+struct hpsb_host_operations {
         /* This function must store a pointer to the configuration ROM into the
          * location referenced to by pointer and return the size of the ROM. It
          * may not fail.  If any allocation is required, it must be done
@@ -175,34 +148,43 @@
                                  quadlet_t data, quadlet_t compare);
 };
 
+struct hpsb_host_driver {
+        struct list_head list;
 
+        struct list_head hosts;
 
-/* mid level internal use */
+        int number_of_hosts;
+        const char *name;
+
+        struct hpsb_host_operations *ops;
+};
+
+
+/* core internal use */
 void register_builtin_lowlevels(void);
 
 /* high level internal use */
 struct hpsb_highlevel;
-void hl_all_hosts(struct hpsb_highlevel *hl, int init);
+void hl_all_hosts(void (*function)(struct hpsb_host*));
 
-/* 
- * These functions are for lowlevel (host) driver use.
- */
-int hpsb_register_lowlevel(struct hpsb_host_template *tmpl);
-void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl);
 
 /*
- * Get a initialized host structure with hostdata_size bytes allocated in
- * embedded_hostdata for free usage.  Returns NULL for failure.  
+ * In order to prevent hosts from unloading, use hpsb_ref_host().  This prevents
+ * the host from going away (e.g. makes module unloading of the driver
+ * impossible), but still can not guarantee it (e.g. PC-Card being pulled by the
+ * user).  hpsb_ref_host() returns false if host could not be locked.  If it is
+ * successful, host is valid as a pointer until hpsb_unref_host() (not just
+ * until after remove_host).
  */
-struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, 
-                                size_t hostdata_size);
+int hpsb_ref_host(struct hpsb_host *host);
+void hpsb_unref_host(struct hpsb_host *host);
 
-/*
- * Increase / decrease host usage counter.  Increase function will return true
- * only if successful (host still existed).  Decrease function expects host to
- * exist.
- */
-int hpsb_inc_host_usage(struct hpsb_host *host);
-void hpsb_dec_host_usage(struct hpsb_host *host);
+struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra);
+void hpsb_add_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *h);
+
+struct hpsb_host_driver *hpsb_register_lowlevel(struct hpsb_host_operations *op,
+                                                const char *name);
+void hpsb_unregister_lowlevel(struct hpsb_host_driver *drv);
 
 #endif /* _IEEE1394_HOSTS_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ieee1394.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394.h
--- linux-2.4.19-pre4/drivers/ieee1394/ieee1394.h	Wed Oct 17 14:19:20 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394.h	Fri Mar 29 14:49:31 2002
@@ -39,10 +39,10 @@
 #define ACK_TYPE_ERROR           0xe 
 
 /* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE                -1
-#define ACKX_SEND_ERROR          -2
-#define ACKX_ABORTED             -3
-#define ACKX_TIMEOUT             -4
+#define ACKX_NONE                (-1)
+#define ACKX_SEND_ERROR          (-2)
+#define ACKX_ABORTED             (-3)
+#define ACKX_TIMEOUT             (-4)
 
 
 #define SPEED_100                0x0
@@ -116,7 +116,7 @@
 
 /*
  * Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine.
+ * endian machine.  Without swapping.
  */
 
 struct selfid {
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ieee1394_core.c linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.19-pre4/drivers/ieee1394/ieee1394_core.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.c	Fri Mar 29 14:49:31 2002
@@ -18,9 +18,11 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/proc_fs.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
+#include <asm/smplock.h>
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
@@ -39,6 +41,10 @@
 MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 static int disable_nodemgr = 0;
 
+MODULE_PARM(disable_hotplug, "i");
+MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes.");
+static int disable_hotplug = 0;
+
 /* We are GPL, so treat us special */
 MODULE_LICENSE("GPL");
 
@@ -106,7 +112,7 @@
                 packet->data_size = data_size;
         }
 
-        INIT_TQ_HEAD(packet->complete_tq);
+        INIT_LIST_HEAD(&packet->complete_tq);
         INIT_LIST_HEAD(&packet->list);
         sema_init(&packet->state_change, 0);
         packet->state = hpsb_unused;
@@ -135,12 +141,8 @@
 
 int hpsb_reset_bus(struct hpsb_host *host, int type)
 {
-        if (!host->initialized) {
-                return 1;
-        }
-
         if (!host->in_bus_reset) {
-                host->template->devctl(host, RESET_BUS, type);
+                host->ops->devctl(host, RESET_BUS, type);
                 return 0;
         } else {
                 return 1;
@@ -151,8 +153,8 @@
 int hpsb_bus_reset(struct hpsb_host *host)
 {
         if (host->in_bus_reset) {
-                HPSB_NOTICE(__FUNCTION__ 
-                            " called while bus reset already in progress");
+                HPSB_NOTICE("%s called while bus reset already in progress",
+			    __FUNCTION__);
                 return 1;
         }
 
@@ -171,14 +173,16 @@
  * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in
  * case verification failed.
  */
-static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
+static int check_selfids(struct hpsb_host *host)
 {
         int nodeid = -1;
-        int rest_of_selfids = num_of_selfids;
+        int rest_of_selfids = host->selfid_count;
         struct selfid *sid = (struct selfid *)host->topology_map;
         struct ext_selfid *esid;
         int esid_seq = 23;
 
+	host->nodes_active = 0;
+
         while (rest_of_selfids--) {
                 if (!sid->extended) {
                         nodeid++;
@@ -190,9 +194,11 @@
                                 return 0;
                         }
                         
-                        if (sid->contender && sid->link_active) {
-                                host->irm_id = LOCAL_BUS | sid->phy_id;
-                        }
+			if (sid->link_active) {
+				host->nodes_active++;
+				if (sid->contender)
+					host->irm_id = LOCAL_BUS | sid->phy_id;
+			}
                 } else {
                         esid = (struct ext_selfid *)sid;
 
@@ -226,7 +232,8 @@
                         return 0;
         }
 
-        return nodeid + 1;
+	host->node_count = nodeid + 1;
+        return 1;
 }
 
 static void build_speed_map(struct hpsb_host *host, int nodecount)
@@ -318,15 +325,17 @@
 
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 {
+	if (!host->in_bus_reset)
+		HPSB_NOTICE("SelfID completion called outside of bus reset!");
+
         host->node_id = LOCAL_BUS | phyid;
-        host->in_bus_reset = 0;
         host->is_root = isroot;
 
-        host->node_count = check_selfids(host, host->selfid_count);
-        if (!host->node_count) {
+        if (!check_selfids(host)) {
                 if (host->reset_retries++ < 20) {
                         /* selfid stage did not complete without error */
                         HPSB_NOTICE("Error in SelfID stage, resetting");
+			host->in_bus_reset = 0;
                         hpsb_reset_bus(host, LONG_RESET);
                         return;
                 } else {
@@ -346,8 +355,9 @@
         }
 
         host->reset_retries = 0;
-        atomic_inc(&host->generation);
-        if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1);
+        if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1);
+	atomic_inc(&host->generation);
+	host->in_bus_reset = 0;
         highlevel_host_reset(host);
 }
 
@@ -402,7 +412,7 @@
 {
         struct hpsb_host *host = packet->host;
 
-        if (!host->initialized || host->in_bus_reset 
+        if (host->is_shutdown || host->in_bus_reset
             || (packet->generation != get_hpsb_generation(host))) {
                 return 0;
         }
@@ -431,7 +441,7 @@
         }
 #endif
 
-        return host->template->transmit_packet(host, packet);
+        return host->ops->transmit_packet(host, packet);
 }
 
 static void send_packet_nocare(struct hpsb_packet *packet)
@@ -727,7 +737,7 @@
         struct list_head *lh;
         LIST_HEAD(llist);
 
-        host->template->devctl(host, CANCEL_REQUESTS, 0);
+        host->ops->devctl(host, CANCEL_REQUESTS, 0);
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
         list_splice(&host->pending_packets, &llist);
@@ -786,14 +796,216 @@
 }
 
 
+/*
+ * character device dispatching (see ieee1394_core.h)
+ * Dan Maas <dmaas@dcine.com>
+ */
+
+static struct {
+	struct file_operations *file_ops;
+	struct module *module;
+} ieee1394_chardevs[16];
+
+static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
+
+static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
+
+static struct file_operations ieee1394_chardev_ops = {
+	owner:	THIS_MODULE,
+	open:	ieee1394_dispatch_open,
+};
+
+devfs_handle_t ieee1394_devfs_handle;
+
+
+/* claim a block of minor numbers */
+int ieee1394_register_chardev(int blocknum,
+			      struct module *module,
+			      struct file_operations *file_ops)
+{
+	int retval;
+	
+	if( (blocknum < 0) || (blocknum > 15) )
+		return -EINVAL;
+
+	write_lock(&ieee1394_chardevs_lock);
+
+	if(ieee1394_chardevs[blocknum].file_ops == NULL) {
+		/* grab the minor block */
+		ieee1394_chardevs[blocknum].file_ops = file_ops;
+		ieee1394_chardevs[blocknum].module = module;
+		
+		retval = 0;
+	} else {
+		/* block already taken */
+		retval = -EBUSY;
+	}
+	
+	write_unlock(&ieee1394_chardevs_lock);
+
+	return retval;
+}
+
+/* release a block of minor numbers */
+void ieee1394_unregister_chardev(int blocknum)
+{
+	if( (blocknum < 0) || (blocknum > 15) )
+		return;
+	
+	write_lock(&ieee1394_chardevs_lock);
+	
+	if(ieee1394_chardevs[blocknum].file_ops) {
+		ieee1394_chardevs[blocknum].file_ops = NULL;
+		ieee1394_chardevs[blocknum].module = NULL;
+	}
+	
+	write_unlock(&ieee1394_chardevs_lock);
+}
+
+/* the point of entry for open() on any ieee1394 character device */
+static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
+{
+	struct file_operations *file_ops;
+	struct module *module;
+	int blocknum;
+	int retval = -ENODEV;
+
+	/*
+	  Maintaining correct module reference counts is tricky here!
+
+	  For Linux v2.4 and later:
+	  
+	  The key thing to remember is that the VFS increments the
+	  reference count of ieee1394 before it calls
+	  ieee1394_dispatch_open().
+
+	  If the open() succeeds, then we need to transfer this extra
+	  reference to the task-specific driver module (e.g. raw1394).
+	  The VFS will deref the driver module automatically when the
+	  file is later released.
+
+	  If the open() fails, then the VFS will drop the
+	  reference count of whatever module file->f_op->owner points
+	  to, immediately after this function returns.
+
+	  The comments below refer to the 2.4 case, since the 2.2
+	  case is trivial.
+	  
+	*/
+
+#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
+                          if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
+#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
+                          if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
+	
+        /* shift away lower four bits of the minor
+	   to get the index of the ieee1394_driver
+	   we want */
+	
+	blocknum = (minor(inode->i_rdev) >> 4) & 0xF;
+
+	/* printk("ieee1394_dispatch_open(%d)", blocknum); */
+
+	/* lock the whole kernel here, to prevent a driver from
+	   being unloaded between the file_ops lookup and the open */
+
+	lock_kernel();
+
+	read_lock(&ieee1394_chardevs_lock);
+	file_ops = ieee1394_chardevs[blocknum].file_ops;
+	module = ieee1394_chardevs[blocknum].module;
+	read_unlock(&ieee1394_chardevs_lock);
+
+	if(file_ops == NULL) {
+		goto out_fail;
+	}
+
+	/* redirect all subsequent requests to the driver's
+	   own file_operations */
+	file->f_op = file_ops;
+
+	/* bump the reference count of the driver that
+	   will receive the open() */
+	INCREF(module);
+	
+	/* at this point BOTH ieee1394 and the task-specific driver have
+	   an extra reference */
+
+	/* follow through with the open() */
+	retval = file_ops->open(inode, file);
+
+	if(retval) {
+		
+		/* if the open() failed, then we need to drop the
+                   extra reference we gave to the task-specific
+                   driver */
+
+		DECREF(module);
+		goto out_fail;
+		
+	} else {
+
+		/* if the open() succeeded, then ieee1394 will be left
+		   with an extra module reference, so we discard it here.*/
+
+		DECREF(THIS_MODULE);
+
+		/* the task-specific driver still has the extra
+		   reference we gave it. This extra reference prevents
+		   the module from unloading while the file is open,
+		   and will be dropped by the VFS when the file is
+		   released. */
+		
+		unlock_kernel();
+		return 0;
+	}
+	       
+out_fail:
+	/* point the file's f_ops back to ieee1394. The VFS will then
+	   decrement ieee1394's reference count immediately after this
+	   function returns. */
+	
+	file->f_op = &ieee1394_chardev_ops;
+	unlock_kernel();
+	return retval;
+
+#undef INCREF
+#undef DECREF
+	     
+}
+
+struct proc_dir_entry *ieee1394_procfs_entry;
+
 static int __init ieee1394_init(void)
 {
 	hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
 					      0, 0, NULL, NULL);
+
+	ieee1394_devfs_handle = devfs_mk_dir(NULL, "ieee1394", NULL);
+
+	if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
+		HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
+		devfs_unregister(ieee1394_devfs_handle);
+		return -ENODEV;
+	}
+
+#ifdef CONFIG_PROC_FS
+	/* Must be done before we start everything else, since the drivers
+	 * may use it.  */
+	ieee1394_procfs_entry = proc_mkdir( "ieee1394", proc_bus);
+	if (ieee1394_procfs_entry == NULL) {
+		HPSB_ERR("unable to create /proc/bus/ieee1394\n");
+		unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+		devfs_unregister(ieee1394_devfs_handle);
+		return -ENOMEM;
+	}
+	ieee1394_procfs_entry->owner = THIS_MODULE;
+#endif
+
 	init_hpsb_highlevel();
 	init_csr();
 	if (!disable_nodemgr)
-		init_ieee1394_nodemgr();
+		init_ieee1394_nodemgr(disable_hotplug);
 	else
 		HPSB_INFO("nodemgr functionality disabled");
 
@@ -807,6 +1019,13 @@
 
 	cleanup_csr();
 	kmem_cache_destroy(hpsb_packet_cache);
+
+	unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+	
+	/* it's ok to pass a NULL devfs_handle to devfs_unregister */
+	devfs_unregister(ieee1394_devfs_handle);
+	
+	remove_proc_entry("ieee1394", proc_bus);
 }
 
 module_init(ieee1394_init);
@@ -815,9 +1034,11 @@
 /* Exported symbols */
 EXPORT_SYMBOL(hpsb_register_lowlevel);
 EXPORT_SYMBOL(hpsb_unregister_lowlevel);
-EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_inc_host_usage);
-EXPORT_SYMBOL(hpsb_dec_host_usage);
+EXPORT_SYMBOL(hpsb_alloc_host);
+EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_remove_host);
+EXPORT_SYMBOL(hpsb_ref_host);
+EXPORT_SYMBOL(hpsb_unref_host);
 EXPORT_SYMBOL(hpsb_speedto_str);
 
 EXPORT_SYMBOL(alloc_hpsb_packet);
@@ -867,12 +1088,19 @@
 EXPORT_SYMBOL(highlevel_add_host);
 EXPORT_SYMBOL(highlevel_remove_host);
 EXPORT_SYMBOL(highlevel_host_reset);
-EXPORT_SYMBOL(highlevel_add_one_host);
 
 EXPORT_SYMBOL(hpsb_guid_get_entry);
 EXPORT_SYMBOL(hpsb_nodeid_get_entry);
-EXPORT_SYMBOL(hpsb_get_host_by_ne);
-EXPORT_SYMBOL(hpsb_guid_fill_packet);
+EXPORT_SYMBOL(hpsb_node_fill_packet);
+EXPORT_SYMBOL(hpsb_node_read);
+EXPORT_SYMBOL(hpsb_node_write);
+EXPORT_SYMBOL(hpsb_node_lock);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
+
+EXPORT_SYMBOL(ieee1394_register_chardev);
+EXPORT_SYMBOL(ieee1394_unregister_chardev);
+EXPORT_SYMBOL(ieee1394_devfs_handle);
+
+EXPORT_SYMBOL(ieee1394_procfs_entry);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ieee1394_core.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.19-pre4/drivers/ieee1394/ieee1394_core.h	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_core.h	Fri Mar 29 14:49:31 2002
@@ -4,6 +4,8 @@
 
 #include <linux/tqueue.h>
 #include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/proc_fs.h>
 #include <asm/semaphore.h>
 #include "hosts.h"
 
@@ -96,7 +98,6 @@
         return atomic_read(&host->generation);
 }
 
-
 /*
  * Queue packet for transmitting, return 0 for failure.
  */
@@ -152,4 +153,65 @@
 void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
                           int write_acked);
 
+
+/*
+ * CHARACTER DEVICE DISPATCHING
+ *
+ * All ieee1394 character device drivers share the same major number
+ * (major 171).  The 256 minor numbers are allocated to the various
+ * task-specific interfaces (raw1394, video1394, dv1394, etc) in
+ * blocks of 16.
+ *
+ * The core ieee1394.o modules handles the initial open() for all
+ * character devices on major 171; it then dispatches to the
+ * appropriate task-specific driver.
+ *
+ * Minor device number block allocations:
+ *
+ * Block 0  (  0- 15)  raw1394
+ * Block 1  ( 16- 31)  video1394
+ * Block 2  ( 32- 47)  dv1394
+ *
+ * Blocks 3-14 free for future allocation
+ *
+ * Block 15 (240-255)  reserved for drivers under development, etc.
+ */
+
+#define IEEE1394_MAJOR               171
+
+#define IEEE1394_MINOR_BLOCK_RAW1394       0
+#define IEEE1394_MINOR_BLOCK_VIDEO1394     1
+#define IEEE1394_MINOR_BLOCK_DV1394        2
+#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
+
+/* return the index (within a minor number block) of a file */
+static inline unsigned char ieee1394_file_to_instance(struct file *file)
+{
+	unsigned char minor = minor(file->f_dentry->d_inode->i_rdev);
+	
+	/* return lower 4 bits */
+	return minor & 0xF;
+}
+
+/* 
+ * Task-specific drivers should call ieee1394_register_chardev() to
+ * request a block of 16 minor numbers.
+ *
+ * Returns 0 if the request was successful, -EBUSY if the block was
+ * already taken.
+ */
+
+int  ieee1394_register_chardev(int blocknum,           /* 0-15 */
+			       struct module *module,  /* THIS_MODULE */
+			       struct file_operations *file_ops);
+
+/* release a block of minor numbers */
+void ieee1394_unregister_chardev(int blocknum);
+
+/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */
+extern devfs_handle_t ieee1394_devfs_handle;
+
+/* the proc_fs entry for /proc/ieee1394 */
+extern struct proc_dir_entry *ieee1394_procfs_entry;
+
 #endif /* _IEEE1394_CORE_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ieee1394_transactions.c linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.4.19-pre4/drivers/ieee1394/ieee1394_transactions.c	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.c	Fri Mar 29 14:49:31 2002
@@ -246,7 +246,7 @@
                                  packet->node_id);
                         return -EAGAIN;
                 }
-                HPSB_PANIC("reached unreachable code 1 in " __FUNCTION__);
+                HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__);
 
         case ACK_BUSY_X:
         case ACK_BUSY_A:
@@ -290,7 +290,7 @@
                 return -EAGAIN;
         }
 
-        HPSB_PANIC("reached unreachable code 2 in " __FUNCTION__);
+        HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
 
@@ -415,8 +415,8 @@
  * avoid in kernel buffers for user space callers
  */
 
-int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
-              quadlet_t *buffer, size_t length)
+int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, quadlet_t *buffer, size_t length)
 {
         struct hpsb_packet *packet;
         int retval = 0;
@@ -447,7 +447,7 @@
                 return -ENOMEM;
         }
 
-	packet->generation = get_hpsb_generation(host);
+	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
 		retval = -EINVAL;
 		goto hpsb_read_fail;
@@ -496,8 +496,8 @@
 	return packet;
 }
 
-int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
-	       quadlet_t *buffer, size_t length)
+int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	       u64 addr, quadlet_t *buffer, size_t length)
 {
 	struct hpsb_packet *packet;
 	int retval;
@@ -522,7 +522,7 @@
 	if (!packet)
 		return -ENOMEM;
 
-	packet->generation = get_hpsb_generation(host);
+	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
 		retval = -EINVAL;
 		goto hpsb_write_fail;
@@ -541,8 +541,8 @@
 
 
 /* We need a hpsb_lock64 function for the 64 bit equivalent.  Probably. */
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
-              quadlet_t *data, quadlet_t arg)
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
 {
         struct hpsb_packet *packet;
         int retval = 0, length;
@@ -588,7 +588,7 @@
         }
         fill_async_lock(packet, addr, extcode, length);
 
-	packet->generation = get_hpsb_generation(host);
+	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
 		retval = -EINVAL;
 		goto hpsb_lock_fail;
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ieee1394_transactions.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.h
--- linux-2.4.19-pre4/drivers/ieee1394/ieee1394_transactions.h	Thu Jul 19 17:48:15 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_transactions.h	Fri Mar 29 14:49:31 2002
@@ -63,14 +63,16 @@
  * The generic read, write and lock functions.  All recognize the local node ID
  * and act accordingly.  Read and write automatically use quadlet commands if
  * length == 4 and and block commands otherwise (however, they do not yet
- * support lengths that are not a multiple of 4).
+ * support lengths that are not a multiple of 4).  You must explicitly specifiy
+ * the generation for which the node ID is valid, to avoid sending packets to
+ * the wrong nodes when we race with a bus reset.
  */
-int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
-              quadlet_t *buffer, size_t length);
-int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
-               quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
-              quadlet_t *data, quadlet_t arg);
+int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, quadlet_t *buffer, size_t length);
+int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	       u64 addr, quadlet_t *buffer, size_t length);
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
 
 /* Generic packet creation. Used by hpsb_write. Also useful for protocol
  * drivers that want to implement their own hpsb_write replacement.  */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ieee1394_types.h linux-2.4.19-pre5/drivers/ieee1394/ieee1394_types.h
--- linux-2.4.19-pre4/drivers/ieee1394/ieee1394_types.h	Wed Oct 17 14:19:20 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ieee1394_types.h	Fri Mar 29 14:49:31 2002
@@ -6,18 +6,18 @@
 #include <linux/types.h>
 #include <linux/version.h>
 #include <linux/list.h>
+#include <linux/init.h>
 #include <asm/byteorder.h>
 
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#include "linux22compat.h"
-#else
-#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0)
-#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0)
-#define OWNER_THIS_MODULE owner: THIS_MODULE,
+/* The great kdev_t changeover in 2.5.x */
+#include <linux/kdev_t.h>
+#ifndef minor
+#define minor(dev) MINOR(dev)
+#endif
 
-#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list)
-#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
+#ifndef __devexit_p
+#define __devexit_p(x) x
 #endif
 
 /* This showed up around this time */
@@ -37,11 +37,7 @@
 
 #endif /* Linux version < 2.4.12 */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
-#include <asm/spinlock.h>
-#else
 #include <linux/spinlock.h>
-#endif
 
 #ifndef list_for_each_safe
 #define list_for_each_safe(pos, n, head) \
@@ -67,7 +63,8 @@
 #define LOCAL_BUS 0xffc0
 #define ALL_NODES 0x003f
 
-#define NODE_BUS_FMT    "%d:%d"
+/* Can be used to consistently print a node/bus ID. */
+#define NODE_BUS_FMT    "%02d:%04d"
 #define NODE_BUS_ARGS(nodeid) \
 	(nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6)
 
diff -urN linux-2.4.19-pre4/drivers/ieee1394/nodemgr.c linux-2.4.19-pre5/drivers/ieee1394/nodemgr.c
--- linux-2.4.19-pre4/drivers/ieee1394/nodemgr.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/nodemgr.c	Fri Mar 29 14:49:31 2002
@@ -12,10 +12,14 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <asm/byteorder.h>
-#include <asm/atomic.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kmod.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
@@ -57,23 +61,254 @@
 static LIST_HEAD(host_info_list);
 static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
 
+/* Disables use of the hotplug calls.  */
+static int nodemgr_disable_hotplug = 0;
+
 struct host_info {
 	struct hpsb_host *host;
-	struct tq_struct task;
 	struct list_head list;
+	struct completion exited;
+	struct semaphore reset_sem;
+	int pid;
 };
 
+#ifdef CONFIG_PROC_FS
+
+#define PUTF(fmt, args...) out += sprintf(out, fmt, ## args)
+
+static int raw1394_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
+{
+	struct list_head *lh;
+	struct node_entry *ne;
+	int len;
+	char *out = page;
+
+	list_for_each(lh, &node_list) {
+		struct list_head *l;
+		int ud_count = 0;
+
+		ne = list_entry(lh, struct node_entry, list);
+		if (!ne)
+			continue;
+
+		PUTF("Node[" NODE_BUS_FMT "]  GUID[%016Lx]:\n",
+		     NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+
+		/* Generic Node information */
+		PUTF("  Vendor ID: `%s' [0x%06x]\n",
+		     ne->vendor_name ?: "Unknown", ne->vendor_id);
+		PUTF("  Capabilities: 0x%06x\n", ne->capabilities);
+		PUTF("  Bus Options:\n");
+		PUTF("    IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d)\n"
+		     "    LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n",
+		     ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
+		     ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
+		     ne->busopt.max_rec, ne->busopt.cyc_clk_acc);
+
+		/* If this is the host entry, output some info about it aswell */
+		if (ne->host != NULL && ne->host->node_id == ne->nodeid) {
+			PUTF("  Host Node Status:\n");
+			PUTF("    Host Driver     : %s\n", ne->host->driver->name);
+			PUTF("    Nodes connected : %d\n", ne->host->node_count);
+			PUTF("    Nodes active    : %d\n", ne->host->nodes_active);
+			PUTF("    SelfIDs received: %d\n", ne->host->selfid_count);
+			PUTF("    Irm ID          : [" NODE_BUS_FMT "]\n",
+			     NODE_BUS_ARGS(ne->host->irm_id));
+			PUTF("    BusMgr ID       : [" NODE_BUS_FMT "]\n",
+			     NODE_BUS_ARGS(ne->host->busmgr_id));
+			PUTF("    In Bus Reset    : %s\n", ne->host->in_bus_reset ? "yes" : "no");
+			PUTF("    Root            : %s\n", ne->host->is_root ? "yes" : "no");
+			PUTF("    Cycle Master    : %s\n", ne->host->is_cycmst ? "yes" : "no");
+			PUTF("    IRM             : %s\n", ne->host->is_irm ? "yes" : "no");
+			PUTF("    Bus Manager     : %s\n", ne->host->is_busmgr ? "yes" : "no");
+		}
+
+		/* Now the unit directories */
+		list_for_each (l, &ne->unit_directories) {
+			struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
+			PUTF("  Unit Directory %d:\n", ud_count++);
+			if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
+				PUTF("    Vendor/Model ID: %s [%06x]",
+				     ud->vendor_name ?: "Unknown", ud->vendor_id);
+			else if (ud->flags & UNIT_DIRECTORY_MODEL_ID) /* Have to put something */
+				PUTF("    Vendor/Model ID: %s [%06x]",
+				      ne->vendor_name ?: "Unknown", ne->vendor_id);
+			if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
+				PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id);
+			PUTF("\n");
+			if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
+				PUTF("    Software Specifier ID: %06x\n", ud->specifier_id);
+			if (ud->flags & UNIT_DIRECTORY_VERSION)
+				PUTF("    Software Version: %06x\n", ud->version);
+			if (ud->driver)
+				PUTF("    Driver: %s\n", ud->driver->name);
+			PUTF("    Length (in quads): %d\n", ud->count);
+		}
+
+	}
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+        *start = page + off;
+
+	return len;
+}
+
+#undef PUTF
+#endif /* CONFIG_PROC_FS */
+
 static void nodemgr_process_config_rom(struct node_entry *ne, 
 				       quadlet_t busoptions);
 
+static int nodemgr_read_quadlet(struct hpsb_host *host,
+				nodeid_t nodeid, unsigned int generation,
+				octlet_t address, quadlet_t *quad)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < 3; i++) {
+		ret = hpsb_read(host, nodeid, generation, address, quad, 4);
+		if (ret != -EAGAIN)
+			break;
+	}
+	*quad = be32_to_cpu(*quad);
+
+	return ret;
+}
+
+static int nodemgr_size_text_leaf(struct hpsb_host *host,
+				  nodeid_t nodeid, unsigned int generation,
+				  octlet_t address)
+{
+	quadlet_t quad;
+	int size = 0;
+	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
+		return -1;
+	if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {
+		/* This is the offset.  */
+		address += 4 * CONFIG_ROM_VALUE(quad); 
+		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
+			return -1;
+		/* Now we got the size of the text descriptor leaf. */
+		size = CONFIG_ROM_LEAF_LENGTH(quad);
+	}
+	return size;
+}
+
+static int nodemgr_read_text_leaf(struct node_entry *ne,
+				  octlet_t address,
+				  quadlet_t *quadp)
+{
+	quadlet_t quad;
+	int i, size, ret;
+
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)
+	    && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
+		return -1;
+
+	/* This is the offset.  */
+	address += 4 * CONFIG_ROM_VALUE(quad);
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))
+		return -1;
+
+	/* Now we got the size of the text descriptor leaf. */
+	size = CONFIG_ROM_LEAF_LENGTH(quad) - 2;
+	if (size <= 0)
+		return -1;
+
+	address += 4;
+	for (i = 0; i < 2; i++, address += 4, quadp++) {
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, quadp))
+			return -1;
+	}
+
+	/* Now read the text string.  */
+	ret = -ENXIO;
+	for (; size > 0; size--, address += 4, quadp++) {
+		for (i = 0; i < 3; i++) {
+			ret = hpsb_read(ne->host, ne->nodeid, ne->generation, address, quadp, 4);
+			if (ret != -EAGAIN)
+				break;
+		}
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static struct node_entry *nodemgr_scan_root_directory
+	(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation)
+{
+	octlet_t address;
+	quadlet_t quad;
+	int length;
+	int code, size, total_size;
+	struct node_entry *ne;
+
+	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
+	
+	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
+		return NULL;
+	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
+
+	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
+		return NULL;
+	length = CONFIG_ROM_ROOT_LENGTH(quad);
+	address += 4;
+
+	size = 0;
+	total_size = sizeof(struct node_entry);
+	for (; length > 0; length--, address += 4) {
+		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
+			return NULL;
+		code = CONFIG_ROM_KEY(quad);
+
+		if (code == CONFIG_ROM_VENDOR_ID && length > 0) {
+			/* Check if there is a text descriptor leaf
+			   immediately after this.  */
+			size = nodemgr_size_text_leaf(host, nodeid, generation,
+						      address + 4);
+			if (size > 0) {
+				address += 4;
+				length--;
+				total_size += (size + 1) * sizeof (quadlet_t);
+			}
+			else if (size < 0)
+				return NULL;
+		}
+	}
+	ne = kmalloc(total_size, SLAB_ATOMIC);
+	if (ne != NULL) {
+		if (size != 0) {
+			ne->vendor_name
+				= (const char *) &(ne->quadlets[2]);
+			ne->quadlets[size] = 0;
+		}
+		else {
+			ne->vendor_name = NULL;
+		}
+	}
+	return ne; 
+}
 
 static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
-					      struct hpsb_host *host, nodeid_t nodeid)
+					      struct hpsb_host *host,
+					      nodeid_t nodeid, unsigned int generation)
 {
         struct node_entry *ne;
         unsigned long flags;
 
-        ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
+	ne = nodemgr_scan_root_directory (host, nodeid, generation);
         if (!ne) return NULL;
 
         INIT_LIST_HEAD(&ne->list);
@@ -81,7 +316,7 @@
         ne->host = host;
         ne->nodeid = nodeid;
         ne->guid = guid;
-	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
+	ne->generation = generation;
 
         write_lock_irqsave(&node_lock, flags);
         list_add_tail(&ne->list, &node_list);
@@ -89,9 +324,10 @@
 
 	nodemgr_process_config_rom (ne, busoptions);
 
-	HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx",
-		   (host->node_id == nodeid) ? "Local host" : "Device",
-		   NODE_BUS_ARGS(nodeid), (unsigned long long)guid);
+	HPSB_DEBUG("%s added: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
+		   (host->node_id == nodeid) ? "Host" : "Device",
+		   NODE_BUS_ARGS(nodeid), (unsigned long long)guid,
+		   ne->vendor_name ?: "Unknown");
 
         return ne;
 }
@@ -122,30 +358,102 @@
 	return NULL;
 }
 
-int nodemgr_read_quadlet(struct node_entry *ne,
-			 octlet_t address, quadlet_t *quad)
+static struct unit_directory *nodemgr_scan_unit_directory
+	(struct node_entry *ne, octlet_t address)
 {
-	int i;
-	int ret = 0;
+	struct unit_directory *ud;
+	quadlet_t quad;
+	u8 flags, todo;
+	int length, size, total_size, count;
+	int vendor_name_size, model_name_size;
 
-	for (i = 0; i < 3; i++) {
-		ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4);
-		if (ret != -EAGAIN)
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))
+		return NULL;
+	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
+	address += 4;
+
+	size = 0;
+	total_size = sizeof (struct unit_directory);
+	flags = 0;
+	count = 0;
+	vendor_name_size = 0;
+	model_name_size = 0;
+	for (; length > 0; length--, address += 4) {
+		int code;
+		quadlet_t value;
+
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+					 address, &quad))
+			return NULL;
+		code = CONFIG_ROM_KEY(quad);
+		value = CONFIG_ROM_VALUE(quad);
+
+		todo = 0;
+		switch (code) {
+		case CONFIG_ROM_VENDOR_ID:
+			todo = UNIT_DIRECTORY_VENDOR_TEXT;
 			break;
-	}
-	*quad = be32_to_cpu(*quad);
 
-	return ret;
-}
+		case CONFIG_ROM_MODEL_ID:
+			todo = UNIT_DIRECTORY_MODEL_TEXT;
+			break;
 
-#define CONFIG_ROM_VENDOR_ID		0x03
-#define CONFIG_ROM_MODEL_ID		0x17
-#define CONFIG_ROM_NODE_CAPABILITES	0x0C
-#define CONFIG_ROM_UNIT_DIRECTORY	0xd1
-#define CONFIG_ROM_SPECIFIER_ID		0x12 
-#define CONFIG_ROM_VERSION		0x13
-#define CONFIG_ROM_DESCRIPTOR_LEAF	0x81
-#define CONFIG_ROM_DESCRIPTOR_DIRECTORY	0xc1
+		case CONFIG_ROM_SPECIFIER_ID:
+		case CONFIG_ROM_UNIT_SW_VERSION:
+			break;
+
+		case CONFIG_ROM_DESCRIPTOR_LEAF:
+		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
+			/* TODO: read strings... icons? */
+			break;
+
+		default:
+			/* Which types of quadlets do we want to
+			   store?  Only count immediate values and
+			   CSR offsets for now.  */
+			code &= CONFIG_ROM_KEY_TYPE_MASK;
+			if ((code & 0x80) == 0)
+				count++;
+			break;
+		}
+
+		if (todo && length > 0) {
+			/* Check if there is a text descriptor leaf
+			   immediately after this.  */
+			size = nodemgr_size_text_leaf(ne->host,
+						      ne->nodeid,
+						      ne->generation,
+						      address + 4);
+
+			if (todo == UNIT_DIRECTORY_VENDOR_TEXT)
+				vendor_name_size = size;
+			else
+				model_name_size = size;
+
+			if (size > 0) {
+				address += 4;
+				length--;
+				flags |= todo;
+				total_size += (size + 1) * sizeof (quadlet_t);
+			}
+			else if (size < 0)
+				return NULL;
+		}
+	}
+	total_size += count * sizeof (quadlet_t);
+	ud = kmalloc (total_size, GFP_KERNEL);
+	if (ud != NULL) {
+		memset (ud, 0, sizeof *ud);
+		ud->flags = flags;
+		ud->count = count;
+		ud->vendor_name_size = vendor_name_size;
+		ud->model_name_size = model_name_size;
+		/* If there is no vendor name in the unit directory,
+		   use the one in the root directory.  */
+		ud->vendor_name = ne->vendor_name;
+	}
+	return ud;
+}
 
 /* This implementation currently only scans the config rom and its
  * immediate unit directories looking for software_id and
@@ -156,41 +464,73 @@
 					   octlet_t address)
 {
 	struct unit_directory *ud;
-	octlet_t a;
 	quadlet_t quad;
-	int length, i;
+	quadlet_t *infop;
+	int length;
 
-	if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL)))
+	if (!(ud = nodemgr_scan_unit_directory(ne, address)))
 		goto unit_directory_error;
 
-	memset (ud, 0, sizeof *ud);
 	ud->ne = ne;
 	ud->address = address;
-	ud->arb_count = 0;
 
-	if (nodemgr_read_quadlet(ne, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+				 address, &quad))
 		goto unit_directory_error;
-	length = quad >> 16;
-	a = address + 4;
+	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
+	address += 4;
 
-	for (i = 0; i < length; i++, a += 4) {
+	infop = (quadlet_t *) ud->quadlets;
+	for (; length > 0; length--, address += 4, infop++) {
 		int code;
 		quadlet_t value;
+		quadlet_t *quadp;
 
-		if (nodemgr_read_quadlet(ne, a, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+					 address, &quad))
 			goto unit_directory_error;
-		code = quad >> 24;
-		value = quad & 0xffffff;
+		code = CONFIG_ROM_KEY(quad) ;
+		value = CONFIG_ROM_VALUE(quad);
 
 		switch (code) {
 		case CONFIG_ROM_VENDOR_ID:
 			ud->vendor_id = value;
 			ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
+			if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) {
+				length--;
+				address += 4;
+				quadp = &(ud->quadlets[ud->count]);
+				if (nodemgr_read_text_leaf(ne, address,
+							   quadp) == 0
+				    && quadp[0] == 0
+				    && quadp[1] == 0) {
+				    	/* We only support minimal
+					   ASCII and English. */
+					quadp[ud->vendor_name_size] = 0;
+					ud->vendor_name
+						= (const char *) &(quadp[2]);
+				}
+			}
 			break;
 
 		case CONFIG_ROM_MODEL_ID:
 			ud->model_id = value;
 			ud->flags |= UNIT_DIRECTORY_MODEL_ID;
+			if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) {
+				length--;
+				address += 4;
+				quadp = &(ud->quadlets[ud->count + ud->vendor_name_size + 1]);
+				if (nodemgr_read_text_leaf(ne, address,
+							   quadp) == 0
+				    && quadp[0] == 0
+				    && quadp[1] == 0) {
+				    	/* We only support minimal
+					   ASCII and English. */
+					quadp[ud->model_name_size] = 0;
+					ud->model_name
+						= (const char *) &(quadp[2]);
+				}
+			}
 			break;
 
 		case CONFIG_ROM_SPECIFIER_ID:
@@ -198,7 +538,7 @@
 			ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
 			break;
 
-		case CONFIG_ROM_VERSION:
+		case CONFIG_ROM_UNIT_SW_VERSION:
 			ud->version = value;
 			ud->flags |= UNIT_DIRECTORY_VERSION;
 			break;
@@ -209,12 +549,13 @@
 			break;
 
 		default:
-			if (ud->arb_count < 16) {
-				/* Place them in the arbitrary pairs */
-				ud->arb_keys[ud->arb_count] = code;
-				ud->arb_values[ud->arb_count] = value;
-				ud->arb_count++;
-			}
+			/* Which types of quadlets do we want to
+			   store?  Only count immediate values and
+			   CSR offsets for now.  */
+			code &= CONFIG_ROM_KEY_TYPE_MASK;
+			if ((code & 0x80) == 0)
+				*infop = quad;
+			break;
 		}
 	}
 
@@ -233,53 +574,74 @@
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	struct list_head *l;
 
-	HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x",
-		   ne->vendor_id, ne->capabilities);
+	HPSB_DEBUG("vendor_id=0x%06x [%s], capabilities=0x%06x",
+		   ne->vendor_id, ne->vendor_name ?: "Unknown",
+		   ne->capabilities);
 	list_for_each (l, &ne->unit_directories) {
 		struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
 		HPSB_DEBUG("unit directory:");
 		if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
-			HPSB_DEBUG("  vendor_id=0x%06x ", ud->vendor_id);
+			HPSB_DEBUG("  vendor_id=0x%06x [%s]",
+				   ud->vendor_id,
+				   ud->vendor_name ?: "Unknown");
 		if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
-			HPSB_DEBUG("  model_id=0x%06x ", ud->model_id);
+			HPSB_DEBUG("  model_id=0x%06x [%s]",
+				   ud->model_id,
+				   ud->model_name ?: "Unknown");
 		if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
 			HPSB_DEBUG("  sw_specifier_id=0x%06x ", ud->specifier_id);
 		if (ud->flags & UNIT_DIRECTORY_VERSION)
 			HPSB_DEBUG("  sw_version=0x%06x ", ud->version);
 	}
-#else
-	return;
 #endif
+	return;
 }
 
 static void nodemgr_process_root_directory(struct node_entry *ne)
 {
 	octlet_t address;
 	quadlet_t quad;
-	int length, i;
+	int length;
 
 	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
 	
-	if (nodemgr_read_quadlet(ne, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+				 address, &quad))
 		return;
-	address += 4 + (quad >> 24) * 4;
+	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
 
-	if (nodemgr_read_quadlet(ne, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+				 address, &quad))
 		return;
-	length = quad >> 16;
+	length = CONFIG_ROM_ROOT_LENGTH(quad);
 	address += 4;
 
-	for (i = 0; i < length; i++, address += 4) {
+	for (; length > 0; length--, address += 4) {
 		int code, value;
 
-		if (nodemgr_read_quadlet(ne, address, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+					 address, &quad))
 			return;
-		code = quad >> 24;
-		value = quad & 0xffffff;
+		code = CONFIG_ROM_KEY(quad);
+		value = CONFIG_ROM_VALUE(quad);
 
 		switch (code) {
 		case CONFIG_ROM_VENDOR_ID:
 			ne->vendor_id = value;
+			/* Now check if there is a vendor name text
+			   string.  */
+			if (ne->vendor_name != NULL) {
+				length--;
+				address += 4;
+				if (nodemgr_read_text_leaf(ne, address,
+							   ne->quadlets)
+				    != 0
+				    || ne->quadlets [0] != 0
+				    || ne->quadlets [1] != 0)
+				    	/* We only support minimal
+					   ASCII and English. */
+					ne->vendor_name = NULL;
+			}
 			break;
 
 		case CONFIG_ROM_NODE_CAPABILITES:
@@ -307,6 +669,10 @@
 	char *argv [3], **envp, *buf, *scratch;
 	int i = 0, value;
 
+	/* User requested to disable hotplug when module was loaded. */
+	if (nodemgr_disable_hotplug)
+		return;
+
 	if (!hotplug_path [0])
 		return;
 	if (!current->fs->root)
@@ -578,7 +944,8 @@
  * the to take whatever actions required.
  */
 static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,
-                               struct hpsb_host *host, nodeid_t nodeid)
+                               struct hpsb_host *host,
+				nodeid_t nodeid, unsigned int generation)
 {
 	struct list_head *lh;
 	struct unit_directory *ud;
@@ -593,7 +960,7 @@
 		nodemgr_process_config_rom (ne, busoptions);
 
 	/* Since that's done, we can declare this record current */
-	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
+	ne->generation = generation;
 
 	list_for_each (lh, &ne->unit_directories) {
 		ud = list_entry (lh, struct unit_directory, node_list);
@@ -602,70 +969,61 @@
 	}
 }
 
-static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid,
+static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation,
 			      quadlet_t *buffer, int buffer_length)
 {
-	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
-	int retries = 3;
-	int header_count;
+	octlet_t addr = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
 	unsigned header_size;
-	quadlet_t quad;
-
-retry_configrom:
-
-	if (!retries--) {
-		HPSB_ERR("Giving up on node " NODE_BUS_FMT
-			 " for ConfigROM probe, too many errors",
-			 NODE_BUS_ARGS(nodeid));
-		return -1;
-	}
+	int i;
 
-	header_count = 0;
-	header_size = 0;
+	/* IEEE P1212 says that devices should support 64byte block
+	 * reads, aligned on 64byte boundaries. That doesn't seem to
+	 * work though, and we are forced to doing quadlet sized
+	 * reads.  */
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,
 		  NODE_BUS_ARGS(nodeid));
 #endif
 
-	/* Now, P1212 says that devices should support 64byte block
-	 * reads, aligned on 64byte boundaries. That doesn't seem
-	 * to work though, and we are forced to doing quadlet
-	 * sized reads.  */
-
-	if (hpsb_read(host, nodeid, base, &quad, 4)) {
-		HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT,
-			 NODE_BUS_ARGS(nodeid));
-		goto retry_configrom;
+	if (nodemgr_read_quadlet(host, nodeid, generation,
+				 addr, &buffer[0]) < 0) {
+		HPSB_ERR("ConfigROM quadlet transaction error for node "
+			 NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));
+		return -1;
 	}
-	buffer[header_count++] = be32_to_cpu(quad);
 
 	header_size = buffer[0] >> 24;
+	addr += 4;
 
 	if (header_size < 4) {
-		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), "
-			  "cannot parse", NODE_BUS_ARGS(nodeid), header_size);
+		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "
+			  "format (%d quads), cannot parse",
+			  NODE_BUS_ARGS(nodeid), header_size);
 		return -1;
 	}
 
-	while (header_count <= header_size && header_count < buffer_length) {
-		if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {
-			HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT,
+	for (i = 1; i < buffer_length; i++, addr += 4) {
+		if (nodemgr_read_quadlet(host, nodeid, generation,
+					 addr, &buffer[i]) < 0) {
+			HPSB_ERR("ConfigROM quadlet transaction "
+				 "error for node " NODE_BUS_FMT,
 				 NODE_BUS_ARGS(nodeid));
-			goto retry_configrom;
+			return -1;
 		}
-		buffer[header_count++] = be32_to_cpu(quad);
 	}
 
 	return 0;
-}
+}		
 
 static void nodemgr_remove_node(struct node_entry *ne)
 {
 	unsigned long flags;
 
-	HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx",
-		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+	HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
+		   (ne->host->node_id == ne->nodeid) ? "Host" : "Device",
+		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid,
+		   ne->vendor_name ?: "Unknown");
 
 	write_lock_irqsave(&unit_directory_lock, flags);
 	nodemgr_free_unit_directories(ne);
@@ -676,19 +1034,11 @@
 	return;
 }
 
-/* Used to schedule each nodes config rom probe */
-struct node_probe_task {
-	nodeid_t nodeid;
-	struct hpsb_host *host;
-	atomic_t *count;
-	struct tq_struct task;
-};
-
 /* This is where we probe the nodes for their information and provided
  * features.  */
-static void nodemgr_node_probe_one(void *__npt)
+static void nodemgr_node_probe_one(struct hpsb_host *host,
+				   nodeid_t nodeid, int generation)
 {
-	struct node_probe_task *npt = (struct node_probe_task *)__npt;
 	struct node_entry *ne;
 	quadlet_t buffer[5];
 	octlet_t guid;
@@ -696,130 +1046,121 @@
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
 
-	if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2))
-		goto probe_complete;
+	if (read_businfo_block (host, nodeid, generation,
+				buffer, sizeof(buffer) >> 2))
+		return;
 
 	if (buffer[1] != IEEE1394_BUSID_MAGIC) {
 		/* This isn't a 1394 device */
 		HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
-			 NODE_BUS_ARGS(npt->nodeid));
-		goto probe_complete;
+			 NODE_BUS_ARGS(nodeid));
+		return;
 	}
 
 	guid = ((u64)buffer[3] << 32) | buffer[4];
 	ne = hpsb_guid_get_entry(guid);
 
 	if (!ne)
-		nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid);
+		nodemgr_create_node(guid, buffer[2], host, nodeid, generation);
 	else
-		nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid);
-
-probe_complete:
-	atomic_dec(npt->count);
-
-	kfree(npt);
+		nodemgr_update_node(ne, buffer[2], host, nodeid, generation);
 
 	return;
 }
 
-static void nodemgr_node_probe_cleanup(void *__npt)
+static void nodemgr_node_probe_cleanup(struct hpsb_host *host, unsigned int generation)
 {
-	struct node_probe_task *npt = (struct node_probe_task *)__npt;
 	unsigned long flags;
 	struct list_head *lh, *next;
 	struct node_entry *ne;
 
-	/* If things aren't done yet, reschedule ourselves. */
-        if (atomic_read(npt->count)) {
-                schedule_task(&npt->task);
-		return;
-	}
-
-	kfree(npt->count);
-
 	/* Now check to see if we have any nodes that aren't referenced
 	 * any longer.  */
 	write_lock_irqsave(&node_lock, flags);
-	for (lh = node_list.next; lh != &node_list; lh = next) {
+	list_for_each_safe(lh, next, &node_list) {
 		ne = list_entry(lh, struct node_entry, list);
-		next = lh->next;
 
 		/* Only checking this host */
-		if (ne->host != npt->host)
+		if (ne->host != host)
 			continue;
 
 		/* If the generation didn't get updated, then either the
 		 * node was removed, or it failed the above probe. Either
 		 * way, we remove references to it, since they are
 		 * invalid.  */
-		if (!hpsb_node_entry_valid(ne))
+		if (ne->generation != generation)
 			nodemgr_remove_node(ne);
 	}
 	write_unlock_irqrestore(&node_lock, flags);
 
-	kfree(npt);
-
 	return;
 }
 
-static void nodemgr_node_probe(void *__host)
+static void nodemgr_node_probe(struct hpsb_host *host)
 {
-	struct hpsb_host *host = (struct hpsb_host *)__host;
-	int nodecount = host->node_count;
+	int count;
 	struct selfid *sid = (struct selfid *)host->topology_map;
 	nodeid_t nodeid = LOCAL_BUS;
-	struct node_probe_task *npt;
-	atomic_t *count;
+	unsigned int generation;
 
-	count = kmalloc(sizeof (*count), GFP_KERNEL);
-
-	if (count == NULL) {
-		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
+	/* Pause for 1 second, to make sure things settle down. If
+	 * schedule_timeout returns non-zero, it means we caught a signal
+	 * and need to return. */
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (schedule_timeout (HZ))
 		return;
-	}
 
-	atomic_set(count, 0);
-
-	for (; nodecount; nodecount--, nodeid++, sid++) {
-		while (sid->extended)
-			sid++;
-		if (!sid->link_active || nodeid == host->node_id)
+	/* Now get the generation in which the node ID's we collect
+	 * are valid.  During the bus scan we will use this generation
+	 * for the read transactions, so that if another reset occurs
+	 * during the scan the transactions will fail instead of
+	 * returning bogus data. */
+	generation = get_hpsb_generation(host);
+
+	/* Scan each node on the bus */
+	for (count = host->selfid_count; count; count--, sid++) {
+		if (sid->extended)
 			continue;
 
-		npt = kmalloc(sizeof (*npt), GFP_KERNEL);
-
-		if (npt == NULL) {
-			HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
-			break;
+		if (!sid->link_active) {
+			nodeid++;
+			continue;
 		}
 
-		INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt);
-		npt->host = host;
-		npt->nodeid = nodeid;
-		npt->count = count;
+		nodemgr_node_probe_one(host, nodeid++, generation);
+	}
 
-		atomic_inc(count);
+	/* If we had a bus reset while we were scanning the bus, it is
+	 * possible that we did not probe all nodes.  In that case, we
+	 * skip the clean up for now, since we could remove nodes that
+	 * were still on the bus.  The bus reset increased
+	 * hi->reset_sem, so there's a bus scan pending which will do
+	 * the clean up eventually. */
+	if (generation == get_hpsb_generation(host))
+		nodemgr_node_probe_cleanup(host, generation);
 
-		schedule_task(&npt->task);
-	}
+	return;
+}
+
+static int nodemgr_host_thread(void *__hi)
+{
+	struct host_info *hi = (struct host_info *)__hi;
 
-	/* Now schedule a task to clean things up after the node probes
-	 * are done.  */
-	npt = kmalloc (sizeof (*npt), GFP_KERNEL);
+	/* No userlevel access needed */
+	daemonize();
 
-	if (npt == NULL) {
-		HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe");
-		return;
-	}
+	strcpy(current->comm, "knodemgrd");
 
-	INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt);
-	npt->host = host;
-	npt->nodeid = 0;
-	npt->count = count;
+	/* Sit and wait for a signal to probe the nodes on the bus. This
+	 * happens when we get a bus reset. */
+	while (!down_interruptible(&hi->reset_sem))
+		nodemgr_node_probe(hi->host);
 
-	schedule_task(&npt->task);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);
+#endif
 
-	return;
+	complete_and_exit(&hi->exited, 0);
 }
 
 struct node_entry *hpsb_guid_get_entry(u64 guid)
@@ -846,23 +1187,57 @@
 	return ne;
 }
 
-struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne)
+/* The following four convenience functions use a struct node_entry
+ * for addressing a node on the bus.  They are intended for use by any
+ * process context, not just the nodemgr thread, so we need to be a
+ * little careful when reading out the node ID and generation.  The
+ * thing that can go wrong is that we get the node ID, then a bus
+ * reset occurs, and then we read the generation.  The node ID is
+ * possibly invalid, but the generation is current, and we end up
+ * sending a packet to a the wrong node.
+ *
+ * The solution is to make sure we read the generation first, so that
+ * if a reset occurs in the process, we end up with a stale generation
+ * and the transactions will fail instead of silently using wrong node
+ * ID's.
+ */
+
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
 {
-        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))
-		return NULL;
-        if (ne->nodeid == ne->host->node_id) return ne->host;
-        return NULL;
+        pkt->host = ne->host;
+        pkt->generation = ne->generation;
+	barrier();
+        pkt->node_id = ne->nodeid;
 }
 
-int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
+int hpsb_node_read(struct node_entry *ne, u64 addr,
+		   quadlet_t *buffer, size_t length)
 {
-        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))
-		return 0;
+	unsigned int generation = ne->generation;
 
-        pkt->host = ne->host;
-        pkt->node_id = ne->nodeid;
-        pkt->generation = atomic_read(&ne->generation);
-        return 1;
+	barrier();
+	return hpsb_read(ne->host, ne->nodeid, generation,
+			 addr, buffer, length);
+}
+
+int hpsb_node_write(struct node_entry *ne, u64 addr, 
+		    quadlet_t *buffer, size_t length)
+{
+	unsigned int generation = ne->generation;
+
+	barrier();
+	return hpsb_write(ne->host, ne->nodeid, generation,
+			  addr, buffer, length);
+}
+
+int hpsb_node_lock(struct node_entry *ne, u64 addr, 
+		   int extcode, quadlet_t *data, quadlet_t arg)
+{
+	unsigned int generation = ne->generation;
+
+	barrier();
+	return hpsb_lock(ne->host, ne->nodeid, generation,
+			 addr, extcode, data, arg);
 }
 
 static void nodemgr_add_host(struct hpsb_host *host)
@@ -875,11 +1250,23 @@
 		return;
 	}
 
-	/* We simply initialize the struct here. We don't start the thread
-	 * until the first bus reset.  */
+	/* Initialize the hostinfo here and start the thread.  The
+	 * thread blocks on the reset semaphore until a bus reset
+	 * happens. */
 	hi->host = host;
 	INIT_LIST_HEAD(&hi->list);
-	INIT_TQUEUE(&hi->task, nodemgr_node_probe, host);
+	init_completion(&hi->exited);
+        sema_init(&hi->reset_sem, 0);
+
+	hi->pid = kernel_thread(nodemgr_host_thread, hi,
+				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	
+	if (hi->pid < 0) {
+		HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s",
+			  host->driver->name);
+		kfree(hi);
+		return;
+	}
 
 	spin_lock_irqsave (&host_info_lock, flags);
 	list_add_tail (&hi->list, &host_info_list);
@@ -908,7 +1295,10 @@
 		goto done_reset_host;
 	}
 
-	schedule_task(&hi->task);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
+#endif
+	up(&hi->reset_sem);
 
 done_reset_host:
 	spin_unlock_irqrestore (&host_info_lock, flags);
@@ -921,40 +1311,42 @@
 	struct list_head *lh, *next;
 	struct node_entry *ne;
 	unsigned long flags;
+	struct host_info *hi = NULL;
+
+	spin_lock_irqsave (&host_info_lock, flags);
+	list_for_each_safe(lh, next, &host_info_list) {
+		struct host_info *myhi = list_entry(lh, struct host_info, list);
+		if (myhi->host == host) {
+			list_del(&myhi->list);
+			hi = myhi;
+			break;
+		}
+	}
 
-	/* Make sure we have no active scans */
-	flush_scheduled_tasks();
+	if (!hi)
+		HPSB_ERR ("NodeMgr: host %s does not exist, cannot remove",
+			  host->driver->name);
+	spin_unlock_irqrestore (&host_info_lock, flags);
 
-	/* First remove all node entries for this host */
+	/* Even if we fail the host_info part, remove all the node
+	 * entries.  */
 	write_lock_irqsave(&node_lock, flags);
-
-	for (lh = node_list.next; lh != &node_list; lh = next) {
+	list_for_each_safe(lh, next, &node_list) {
 		ne = list_entry(lh, struct node_entry, list);
-		next = lh->next;
 
-		/* Only checking this host */
-		if (ne->host != host)
-			continue;
-
-		nodemgr_remove_node(ne);
+		if (ne->host == host)
+			nodemgr_remove_node(ne);
 	}
 	write_unlock_irqrestore(&node_lock, flags);
 
-	spin_lock_irqsave (&host_info_lock, flags);
-	list_for_each_safe(lh, next, &host_info_list) {
-		struct host_info *hi = list_entry(lh, struct host_info, list);
-		if (hi->host == host) {
-			list_del(&hi->list);
-			kfree (hi);
-			break;
+	if (hi) {
+		if (hi->pid >= 0) {
+			kill_proc(hi->pid, SIGTERM, 1);
+			wait_for_completion(&hi->exited);
 		}
+		kfree(hi);
 	}
 
-	if (lh == host_info_list.next)
-		HPSB_ERR ("NodeMgr: could not remove non-existent host");
-
-	spin_unlock_irqrestore (&host_info_lock, flags);
-
 	return;
 }
 
@@ -966,8 +1358,15 @@
 
 static struct hpsb_highlevel *hl;
 
-void init_ieee1394_nodemgr(void)
+#define PROC_ENTRY "devices"
+
+void init_ieee1394_nodemgr(int disable_hotplug)
 {
+	nodemgr_disable_hotplug = disable_hotplug;
+#ifdef CONFIG_PROC_FS
+	if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL))
+		HPSB_ERR("Can't create devices procfs entry");
+#endif
         hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
         if (!hl) {
 		HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
@@ -977,4 +1376,7 @@
 void cleanup_ieee1394_nodemgr(void)
 {
         hpsb_unregister_highlevel(hl);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry);
+#endif
 }
diff -urN linux-2.4.19-pre4/drivers/ieee1394/nodemgr.h linux-2.4.19-pre5/drivers/ieee1394/nodemgr.h
--- linux-2.4.19-pre4/drivers/ieee1394/nodemgr.h	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/nodemgr.h	Fri Mar 29 14:49:31 2002
@@ -20,6 +20,44 @@
 #ifndef _IEEE1394_NODEMGR_H
 #define _IEEE1394_NODEMGR_H
 
+#define CONFIG_ROM_BUS_INFO_LENGTH(q)		((q) >> 24)
+#define CONFIG_ROM_BUS_CRC_LENGTH(q)		(((q) >> 16) & 0xff)
+#define CONFIG_ROM_BUS_CRC(q)			((q) & 0xffff)
+
+#define CONFIG_ROM_ROOT_LENGTH(q)		((q) >> 16)
+#define CONFIG_ROM_ROOT_CRC(q)			((q) & 0xffff)
+
+#define CONFIG_ROM_DIRECTORY_LENGTH(q)		((q) >> 16)
+#define CONFIG_ROM_DIRECTORY_CRC(q)		((q) & 0xffff)
+
+#define CONFIG_ROM_LEAF_LENGTH(q)		((q) >> 16)
+#define CONFIG_ROM_LEAF_CRC(q)			((q) & 0xffff)
+
+#define CONFIG_ROM_DESCRIPTOR_TYPE(q)		((q) >> 24)
+#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q)	((q) & 0xffffff)
+#define CONFIG_ROM_DESCRIPTOR_WIDTH(q)		((q) >> 28)
+#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q)	(((q) >> 16) & 0xfff)
+#define CONFIG_ROM_DESCRIPTOR_LANG(q)		((q) & 0xffff)
+
+#define CONFIG_ROM_KEY_ID_MASK			0x3f
+#define CONFIG_ROM_KEY_TYPE_MASK		0xc0
+#define CONFIG_ROM_KEY_TYPE_IMMEDIATE		0x00
+#define CONFIG_ROM_KEY_TYPE_OFFSET		0x40
+#define CONFIG_ROM_KEY_TYPE_LEAF		0x80
+#define CONFIG_ROM_KEY_TYPE_DIRECTORY		0xc0
+
+#define CONFIG_ROM_KEY(q)			((q) >> 24)
+#define CONFIG_ROM_VALUE(q)			((q) & 0xffffff)
+
+#define CONFIG_ROM_VENDOR_ID			0x03
+#define CONFIG_ROM_MODEL_ID			0x17
+#define CONFIG_ROM_NODE_CAPABILITES		0x0C
+#define CONFIG_ROM_UNIT_DIRECTORY		0xd1
+#define CONFIG_ROM_SPECIFIER_ID			0x12 
+#define CONFIG_ROM_UNIT_SW_VERSION		0x13
+#define CONFIG_ROM_DESCRIPTOR_LEAF		0x81
+#define CONFIG_ROM_DESCRIPTOR_DIRECTORY		0xc1
+
 /* '1' '3' '9' '4' in ASCII */
 #define IEEE1394_BUSID_MAGIC	0x31333934
 
@@ -42,6 +80,8 @@
 #define UNIT_DIRECTORY_MODEL_ID		0x02
 #define UNIT_DIRECTORY_SPECIFIER_ID	0x04
 #define UNIT_DIRECTORY_VERSION		0x08
+#define UNIT_DIRECTORY_VENDOR_TEXT	0x10
+#define UNIT_DIRECTORY_MODEL_TEXT	0x20
 
 /*
  * A unit directory corresponds to a protocol supported by the
@@ -58,17 +98,14 @@
 	octlet_t address;	/* Address of the unit directory on the node */
 	u8 flags;		/* Indicates which entries were read */
 	quadlet_t vendor_id;
-	char *vendor_name;
+	const char *vendor_name;
+	int vendor_name_size;
 	quadlet_t model_id;
-	char *model_name;
+	const char *model_name;
+	int model_name_size;
 	quadlet_t specifier_id;
 	quadlet_t version;
 
-	/* Groupings for arbitrary key/value pairs */
-	int arb_count;			/* Number of arbitrary key/values */
-	char arb_keys[16];		/* Up to 16 keys */
-	quadlet_t arb_values[16];	/* Same for values */
-
 	struct hpsb_protocol_driver *driver;
 	void *driver_data;
 
@@ -77,6 +114,9 @@
 
 	/* For linking directories belonging to a node */
 	struct list_head node_list;
+
+	int count;		/* Number of quadlets */
+	quadlet_t quadlets[0];
 };
 
 struct node_entry {
@@ -85,17 +125,20 @@
 	struct hpsb_host *host;		/* Host this node is attached to */
 	nodeid_t nodeid;		/* NodeID */
 	struct bus_options busopt;	/* Bus Options */
-	atomic_t generation;		/* Synced with hpsb generation */
+	unsigned int generation;	/* Synced with hpsb generation */
 
 	/* The following is read from the config rom */
 	u32 vendor_id;
 	u32 capabilities;	
 	struct list_head unit_directories;
+
+	const char *vendor_name;
+	quadlet_t quadlets[0];
 };
 
 static inline int hpsb_node_entry_valid(struct node_entry *ne)
 {
-	return atomic_read(&ne->generation) == get_hpsb_generation(ne->host);
+	return ne->generation == get_hpsb_generation(ne->host);
 }
 
 /*
@@ -127,10 +170,17 @@
  * number).  It will at least reliably fail so that you don't accidentally and
  * unknowingly send your packet to the wrong node.
  */
-int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
+
+int hpsb_node_read(struct node_entry *ne, u64 addr,
+		   quadlet_t *buffer, size_t length);
+int hpsb_node_write(struct node_entry *ne, u64 addr, 
+		    quadlet_t *buffer, size_t length);
+int hpsb_node_lock(struct node_entry *ne, u64 addr, 
+		   int extcode, quadlet_t *data, quadlet_t arg);
 
 
-void init_ieee1394_nodemgr(void);
+void init_ieee1394_nodemgr(int disable_hotplug);
 void cleanup_ieee1394_nodemgr(void);
 
 #endif /* _IEEE1394_NODEMGR_H */
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ohci1394.c linux-2.4.19-pre5/drivers/ieee1394/ohci1394.c
--- linux-2.4.19-pre4/drivers/ieee1394/ohci1394.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ohci1394.c	Fri Mar 29 14:49:31 2002
@@ -77,6 +77,12 @@
  *  . Config ROM generation
  */
 
+/* Issues:
+ *
+ * - devctl BUS_RESET should treat arg as reset type
+ *
+ */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -99,7 +105,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
@@ -136,10 +141,10 @@
 
 #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
 #define OHCI_DMA_ALLOC(fmt, args...) \
-	HPSB_ERR("%s("__FUNCTION__")alloc(%d): "fmt, OHCI1394_DRIVER_NAME, \
+	HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
 		++global_outstanding_dmas, ## args)
 #define OHCI_DMA_FREE(fmt, args...) \
-	HPSB_ERR("%s("__FUNCTION__")free(%d): "fmt, OHCI1394_DRIVER_NAME, \
+	HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
 		--global_outstanding_dmas, ## args)
 u32 global_outstanding_dmas = 0;
 #else
@@ -155,35 +160,23 @@
 #define PRINT(level, card, fmt, args...) \
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
-#define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
-static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
-	{
-		class: 		PCI_CLASS_FIREWIRE_OHCI,
-		class_mask: 	0x00ffffff,
-		vendor:		PCI_ANY_ID,
-		device:		PCI_ANY_ID,
-		subvendor:	PCI_ANY_ID,
-		subdevice:	PCI_ANY_ID,
-	},
-	{ 0, },
-};
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
 static char version[] __devinitdata =
-	"$Revision: 1.80 $ Ben Collins <bcollins@debian.org>";
+	"$Revision: 1.101 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
 MODULE_PARM_DESC(attempt_root, "Attempt to make the host root.");
 static int attempt_root = 0;
 
-static unsigned int card_id_counter = 0;
-
 static void dma_trm_tasklet(unsigned long data);
-static void remove_card(struct ti_ohci *ohci);
 static void dma_trm_reset(struct dma_trm_ctx *d);
 
+static void __devexit ohci1394_pci_remove(struct pci_dev *pdev);
+
+static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
+					  quadlet_t isoRecvEvent, 
+					  quadlet_t isoXmitEvent);
+
 #ifndef __LITTLE_ENDIAN
 /* Swap a series of quads inplace. */
 static __inline__ void block_swab32(quadlet_t *data, size_t size) {
@@ -311,8 +304,8 @@
 	if ((self_id_count & 0x80000000) || 
 	    ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
 		PRINT(KERN_ERR, ohci->id, 
-		      "Error in reception of SelfID packets [0x%08x/0x%08x]",
-		      self_id_count, q0);
+		      "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
+		      self_id_count, q0, ohci->self_id_errors);
 
 		/* Tip by James Goodwin <jamesg@Filanet.com>:
 		 * We had an error, generate another bus reset in response.  */
@@ -325,6 +318,9 @@
 		}
 		return;
 	}
+
+	/* SelfID Ok, reset error counter. */
+	ohci->self_id_errors = 0;
 	
 	size = ((self_id_count & 0x00001FFC) >> 2) - 1;
 	q++;
@@ -358,7 +354,7 @@
 	return;
 }
 
-static int ohci_soft_reset(struct ti_ohci *ohci) {
+static void ohci_soft_reset(struct ti_ohci *ohci) {
 	int i;
 
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
@@ -369,9 +365,13 @@
 		mdelay(1);
 	}
 
-	DBGMSG (ohci->id, "Soft reset finished");
+	/* Now reenable LPS, since that's usually what we want after a
+	 * softreset anyway. Wait 50msec to make sure we have full link
+	 * enabled.  */
+	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+	mdelay(50);
 
-	return 0;
+	DBGMSG (ohci->id, "Soft reset finished");
 }
 
 static int run_context(struct ti_ohci *ohci, int reg, char *msg)
@@ -412,8 +412,7 @@
 	for (i=0; i<d->num_desc; i++) {
 		u32 c;
 		
-		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-			DMA_CTL_BRANCH;
+		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
 		if (generate_irq)
 			c |= DMA_CTL_IRQ;
 				
@@ -486,19 +485,13 @@
 static void ohci_init_config_rom(struct ti_ohci *ohci);
 
 /* Global initialization */
-static int ohci_initialize(struct hpsb_host *host)
+static void ohci_initialize(struct ti_ohci *ohci)
 {
-	struct ti_ohci *ohci=host->hostdata;
-	int retval, i;
 	quadlet_t buf;
 
 	spin_lock_init(&ohci->phy_reg_lock);
 	spin_lock_init(&ohci->event_lock);
   
-	/* Soft reset */
-	if ((retval = ohci_soft_reset(ohci)) < 0)
-		return retval;
-
 	/* Put some defaults to these undefined bus options */
 	buf = reg_read(ohci, OHCI1394_BusOptions);
 	buf |=  0x60000000; /* Enable CMC and ISC */
@@ -506,16 +499,6 @@
 	buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */
 	reg_write(ohci, OHCI1394_BusOptions, buf);
 
-	/* Set Link Power Status (LPS) */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
-
-	/* After enabling LPS, we need to wait for the connection
-	 * between phy and link to be established.  This should be
-	 * signaled by the LPS bit becoming 1, but this happens
-	 * immediately.  There seems to be no consistent way to wait
-	 * for this, but 50ms seems to be enough. */
-	mdelay(50);
-
 	/* Set the bus number */
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
 
@@ -551,18 +534,6 @@
 	/* Don't accept phy packets into AR request context */ 
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
 
-	/* Initialize IR dma */
-	ohci->nb_iso_rcv_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-	DBGMSG(ohci->id, "%d iso receive contexts available",
-	       ohci->nb_iso_rcv_ctx);
-	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
-		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
-			  0xffffffff);
-		reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);
-		reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);
-	}
-
 	/* Set bufferFill, isochHeader, multichannel for IR context */
 	reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
 			
@@ -573,17 +544,6 @@
 	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
 
-	/* Initialize IT dma */
-	ohci->nb_iso_xmit_ctx = 
-		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-	DBGMSG(ohci->id, "%d iso transmit contexts available",
-	       ohci->nb_iso_xmit_ctx);
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
-		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
-			  0xffffffff);
-		reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);
-	}
-	
 	/* Clear the interrupt mask */
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
@@ -640,31 +600,19 @@
 		  OHCI1394_reqTxComplete |
 		  OHCI1394_isochRx |
 		  OHCI1394_isochTx |
-		  OHCI1394_unrecoverableError
-		);
+		  OHCI1394_cycleInconsistent);
 
 	/* Enable link */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
 
 	buf = reg_read(ohci, OHCI1394_Version);
-	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  MMIO=[%lx-%lx]"
-	      "  Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
+	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  "
+	      "MMIO=[%lx-%lx]  Max Packet=[%d]",
+	      ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
 	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
 	      pci_resource_start(ohci->dev, 0),
 	      pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),
 	      ohci->max_packet_size);
-
-	return 1;
-}
-
-static void ohci_remove(struct hpsb_host *host)
-{
-	struct ti_ohci *ohci;
-
-	if (host != NULL) {
-		ohci = host->hostdata;
-		remove_card(ohci);
-	}
 }
 
 /* 
@@ -686,7 +634,7 @@
 	d->prg_cpu[idx]->begin.address = 0;
 	d->prg_cpu[idx]->begin.branchAddress = 0;
 
-	if (d->ctx==1) {
+	if (d->type == DMA_CTX_ASYNC_RESP) {
 		/* 
 		 * For response packets, we need to put a timeout value in
 		 * the 16 lower bits of the status... let's try 1 sec timeout 
@@ -735,9 +683,9 @@
                         if (cross_bound((unsigned long)packet->data, 
                                         packet->data_size)>0) {
                                 /* FIXME: do something about it */
-                                PRINT(KERN_ERR, ohci->id, __FUNCTION__
-                                      ": packet data addr: %p size %Zd bytes "
-                                      "cross page boundary", 
+                                PRINT(KERN_ERR, ohci->id,
+                                      "%s: packet data addr: %p size %Zd bytes "
+                                      "cross page boundary", __FUNCTION__,
                                       packet->data, packet->data_size);
                         }
 
@@ -927,10 +875,8 @@
 	switch (cmd) {
 	case RESET_BUS:
 		DBGMSG(ohci->id, "devctl: Bus reset requested%s",
-		       ((host->attempt_root || attempt_root) ? 
-		       " and attempting to become root" : ""));
-		set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?
-				  0x80 : 0));
+		       attempt_root ? " and attempting to become root" : "");
+		set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0));
 		break;
 
 	case GET_CYCLE_COUNTER:
@@ -975,6 +921,7 @@
                 } else {
                         MOD_DEC_USE_COUNT;
                 }
+		retval = 1;
                 break;
 
 	case ISO_LISTEN_CHANNEL:
@@ -982,9 +929,9 @@
 		u64 mask;
 
 		if (arg<0 || arg>63) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 listen channel %d is out of range", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 listen channel %d is out of range", 
+			      __FUNCTION__, arg);
 			return -EFAULT;
 		}
 
@@ -993,9 +940,9 @@
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
 		if (ohci->ISO_channel_usage & mask) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 listen channel %d is already used", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 listen channel %d is already used", 
+			      __FUNCTION__, arg);
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
 		}
@@ -1018,9 +965,9 @@
 		u64 mask;
 
 		if (arg<0 || arg>63) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 unlisten channel %d is out of range", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 unlisten channel %d is out of range", 
+			      __FUNCTION__, arg);
 			return -EFAULT;
 		}
 
@@ -1029,9 +976,9 @@
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
 		if (!(ohci->ISO_channel_usage & mask)) {
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 unlisten channel %d is not used", 
-			      arg);
+			PRINT(KERN_ERR, ohci->id,
+			      "%s: IS0 unlisten channel %d is not used", 
+			      __FUNCTION__, arg);
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
 		}
@@ -1134,10 +1081,17 @@
 	/* Die right here an now */
 	if (event & OHCI1394_unrecoverableError) {
 		PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!");
-		remove_card(ohci);
 		return;
 	}
 
+	if (event & OHCI1394_cycleInconsistent) {
+		/* We subscribe to the cycleInconsistent event only to
+		 * clear the corresponding event bit... otherwise,
+		 * isochronous cycleMatch DMA wont work. */
+		DBGMSG(ohci->id, "OHCI1394_cycleInconsistent");
+		event &= ~OHCI1394_cycleInconsistent;
+	}
+
 	if (event & OHCI1394_busReset) {
 		/* The busReset event bit can't be cleared during the
 		 * selfID phase, so we disable busReset interrupts, to
@@ -1157,8 +1111,8 @@
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		if (!host->in_bus_reset) {
 			DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",
-			      ((host->attempt_root || attempt_root) ?
-			      " and attempting to become root" : ""));
+			      (attempt_root) ? " and attempting to become root"
+			       : "");
 
 			/* Subsystem call */
 			hpsb_bus_reset(ohci->host);
@@ -1229,9 +1183,9 @@
 			else
 				tasklet_schedule(&d->task);
 		}
-		if (ohci->video_tmpl) 
-			ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent,
-						      0);
+
+		ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0);
+
 		event &= ~OHCI1394_isochRx;
 	}
 	if (event & OHCI1394_isochTx) {
@@ -1244,9 +1198,9 @@
                        DBGMSG(ohci->id, "Got isochTx interrupt "
                                "status=0x%08x isoXmitIntEvent=%08x",
                               reg_read(ohci, d->ctrlSet), isoXmitIntEvent);
-		if (ohci->video_tmpl) 
-			ohci->video_tmpl->irq_handler(ohci->id, 0,
-						      isoXmitIntEvent);
+
+		ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent);
+		
 		if (isoXmitIntEvent & 0x1) {
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
 				ohci1394_stop_context(ohci, d->ctrlClear, "isochTx");
@@ -1305,8 +1259,8 @@
 		/* Finally, we clear the busReset event and reenable
 		 * the busReset interrupt. */
 		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		event &= ~OHCI1394_selfIDComplete;	
 	}
@@ -1353,7 +1307,7 @@
 {
 	int length = -1;
 
-	if (d->ctx < 2) { /* Async Receive Response/Request */
+	if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
 		length = TCODE_SIZE[tcode];
 		if (length == 0) {
 			if (offset + 12 >= d->buf_size) {
@@ -1364,7 +1318,7 @@
 			}
 			length += 20;
 		}
-	} else if (d->ctx == 2) { /* Iso receive */
+	} else if (d->type == DMA_CTX_ISO) {
 		/* Assumption: buffer fill mode with header/trailer */
 		length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
 	}
@@ -1394,11 +1348,8 @@
 	offset = d->buf_offset;
 	buf_ptr = d->buf_cpu[idx] + offset/4;
 
-	dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status));
 	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
 	bytes_left = d->buf_size - rescount - offset;
-	dma_cache_wback_inv(buf_ptr, bytes_left);
 
 	while (bytes_left > 0) {
 		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
@@ -1450,7 +1401,6 @@
 			insert_dma_buffer(d, idx);
 			idx = (idx+1) % d->num_desc;
 			buf_ptr = d->buf_cpu[idx];
-			dma_cache_wback_inv(buf_ptr, d->buf_size);
 			offset=0;
 
 			while (split_left >= d->buf_size) {
@@ -1460,7 +1410,6 @@
 				insert_dma_buffer(d, idx);
 				idx = (idx+1) % d->num_desc;
 				buf_ptr = d->buf_cpu[idx];
-                                dma_cache_wback_inv(buf_ptr, d->buf_size);
 			}
 
 			if (split_left > 0) {
@@ -1507,8 +1456,6 @@
 			       d->ctx);
 #endif
 
-                dma_cache_wback_inv(&(d->prg_cpu[idx]->status),
-                        sizeof(d->prg_cpu[idx]->status));
 	       	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
 
 		bytes_left = d->buf_size - rescount - offset;
@@ -1556,6 +1503,15 @@
 			/* this packet hasn't been sent yet*/
 			break;
 
+		if (!(ack & 0x10)) {
+			/* XXX: This is an OHCI evt_* code. We need to handle
+			 * this specially! For right now, we just fake an
+			 * ackx_send_error. */
+			PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x",
+			       ack & 0xf);
+			ack = (ack & 0xffe0) | ACK_BUSY_A;
+		}
+
 #ifdef OHCI1394_DEBUG
 		if (datasize)
 			DBGMSG(ohci->id,
@@ -1647,6 +1603,11 @@
 	}
 	if ((*d)->spb) kfree((*d)->spb);
 
+	/* clear ISO context usage bit */
+	if ((*d)->type == DMA_CTX_ISO) {
+		clear_bit((*d)->ctx, &ohci->ir_ctx_usage);
+	}
+	       
 	kfree(*d);
 	*d = NULL;
 
@@ -1654,15 +1615,21 @@
 }
 
 static struct dma_rcv_ctx *
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
-		  int buf_size, int split_buf_size, 
-		  int ctrlSet, int ctrlClear, int cmdPtr)
+alloc_dma_rcv_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+		  int buf_size, int split_buf_size, int context_base)
 {
-	struct dma_rcv_ctx *d=NULL;
+	struct dma_rcv_ctx *d;
 	int i;
 
-	d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), 
-					  GFP_KERNEL);
+	if (type == DMA_CTX_ISO) {
+		/* try to claim the ISO context usage bit */
+		if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) {
+			PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx);
+			return NULL;
+		}
+	}
+	
+	d = kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL);
 
 	if (d == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx");
@@ -1671,21 +1638,17 @@
 
 	memset (d, 0, sizeof (struct dma_rcv_ctx));
 
-	d->ohci = (void *)ohci;
+	d->ohci = ohci;
+	d->type = type;
 	d->ctx = ctx;
 
 	d->num_desc = num_desc;
 	d->buf_size = buf_size;
 	d->split_buf_size = split_buf_size;
-	d->ctrlSet = ctrlSet;
-	d->ctrlClear = ctrlClear;
-	d->cmdPtr = cmdPtr;
-
-	d->buf_cpu = NULL;
-	d->buf_bus = NULL;
-	d->prg_cpu = NULL;
-	d->prg_bus = NULL;
-	d->spb = NULL;
+
+	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
 
 	d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
 	d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
@@ -1784,36 +1747,47 @@
 		kfree((*d)->prg_bus);
 	}
 
+	/* clear the ISO context usage bit */
+	if ((*d)->type == DMA_CTX_ISO) {
+		clear_bit((*d)->ctx, &ohci->it_ctx_usage);
+	}
+
 	kfree(*d);
 	*d = NULL;
 	return 0;
 }
 
 static struct dma_trm_ctx *
-alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
-		  int ctrlSet, int ctrlClear, int cmdPtr)
+alloc_dma_trm_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc,
+		  int context_base)
 {
-	struct dma_trm_ctx *d=NULL;
+	struct dma_trm_ctx *d;
 	int i;
 
-	d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), 
-					  GFP_KERNEL);
+	if (type == DMA_CTX_ISO) {
+		/* try to claim the ISO context usage bit */
+		if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) {
+			PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx);
+			return NULL;
+		}
+	}
+	
+	d = kmalloc(sizeof(struct dma_trm_ctx), GFP_KERNEL);
 
-	if (d==NULL) {
+	if (d == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx");
 		return NULL;
 	}
 
 	memset (d, 0, sizeof (struct dma_trm_ctx));
 
-	d->ohci = (void *)ohci;
+	d->ohci = ohci;
+	d->type = type;
 	d->ctx = ctx;
 	d->num_desc = num_desc;
-	d->ctrlSet = ctrlSet;
-	d->ctrlClear = ctrlClear;
-	d->cmdPtr = cmdPtr;
-	d->prg_cpu = NULL;
-	d->prg_bus = NULL;
+	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
 
 	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), 
 			     GFP_KERNEL);
@@ -1827,7 +1801,7 @@
 	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
 	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
-	for (i=0; i<d->num_desc; i++) {
+	for (i = 0; i < d->num_desc; i++) {
                 d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
 						     sizeof(struct at_dma_prg),
 						     d->prg_bus+i);
@@ -1890,6 +1864,21 @@
 
 #define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))
 
+static inline void cf_put_str(struct config_rom_ptr *cr, const char *str)
+{
+	int t;
+	char fourb[4];
+
+	while (str[0]) {
+		memset(fourb, 0, 4);
+		for (t = 0; t < 4 && str[t]; t++)
+			fourb[t] = str[t];
+		cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]);
+		str += strlen(str) < 4 ? strlen(str) : 4;
+	}
+	return;
+}
+
 static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit)
 {
 	*cr->unitdir[unit].start =
@@ -1956,7 +1945,8 @@
 
 	/* Root directory */
 	cf_unit_begin(&cr, 1);
-	cf_put_keyval(&cr, 0x03, 0x00005e);	/* Vendor ID */
+	/* Vendor ID */
+	cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF);
 	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */
 	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */
 	/* NOTE: Add other unit referers here, and append at bottom */
@@ -1966,9 +1956,7 @@
 	cf_unit_begin(&cr, 2);
 	cf_put_keyval(&cr, 0, 0);
 	cf_put_1quad(&cr, 0);
-	cf_put_4bytes(&cr, 'L', 'i', 'n', 'u');
-	cf_put_4bytes(&cr, 'x', ' ', '1', '3');
-	cf_put_4bytes(&cr, '9', '4', 0x0, 0x0);
+	cf_put_str(&cr, "Linux OHCI-1394");
 	cf_unit_end(&cr);
 
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
@@ -1986,13 +1974,15 @@
 	return ohci->csr_config_rom_length * 4;
 }
 
-int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,
-                      quadlet_t compare, int sel)
+static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
+                                 quadlet_t data, quadlet_t compare)
 {
+	struct ti_ohci *ohci = host->hostdata;
 	int i;
-	reg_write(ohci, OHCI1394_CSRData, *data);
+
+	reg_write(ohci, OHCI1394_CSRData, data);
 	reg_write(ohci, OHCI1394_CSRCompareData, compare);
-	reg_write(ohci, OHCI1394_CSRControl, sel & 0x3);
+	reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
 
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
@@ -2001,68 +1991,58 @@
 		mdelay(1);
 	}
 
-	*data = reg_read(ohci, OHCI1394_CSRData);
-	return 0;
-}
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
-                                 quadlet_t data, quadlet_t compare)
-{
-	struct ti_ohci *ohci=host->hostdata;
-
-	ohci_compare_swap (ohci, &data, compare, reg);
-
-	return data;
+	return reg_read(ohci, OHCI1394_CSRData);
 }
 
-static struct hpsb_host_template ohci_template = {
-	name:			OHCI1394_DRIVER_NAME,
-	initialize_host:	ohci_initialize,
-	release_host:		ohci_remove,
+static struct hpsb_host_operations ohci1394_ops = {
 	get_rom:		ohci_get_rom,
 	transmit_packet:	ohci_transmit,
 	devctl:			ohci_devctl,
 	hw_csr_reg:		ohci_hw_csr_reg,
 };
 
+static struct hpsb_host_driver *ohci1394_driver;
+
+
+
+/***********************************
+ * PCI Driver Interface functions  *
+ ***********************************/
 
-#define FAIL(fmt, args...)			\
+#define FAIL(err, fmt, args...)			\
 do {						\
 	PRINT_G(KERN_ERR, fmt , ## args);	\
-	remove_card(ohci);			\
-	return 1;				\
+        ohci1394_pci_remove(dev);               \
+	return err;				\
 } while(0)
 
-static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
+static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
+					const struct pci_device_id *ent)
 {
-	struct ti_ohci *ohci;	/* shortcut to currently handled device */
-	struct hpsb_host *host;
-	unsigned long ohci_base, ohci_len;
+	static unsigned int card_id_counter = 0;
 	static int version_printed = 0;
 
+	struct hpsb_host *host;
+	struct ti_ohci *ohci;	/* shortcut to currently handled device */
+	unsigned long ohci_base, ohci_len;
+	int i;
+	
 	if (version_printed++ == 0)
 		PRINT_G(KERN_INFO, "%s", version);
 
-        if (pci_enable_device(dev)) {
-		/* Skip ID's that fail */
-		PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d",
-			card_id_counter++);
-		return -ENXIO;
-        }
+        if (pci_enable_device(dev))
+		FAIL(-ENXIO, "Failed to enable OHCI hardware %d",
+		        card_id_counter++);
         pci_set_master(dev);
 
-	host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci));
-	if (!host) {
-		PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");
-		return -ENOMEM;
-	}
+	host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci));
+	if (!host) FAIL(-ENOMEM, "Failed to allocate host structure");
+
 	ohci = host->hostdata;
-	ohci->host = host;
-	INIT_LIST_HEAD(&ohci->list);
 	ohci->id = card_id_counter++;
 	ohci->dev = dev;
-	host->pdev = dev;
 	ohci->host = host;
+	host->pdev = dev;
 	pci_set_drvdata(dev, ohci);
 
 	/* We don't want hardware swapping */
@@ -2090,8 +2070,54 @@
 				     &ohci->csr_config_rom_bus);
 	OHCI_DMA_ALLOC("consistent csr_config_rom");
 	if (ohci->csr_config_rom_cpu == NULL)
-		FAIL("Failed to allocate buffer config rom");
+		FAIL(-ENOMEM, "Failed to allocate buffer config rom");
 
+
+	ohci_base = pci_resource_start(dev, 0);
+	ohci_len = pci_resource_len(dev, 0);
+
+	if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME))
+		FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
+		     ohci_base, ohci_len);
+
+	ohci->registers = ioremap(ohci_base, ohci_len);
+
+	if (ohci->registers == NULL)
+		FAIL(-ENXIO, "Failed to remap registers - card not accessible");
+
+	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers);
+
+
+	/* Start off with a softreset, to clear everything to a sane
+	 * state.  This will also set Link Power State (LPS), which we
+	 * need in order to start accessing most of the registers.  */
+	ohci_soft_reset(ohci);
+
+	/* determinte the number of available IR and IT contexts right away,
+	   because they need to be known for alloc_dma_*_ctx() */
+	ohci->nb_iso_rcv_ctx = 
+		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
+	DBGMSG(ohci->id, "%d iso receive contexts available",
+	       ohci->nb_iso_rcv_ctx);
+
+	ohci->ir_ctx_usage = 0;
+	
+	/* set the usage bits for non-existent contexts so they can't be allocated */
+	for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++)
+		__set_bit(i, &ohci->ir_ctx_usage);
+	
+	ohci->nb_iso_xmit_ctx = 
+		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
+	DBGMSG(ohci->id, "%d iso transmit contexts available",
+	       ohci->nb_iso_xmit_ctx);
+
+	ohci->it_ctx_usage = 0;
+	
+	/* set the usage bits for non-existent contexts so they can't be allocated */
+	for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++)
+		__set_bit(i, &ohci->it_ctx_usage);
+
+	
 	/* 
 	 * self-id dma buffer allocation
 	 */
@@ -2100,103 +2126,101 @@
                       &ohci->selfid_buf_bus);
 	OHCI_DMA_ALLOC("consistent selfid_buf");
 	if (ohci->selfid_buf_cpu == NULL)
-		FAIL("Failed to allocate DMA buffer for self-id packets");
+		FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
 
 	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
 		PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "
 		      "8Kb boundary... may cause problems on some CXD3222 chip", 
 		      ohci->selfid_buf_cpu);  
 
-	ohci->it_context =
-		alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC,
-				  OHCI1394_IsoXmitContextControlSet,
-				  OHCI1394_IsoXmitContextControlClear,
-				  OHCI1394_IsoXmitCommandPtr);
-
-	if (ohci->it_context == NULL)
-		FAIL("Failed to allocate IT context");
-
-	ohci_base = pci_resource_start(dev, 0);
-	ohci_len = pci_resource_len(dev, 0);
-
-	if (!request_mem_region (ohci_base, ohci_len, host->template->name))
-		FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
-		     ohci_base, ohci_len);
-
-	ohci->registers = ioremap(ohci_base, ohci_len);
-
-	if (ohci->registers == NULL)
-		FAIL("Failed to remap registers - card not accessible");
-
-	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p",
-	      ohci->registers);
+	/* No self-id errors at startup */
+	ohci->self_id_errors = 0;
 
+	/* AR DMA request context allocation */
 	ohci->ar_req_context = 
-		alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
+		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
 				  AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
-				  OHCI1394_AsReqRcvContextControlSet,
-				  OHCI1394_AsReqRcvContextControlClear,
-				  OHCI1394_AsReqRcvCommandPtr);
+				  OHCI1394_AsReqRcvContextBase);
 
 	if (ohci->ar_req_context == NULL)
-		FAIL("Failed to allocate AR Req context");
+		FAIL(-ENOMEM, "Failed to allocate AR Req context");
 
+	/* AR DMA response context allocation */
 	ohci->ar_resp_context = 
-		alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,
+		alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
 				  AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
-				  OHCI1394_AsRspRcvContextControlSet,
-				  OHCI1394_AsRspRcvContextControlClear,
-				  OHCI1394_AsRspRcvCommandPtr);
+				  OHCI1394_AsRspRcvContextBase);
 	
 	if (ohci->ar_resp_context == NULL)
-		FAIL("Failed to allocate AR Resp context");
+		FAIL(-ENOMEM, "Failed to allocate AR Resp context");
 
+	/* AT DMA request context */
 	ohci->at_req_context = 
-		alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,
-				  OHCI1394_AsReqTrContextControlSet,
-				  OHCI1394_AsReqTrContextControlClear,
-				  OHCI1394_AsReqTrCommandPtr);
+		alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
+				  OHCI1394_AsReqTrContextBase);
 	
 	if (ohci->at_req_context == NULL)
-		FAIL("Failed to allocate AT Req context");
+		FAIL(-ENOMEM, "Failed to allocate AT Req context");
 
+	/* AT DMA response context */
 	ohci->at_resp_context = 
-		alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,
-				  OHCI1394_AsRspTrContextControlSet,
-				  OHCI1394_AsRspTrContextControlClear,
-				  OHCI1394_AsRspTrCommandPtr);
+		alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
+				  OHCI1394_AsRspTrContextBase);
 	
 	if (ohci->at_resp_context == NULL)
-		FAIL("Failed to allocate AT Resp context");
+		FAIL(-ENOMEM, "Failed to allocate AT Resp context");
 
+	/* IR DMA context */
 	ohci->ir_context =
-		alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
+		alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC,
 				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-				  OHCI1394_IsoRcvContextControlSet,
-				  OHCI1394_IsoRcvContextControlClear,
-				  OHCI1394_IsoRcvCommandPtr);
+				  OHCI1394_IsoRcvContextBase);
 
 	if (ohci->ir_context == NULL)
-		FAIL("Failed to allocate IR context");
+		FAIL(-ENOMEM, "Failed to allocate IR context");
+
+	
+	/* IT DMA context allocation */
+	ohci->it_context =
+		alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC,
+				  OHCI1394_IsoXmitContextBase);
+
+	if (ohci->it_context == NULL)
+		FAIL(-ENOMEM, "Failed to allocate IT context");
 
 	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		ohci->irq_hooks[i].irq_handler = NULL;
+		ohci->irq_hooks[i].data = NULL;
+	}
+	
 	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
 			 OHCI1394_DRIVER_NAME, ohci))
-		FAIL("Failed to allocate shared interrupt %d", dev->irq);
+		FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
+
+	ohci_initialize(ohci);
 
 	/* Tell the highlevel this host is ready */
-	highlevel_add_one_host (host);
+	hpsb_add_host(host);
 
 	return 0;
 #undef FAIL
 }
 
-static void remove_card(struct ti_ohci *ohci)
+static void __devexit ohci1394_pci_remove(struct pci_dev *pdev)
 {
+	struct ti_ohci *ohci;
 	quadlet_t buf;
 
+	ohci = pci_get_drvdata(pdev);
+	if (!ohci)
+		return;
+
+	if (ohci->host)
+		hpsb_remove_host(ohci->host);
+
 	/* Soft reset before we start */
 	ohci_soft_reset(ohci);
 
@@ -2267,8 +2291,41 @@
 #endif /* CONFIG_ALL_PPC */
 
 	pci_set_drvdata(ohci->dev, NULL);
+	hpsb_unref_host(ohci->host);
 }
 
+#define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
+
+static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
+	{
+		class: 		PCI_CLASS_FIREWIRE_OHCI,
+		class_mask: 	0x00ffffff,
+		vendor:		PCI_ANY_ID,
+		device:		PCI_ANY_ID,
+		subvendor:	PCI_ANY_ID,
+		subdevice:	PCI_ANY_ID,
+	},
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
+
+static struct pci_driver ohci1394_pci_driver = {
+	name:		OHCI1394_DRIVER_NAME,
+	id_table:	ohci1394_pci_tbl,
+	probe:		ohci1394_pci_probe,
+	remove:		__devexit_p(ohci1394_pci_remove),
+};
+
+
+
+/***********************************
+ * OHCI1394 Video Interface        *
+ ***********************************/
+
+/* essentially the only purpose of this code is to allow another
+   module to hook into ohci's interrupt handler */
+
 void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
 {
 	int i=0;
@@ -2288,111 +2345,96 @@
 	if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg);
 }
 
-int ohci1394_register_video(struct ti_ohci *ohci,
-			    struct video_template *tmpl)
+static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci,
+					  quadlet_t isoRecvEvent, 
+					  quadlet_t isoXmitEvent)
 {
-	if (ohci->video_tmpl)
-		return -ENFILE;
-	ohci->video_tmpl = tmpl;
-	MOD_INC_USE_COUNT;
-	return 0;
+	int i;
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		if(ohci->irq_hooks[i].irq_handler != NULL) {
+			ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent,
+						       ohci->irq_hooks[i].data);
+		}
+	}
 }
-	
-void ohci1394_unregister_video(struct ti_ohci *ohci,
-			       struct video_template *tmpl)
+
+int ohci1394_hook_irq(struct ti_ohci *ohci,
+		      void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+		      void *data)
 {
-	if (ohci->video_tmpl != tmpl) {
-		PRINT(KERN_ERR, ohci->id, 
-		      "Trying to unregister wrong video device");
-	} else {
-		ohci->video_tmpl = NULL;
-		MOD_DEC_USE_COUNT;
+	int i;
+	
+	/* find a free slot */
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		if(ohci->irq_hooks[i].irq_handler == NULL)
+			break;
 	}
+
+	if(i >= OHCI1394_MAX_IRQ_HOOKS)
+		return -EBUSY;
+
+	ohci->irq_hooks[i].irq_handler = irq_handler;
+	ohci->irq_hooks[i].data = data;
+
+	/* ohci1394 will never be unloaded while an IRQ hook is
+	   in use, because the user must reference this symbol */
+	
+	return 0;
 }
 
-#if 0
-int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
+void ohci1394_unhook_irq(struct ti_ohci *ohci,
+			 void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+			 void *data)
 {
-	int csrSel;
-	quadlet_t chan, data1=0, data2=0;
-	int timeout = 32;
-
-	if (channel<32) {
-		chan = 1<<channel;
-		csrSel = 2;
-	}
-	else {
-		chan = 1<<(channel-32);
-		csrSel = 3;
-	}
-	if (ohci_compare_swap(ohci, &data1, 0, csrSel)<0) {
-		PRINT(KERN_INFO, ohci->id, "request_channel timeout");
-		return -1;
+	int i;
+	
+	for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) {
+		if( (ohci->irq_hooks[i].irq_handler == irq_handler) &&
+		    (ohci->irq_hooks[i].data == data) )
+			break;
 	}
-	while (timeout--) {
-		if (data1 & chan) {
-			PRINT(KERN_INFO, ohci->id, 
-			      "request channel %d failed", channel);
-			return -1;
-		}
-		data2 = data1;
-		data1 |= chan;
-		if (ohci_compare_swap(ohci, &data1, data2, csrSel)<0) {
-			PRINT(KERN_INFO, ohci->id, "request_channel timeout");
-			return -1;
-		}
-		if (data1==data2) {
-			PRINT(KERN_INFO, ohci->id, 
-			      "request channel %d succeded", channel);
-			return 0;
-		}
+	
+	if(i < OHCI1394_MAX_IRQ_HOOKS) {
+		ohci->irq_hooks[i].irq_handler = NULL;
+		ohci->irq_hooks[i].data = NULL;
 	}
-	PRINT(KERN_INFO, ohci->id, "request channel %d failed", channel);
-	return -1;
 }
-#endif
 
 EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_register_video);
-EXPORT_SYMBOL(ohci1394_unregister_video);
+EXPORT_SYMBOL(ohci1394_hook_irq);
+EXPORT_SYMBOL(ohci1394_unhook_irq);
 
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
 
-static void __devexit ohci1394_remove_one(struct pci_dev *pdev)
-{
-	struct ti_ohci *ohci = pci_get_drvdata(pdev);
 
-	if (ohci) {
-		remove_card (ohci);
-		pci_set_drvdata(pdev, NULL);
-	}
-}
+/***********************************
+ * General module initialization   *
+ ***********************************/
 
-static struct pci_driver ohci1394_driver = {
-	name:		OHCI1394_DRIVER_NAME,
-	id_table:	ohci1394_pci_tbl,
-	probe:		ohci1394_add_one,
-	remove:		__devexit_p(ohci1394_remove_one),
-};
+MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
+MODULE_LICENSE("GPL");
 
 static void __exit ohci1394_cleanup (void)
 {
-	hpsb_unregister_lowlevel(&ohci_template);
-	pci_unregister_driver(&ohci1394_driver);
+	pci_unregister_driver(&ohci1394_pci_driver);
+	hpsb_unregister_lowlevel(ohci1394_driver);
 }
 
 static int __init ohci1394_init(void)
 {
 	int ret;
-	if (hpsb_register_lowlevel(&ohci_template)) {
-		PRINT_G(KERN_ERR, "Registering failed");
-		return -ENXIO;
-	}
-	if ((ret = pci_module_init(&ohci1394_driver))) {
-		PRINT_G(KERN_ERR, "PCI module init failed");
-		hpsb_unregister_lowlevel(&ohci_template);
+
+	ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops,
+						 OHCI1394_DRIVER_NAME);
+	if (!ohci1394_driver) {
+		PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed");
+		return -ENOMEM;
+	}
+
+	ret = pci_module_init(&ohci1394_pci_driver);
+	if (ret < 0) {
+		PRINT_G(KERN_ERR, "pci_module_init failed");
+		hpsb_unregister_lowlevel(ohci1394_driver);
 		return ret;
 	}
 	return ret;
diff -urN linux-2.4.19-pre4/drivers/ieee1394/ohci1394.h linux-2.4.19-pre5/drivers/ieee1394/ohci1394.h
--- linux-2.4.19-pre4/drivers/ieee1394/ohci1394.h	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/ohci1394.h	Fri Mar 29 14:49:31 2002
@@ -76,9 +76,13 @@
 	quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
 };
 
+/* identify whether a DMA context is asynchronous or isochronous */
+enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
+
 /* DMA receive context */
 struct dma_rcv_ctx {
-	void *ohci;
+	struct ti_ohci *ohci;
+	enum context_type type;
 	int ctx;
 	unsigned int num_desc;
 
@@ -105,7 +109,8 @@
 
 /* DMA transmit context */	
 struct dma_trm_ctx {
-	void *ohci;
+	struct ti_ohci *ohci;
+	enum context_type type;
 	int ctx;
 	unsigned int num_desc;
 
@@ -133,18 +138,9 @@
 	int cmdPtr;
 };
 
-/* video device template */
-struct video_template {
-	void (*irq_handler) (int card, quadlet_t isoRecvEvent, 
-			     quadlet_t isoXmitEvent);
-};
-
-
 struct ti_ohci {
         int id; /* sequential card number */
 
-	struct list_head list;
-
         struct pci_dev *dev;
 
         u32 state;
@@ -175,11 +171,13 @@
 	struct dma_rcv_ctx *ir_context;
         spinlock_t IR_channel_lock;
 	int nb_iso_rcv_ctx;
-
+	unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
+	
         /* iso transmit */
 	struct dma_trm_ctx *it_context;
 	int nb_iso_xmit_ctx;
-
+	unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
+	
         u64 ISO_channel_usage;
 
         /* IEEE-1394 part follows */
@@ -192,8 +190,15 @@
 
 	int self_id_errors;
 
-	/* video device */
-	struct video_template *video_tmpl;
+	/* IRQ hooks, for video1394 and dv1394 */
+	
+#define OHCI1394_MAX_IRQ_HOOKS 16
+	
+	struct ohci1394_irq_hook {
+		void (*irq_handler) (int card, quadlet_t isoRecvEvent, 
+				     quadlet_t isoXmitEvent, void *data);
+		void *data;
+	} irq_hooks[OHCI1394_MAX_IRQ_HOOKS];
 
 	/* Swap the selfid buffer? */
 	unsigned int selfid_swap:1;
@@ -230,6 +235,12 @@
 /* 2 KiloBytes of register space */
 #define OHCI1394_REGISTER_SIZE                0x800       
 
+/* Offsets relative to context bases defined below */
+
+#define OHCI1394_ContextControlSet            0x000
+#define OHCI1394_ContextControlClear          0x004
+#define OHCI1394_ContextCommandPtr            0x00C
+
 /* register map */
 #define OHCI1394_Version                      0x000
 #define OHCI1394_GUID_ROM                     0x004
@@ -281,27 +292,37 @@
 #define OHCI1394_PhyReqFilterLoSet            0x118
 #define OHCI1394_PhyReqFilterLoClear          0x11C
 #define OHCI1394_PhyUpperBound                0x120
+
+#define OHCI1394_AsReqTrContextBase           0x180
 #define OHCI1394_AsReqTrContextControlSet     0x180
 #define OHCI1394_AsReqTrContextControlClear   0x184
 #define OHCI1394_AsReqTrCommandPtr            0x18C
+
+#define OHCI1394_AsRspTrContextBase           0x1A0
 #define OHCI1394_AsRspTrContextControlSet     0x1A0
 #define OHCI1394_AsRspTrContextControlClear   0x1A4
 #define OHCI1394_AsRspTrCommandPtr            0x1AC
+
+#define OHCI1394_AsReqRcvContextBase          0x1C0
 #define OHCI1394_AsReqRcvContextControlSet    0x1C0
 #define OHCI1394_AsReqRcvContextControlClear  0x1C4
 #define OHCI1394_AsReqRcvCommandPtr           0x1CC
+
+#define OHCI1394_AsRspRcvContextBase          0x1E0
 #define OHCI1394_AsRspRcvContextControlSet    0x1E0
 #define OHCI1394_AsRspRcvContextControlClear  0x1E4
 #define OHCI1394_AsRspRcvCommandPtr           0x1EC
 
 /* Isochronous transmit registers */
-/* Add (32 * n) for context n */
+/* Add (16 * n) for context n */
+#define OHCI1394_IsoXmitContextBase           0x200
 #define OHCI1394_IsoXmitContextControlSet     0x200
 #define OHCI1394_IsoXmitContextControlClear   0x204
 #define OHCI1394_IsoXmitCommandPtr            0x20C
 
 /* Isochronous receive registers */
 /* Add (32 * n) for context n */
+#define OHCI1394_IsoRcvContextBase            0x400
 #define OHCI1394_IsoRcvContextControlSet      0x400
 #define OHCI1394_IsoRcvContextControlClear    0x404
 #define OHCI1394_IsoRcvCommandPtr             0x40C
@@ -342,14 +363,39 @@
 #define DMA_CTL_BRANCH                   0x000c0000
 #define DMA_CTL_WAIT                     0x00030000
 
+/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
+#define EVT_NO_STATUS		0x0	/* No event status */
+#define EVT_RESERVED		0x1	/* Reserved, not used !!! */
+#define EVT_LONG_PACKET		0x2	/* The revc data was longer than the buf */
+#define EVT_MISSING_ACK		0x3	/* A subaction gap was detected before an ack
+					   arrived, or recv'd ack had a parity error */
+#define EVT_UNDERRUN		0x4	/* Underrun on corresponding FIFO, packet
+					   truncated */
+#define EVT_OVERRUN		0x5	/* A recv FIFO overflowed on reception of ISO
+					   packet */
+#define EVT_DESCRIPTOR_READ	0x6	/* An unrecoverable error occured while host was
+					   reading a descriptor block */
+#define EVT_DATA_READ		0x7	/* An error occured while host controller was
+					   attempting to read from host memory in the data
+					   stage of descriptor processing */
+#define EVT_DATA_WRITE		0x8	/* An error occured while host controller was
+					   attempting to write either during the data stage
+					   of descriptor processing, or when processing a single
+					   16-bit host memory write */
+#define EVT_BUS_RESET		0x9	/* Identifies a PHY packet in the recv buffer as
+					   being a synthesized bus reset packet */
+
 #define OHCI1394_TCODE_PHY               0xE
 
 void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
 struct ti_ohci *ohci1394_get_struct(int card_num);
-int ohci1394_register_video(struct ti_ohci *ohci,
-			    struct video_template *tmpl);
-void ohci1394_unregister_video(struct ti_ohci *ohci,
-			       struct video_template *tmpl);
 
+int ohci1394_hook_irq(struct ti_ohci *ohci,
+		      void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+		      void *data);
+
+void ohci1394_unhook_irq(struct ti_ohci *ohci,
+			 void (*irq_handler) (int, quadlet_t, quadlet_t, void *),
+			 void *data);
 #endif
 
diff -urN linux-2.4.19-pre4/drivers/ieee1394/pcilynx.c linux-2.4.19-pre5/drivers/ieee1394/pcilynx.c
--- linux-2.4.19-pre4/drivers/ieee1394/pcilynx.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/pcilynx.c	Fri Mar 29 14:49:31 2002
@@ -42,10 +42,6 @@
 #include "pcilynx.h"
 
 
-#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START
-#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work.
-#endif
-
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
 /* print card specific information */
@@ -60,9 +56,8 @@
 #endif
 
 
-static struct ti_lynx cards[MAX_PCILYNX_CARDS];
-static int num_of_cards = 0;
-static struct hpsb_host_template lynx_template;
+static struct hpsb_host_driver *lynx_driver;
+static unsigned int card_id;
 
 /*
  * PCL handling functions.
@@ -143,10 +138,6 @@
 #endif
 
 
-static int add_card(struct pci_dev *dev, const struct pci_device_id *devid);
-static void remove_card(struct pci_dev *dev);
-
-
 
 /***********************************
  * IEEE-1394 functionality section *
@@ -161,8 +152,9 @@
         unsigned long flags;
 
         if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY register address %d out of range", addr);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY register address %d out of range",
+		      __FUNCTION__, addr);
                 return -1;
         }
 
@@ -173,8 +165,8 @@
                 retval = reg_read(lynx, LINK_PHY);
 
                 if (i > 10000) {
-                        PRINT(KERN_ERR, lynx->id, __FUNCTION__ 
-                              ": runaway loop, aborting");
+                        PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
+			      __FUNCTION__);
                         retval = -1;
                         break;
                 }
@@ -196,14 +188,14 @@
         unsigned long flags;
 
         if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY register address %d out of range", addr);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY register address %d out of range", __FUNCTION__, addr);
                 return -1;
         }
 
         if (val > 0xff) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY register value %d out of range", val);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY register value %d out of range", __FUNCTION__, val);
                 return -1;
         }
 
@@ -222,8 +214,8 @@
         int reg;
 
         if (page > 7) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY page %d out of range", page);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY page %d out of range", __FUNCTION__, page);
                 return -1;
         }
 
@@ -244,8 +236,8 @@
         int reg;
 
         if (port > 15) {
-                PRINT(KERN_ERR, lynx->id, __FUNCTION__
-                      ": PHY port %d out of range", port);
+                PRINT(KERN_ERR, lynx->id,
+                      "%s: PHY port %d out of range", __FUNCTION__, port);
                 return -1;
         }
 
@@ -377,7 +369,7 @@
 
         hpsb_selfid_complete(host, phyid, isroot);
 
-        if (host->in_bus_reset) return;
+        if (host->in_bus_reset) return; /* in bus reset again */
 
         if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER);
         reg_set_bits(lynx, LINK_CONTROL,
@@ -440,160 +432,7 @@
 }
 
 
-#if 0
-static int lynx_detect(struct hpsb_host_template *tmpl)
-{
-        struct hpsb_host *host;
-        int i;
-
-        init_driver();
-
-        for (i = 0; i < num_of_cards; i++) {
-                host = hpsb_get_host(tmpl, 0);
-                if (host == NULL) {
-                        /* simply don't init more after out of mem */
-                        return i;
-                }
-                host->hostdata = &cards[i];
-                cards[i].host = host;
-        }
-
-        return num_of_cards;
-}
-#endif
-
-static int lynx_initialize(struct hpsb_host *host)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        struct ti_pcl pcl;
-        int i;
-        u32 *pcli;
-
-        lynx->selfid_size = -1;
-        lynx->phy_reg0 = -1;
-
-        lynx->async.queue = NULL;
-        
-        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
-        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-        
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-#ifdef __BIG_ENDIAN
-        pcl.buffer[0].control = PCL_CMD_RCV | 16;
-        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#else
-        pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
-        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#endif
-        pcl.buffer[0].pointer = lynx->rcv_page_dma;
-        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
-        put_pcl(lynx, lynx->rcv_pcl, &pcl);
-        
-        pcl.next = pcl_bus(lynx, lynx->async.pcl);
-        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
-        put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
-        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
-        pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                int page = i / ISORCV_PER_PAGE;
-                int sec = i % ISORCV_PER_PAGE;
-
-                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] 
-                        + sec * MAX_ISORCV_SIZE;
-                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
-                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
-        }
-
-        pcli = (u32 *)&pcl;
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
-        }
-        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
-        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
-        reg_write(lynx, FIFO_SIZES, 0x003030a0);
-        /* 20 byte threshold before triggering PCI transfer */
-        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
-        /* threshold on both send FIFOs before transmitting:
-           FIFO size - cache line size - 1 */
-        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
-        i = 0x30 - i - 1;
-        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-        
-        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
-        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
-                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET
-                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK 
-                  | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC
-                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW
-                  | LINK_INT_ATF_UNDERFLOW);
-        
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
-                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
-                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST
-                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
-        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
-        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
-        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
-                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN
-                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
-                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
-
-        if (!lynx->phyic.reg_1394a) {
-                /* attempt to enable contender bit -FIXME- would this work
-                 * elsewhere? */
-                reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
-                reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); 
-        } else {
-                /* set the contender bit in the extended PHY register
-                 * set. (Should check that bis 0,1,2 (=0xE0) is set
-                 * in register 2?)
-                 */
-                i = get_phy_reg(lynx, 4);
-                if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
-        }
-
-        return 1;
-}
-
-static void lynx_release(struct hpsb_host *host)
-{
-        struct ti_lynx *lynx;
-        
-        if (host != NULL) {
-                lynx = host->hostdata;
-                remove_card(lynx->dev);
-        } else {
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-                unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
-        }
-}
-
+/* called from subsystem core */
 static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 {
         struct ti_lynx *lynx = host->hostdata;
@@ -642,6 +481,8 @@
         return 1;
 }
 
+
+/* called from subsystem core */
 static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
 {
         struct ti_lynx *lynx = host->hostdata;
@@ -666,9 +507,7 @@
                 arg |= (retval == -1 ? 63 : retval);
                 retval = 0;
 
-                PRINT(KERN_INFO, lynx->id, "resetting bus on request%s",
-                      (host->attempt_root ? " and attempting to become root"
-                       : ""));
+                PRINT(KERN_INFO, lynx->id, "resetting bus on request");
 
                 lynx->selfid_size = -1;
                 lynx->phy_reg0 = -1;
@@ -721,6 +560,8 @@
                 } else {
                         MOD_DEC_USE_COUNT;
                 }
+
+                retval = 1;
                 break;
 
         case ISO_LISTEN_CHANNEL:
@@ -773,7 +614,7 @@
 
 
 static struct file_operations aux_ops = {
-        OWNER_THIS_MODULE
+	owner:		THIS_MODULE,
         read:           mem_read,
         write:          mem_write,
         poll:           aux_poll,
@@ -794,46 +635,35 @@
 
 static int mem_open(struct inode *inode, struct file *file)
 {
-        int cid = MINOR(inode->i_rdev);
+        int cid = minor(inode->i_rdev);
         enum { t_rom, t_aux, t_ram } type;
         struct memdata *md;
         
-        V22_COMPAT_MOD_INC_USE_COUNT;
-
         if (cid < PCILYNX_MINOR_AUX_START) {
                 /* just for completeness */
-                V22_COMPAT_MOD_DEC_USE_COUNT;
                 return -ENXIO;
         } else if (cid < PCILYNX_MINOR_ROM_START) {
                 cid -= PCILYNX_MINOR_AUX_START;
-                if (cid >= num_of_cards || !cards[cid].aux_port) {
-                        V22_COMPAT_MOD_DEC_USE_COUNT;
+                if (cid >= num_of_cards || !cards[cid].aux_port)
                         return -ENXIO;
-                }
                 type = t_aux;
         } else if (cid < PCILYNX_MINOR_RAM_START) {
                 cid -= PCILYNX_MINOR_ROM_START;
-                if (cid >= num_of_cards || !cards[cid].local_rom) {
-                        V22_COMPAT_MOD_DEC_USE_COUNT;
+                if (cid >= num_of_cards || !cards[cid].local_rom)
                         return -ENXIO;
-                }
                 type = t_rom;
         } else {
                 /* WARNING: Know what you are doing when opening RAM.
                  * It is currently used inside the driver! */
                 cid -= PCILYNX_MINOR_RAM_START;
-                if (cid >= num_of_cards || !cards[cid].local_ram) {
-                        V22_COMPAT_MOD_DEC_USE_COUNT;
+                if (cid >= num_of_cards || !cards[cid].local_ram)
                         return -ENXIO;
-                }
                 type = t_ram;
         }
 
         md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
-        if (md == NULL) {
-                V22_COMPAT_MOD_DEC_USE_COUNT;
+        if (md == NULL)
                 return -ENOMEM;
-        }
 
         md->lynx = &cards[cid];
         md->cid = cid;
@@ -859,11 +689,7 @@
 
 static int mem_release(struct inode *inode, struct file *file)
 {
-        struct memdata *md = (struct memdata *)file->private_data;
-
-        kfree(md);
-
-        V22_COMPAT_MOD_DEC_USE_COUNT;
+        kfree(file->private_data);
         return 0;
 }
 
@@ -1010,8 +836,8 @@
                 membase = md->lynx->aux_port;
                 break;
         default:
-                panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__,
-                      md->lynx->id, md->type);
+                panic("pcilynx%d: unsupported md->type %d in %s",
+                      md->lynx->id, md->type, __FUNCTION__);
         }
 
         down(&md->lynx->mem_dma_mutex);
@@ -1291,6 +1117,7 @@
         }
 }
 
+
 static void iso_rcv_bh(struct ti_lynx *lynx)
 {
         unsigned int idx;
@@ -1335,44 +1162,97 @@
 }
 
 
+static void remove_card(struct pci_dev *dev)
+{
+        struct ti_lynx *lynx;
+        int i;
+
+        lynx = pci_get_drvdata(dev);
+        if (!lynx) return;
+        pci_set_drvdata(dev, NULL);
+
+        switch (lynx->state) {
+        case is_host:
+                reg_write(lynx, PCI_INT_ENABLE, 0);
+                hpsb_remove_host(lynx->host);
+        case have_intr:
+                reg_write(lynx, PCI_INT_ENABLE, 0);
+                free_irq(lynx->dev->irq, lynx);
+        case have_iomappings:
+                reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+                /* Fix buggy cards with autoboot pin not tied low: */
+                reg_write(lynx, DMA0_CHAN_CTRL, 0);
+                iounmap(lynx->registers);
+                iounmap(lynx->local_rom);
+                iounmap(lynx->local_ram);
+                iounmap(lynx->aux_port);
+        case have_1394_buffers:
+                for (i = 0; i < ISORCV_PAGES; i++) {
+                        if (lynx->iso_rcv.page[i]) {
+                                pci_free_consistent(lynx->dev, PAGE_SIZE,
+                                                    lynx->iso_rcv.page[i],
+                                                    lynx->iso_rcv.page_dma[i]);
+                        }
+                }
+                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
+                                    lynx->rcv_page_dma);
+        case have_aux_buf:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
+                                    lynx->mem_dma_buffer_dma);
+#endif
+        case have_pcl_mem:
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
+                                    lynx->pcl_mem_dma);
+#endif
+        case clear:
+                /* do nothing - already freed */
+                ;
+        }
+
+	tasklet_kill(&lynx->iso_rcv.tq);
+	hpsb_unref_host(lynx->host);
+}
+
+
 static int __devinit add_card(struct pci_dev *dev,
-                              const struct pci_device_id *devid)
+                              const struct pci_device_id *devid_is_unused)
 {
 #define FAIL(fmt, args...) do { \
         PRINT_G(KERN_ERR, fmt , ## args); \
-        num_of_cards--; \
         remove_card(dev); \
-        return -1; \
+        return error; \
         } while (0)
 
+	struct hpsb_host *host;
         struct ti_lynx *lynx; /* shortcut to currently handled device */
-        unsigned int i;
+        struct ti_pcl pcl;
+        u32 *pcli;
+        int i;
+        int error;
 
-        if (num_of_cards == MAX_PCILYNX_CARDS) {
-                PRINT_G(KERN_WARNING, "cannot handle more than %d cards.  "
-                        "Adjust MAX_PCILYNX_CARDS in pcilynx.h.",
-                        MAX_PCILYNX_CARDS);
-                return -1;
-        }
 
-        lynx = &cards[num_of_cards++];
+        error = -ENXIO;
 
         if (pci_set_dma_mask(dev, 0xffffffff))
-                FAIL("DMA address limits not supported for PCILynx hardware %d",
-                     lynx->id);
+                FAIL("DMA address limits not supported for PCILynx hardware");
         if (pci_enable_device(dev))
-                FAIL("failed to enable PCILynx hardware %d", lynx->id);
+                FAIL("failed to enable PCILynx hardware");
         pci_set_master(dev);
 
-        lynx->host = hpsb_get_host(&lynx_template, 0);
-        if (!lynx->host)
-                FAIL("failed to allocate host structure");
-
-        lynx->state = have_host_struct;
-	lynx->host->hostdata = lynx;
-        lynx->id = num_of_cards-1;
+        error = -ENOMEM;
+
+	host = hpsb_alloc_host(lynx_driver, sizeof(struct ti_lynx));
+        if (!host) FAIL("failed to allocate control structure memory");
+
+        lynx = host->hostdata;
+	lynx->id = card_id++;
         lynx->dev = dev;
-	lynx->host->pdev = dev;
+        lynx->state = clear;
+	lynx->host = host;
+        host->pdev = dev;
+        pci_set_drvdata(dev, lynx);
 
         lynx->lock = SPIN_LOCK_UNLOCKED;
         lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;
@@ -1435,7 +1315,9 @@
         }
 #endif
 
-        reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+        reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+        /* Fix buggy cards with autoboot pin not tied low: */
+        reg_write(lynx, DMA0_CHAN_CTRL, 0);
 
         if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,
                          PCILYNX_DRIVER_NAME, lynx)) {
@@ -1502,99 +1384,121 @@
                 PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
         }
 
-	/* Tell the highlevel this host is ready */
-	highlevel_add_one_host (lynx->host);
-
-        return 0;
-#undef FAIL
-}
+        lynx->selfid_size = -1;
+        lynx->phy_reg0 = -1;
 
-static void remove_card(struct pci_dev *dev)
-{
-        struct ti_lynx *lynx;
-        int i;
+        lynx->async.queue = NULL;
 
-        lynx = cards;
-        while (lynx->dev != dev) lynx++;
+        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
+        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
 
-        switch (lynx->state) {
-        case have_intr:
-                reg_write(lynx, PCI_INT_ENABLE, 0);
-                free_irq(lynx->dev->irq, lynx);
-        case have_iomappings:
-                reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
-                iounmap(lynx->registers);
-                iounmap(lynx->local_rom);
-                iounmap(lynx->local_ram);
-                iounmap(lynx->aux_port);
-        case have_1394_buffers:
-                for (i = 0; i < ISORCV_PAGES; i++) {
-                        if (lynx->iso_rcv.page[i]) {
-                                pci_free_consistent(lynx->dev, PAGE_SIZE,
-                                                    lynx->iso_rcv.page[i],
-                                                    lynx->iso_rcv.page_dma[i]);
-                        }
-                }
-                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
-                                    lynx->rcv_page_dma);
-        case have_aux_buf:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
-                                    lynx->mem_dma_buffer_dma);
+        pcl.next = PCL_NEXT_INVALID;
+        pcl.async_error_next = PCL_NEXT_INVALID;
+#ifdef __BIG_ENDIAN
+        pcl.buffer[0].control = PCL_CMD_RCV | 16;
+        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
+#else
+        pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+        pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
 #endif
-        case have_pcl_mem:
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
-                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
-                                    lynx->pcl_mem_dma);
+        pcl.buffer[0].pointer = lynx->rcv_page_dma;
+        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
+        put_pcl(lynx, lynx->rcv_pcl, &pcl);
+        
+        pcl.next = pcl_bus(lynx, lynx->async.pcl);
+        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
+        put_pcl(lynx, lynx->async.pcl_start, &pcl);
+
+        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
+        pcl.async_error_next = PCL_NEXT_INVALID;
+        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
+
+        pcl.next = PCL_NEXT_INVALID;
+        pcl.async_error_next = PCL_NEXT_INVALID;
+        pcl.buffer[0].control = PCL_CMD_RCV | 4;
+#ifndef __BIG_ENDIAN
+        pcl.buffer[0].control |= PCL_BIGENDIAN;
 #endif
-        case have_host_struct:
-                /* FIXME - verify host freeing */
-        case clear:;
-                /* do nothing - already freed */
+        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
+
+        for (i = 0; i < NUM_ISORCV_PCL; i++) {
+                int page = i / ISORCV_PER_PAGE;
+                int sec = i % ISORCV_PER_PAGE;
+
+                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] 
+                        + sec * MAX_ISORCV_SIZE;
+                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
+                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
         }
 
-	tasklet_kill(&lynx->iso_rcv.tq);
+        pcli = (u32 *)&pcl;
+        for (i = 0; i < NUM_ISORCV_PCL; i++) {
+                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
+        }
+        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
 
-        lynx->state = clear;
-}
+        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
+        reg_write(lynx, FIFO_SIZES, 0x003030a0);
+        /* 20 byte threshold before triggering PCI transfer */
+        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
+        /* threshold on both send FIFOs before transmitting:
+           FIFO size - cache line size - 1 */
+        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
+        i = 0x30 - i - 1;
+        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
 
-#if 0
-static int init_driver()
-{
-        struct pci_dev *dev = NULL;
-        int success = 0;
+        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
 
-        if (num_of_cards) {
-                PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
-                return 0;
-        }
+        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
+                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET
+                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK 
+                  | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC
+                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW
+                  | LINK_INT_ATF_UNDERFLOW);
+        
+        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
+        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
+                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
+                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST
+                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
 
-        PRINT_G(KERN_INFO, "looking for PCILynx cards");
+        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
 
-        while ((dev = pci_find_device(PCI_VENDOR_ID_TI,
-                                      PCI_DEVICE_ID_TI_PCILYNX, dev)) 
-               != NULL) {
-                if (add_card(dev) == 0) {
-                        success = 1;
-                }
-        }
+        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
+        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
 
-        if (success == 0) {
-                PRINT_G(KERN_WARNING, "no operable PCILynx cards found");
-                return -ENXIO;
-        }
+        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
 
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
-        if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
-                PRINT_G(KERN_ERR, "allocation of char major number %d failed",
-                        PCILYNX_MAJOR);
-                return -EBUSY;
+        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
+                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN
+                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
+                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
+
+        if (!lynx->phyic.reg_1394a) {
+                /* attempt to enable contender bit -FIXME- would this work
+                 * elsewhere? */
+                reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
+                reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); 
+        } else {
+                /* set the contender bit in the extended PHY register
+                 * set. (Should check that bis 0,1,2 (=0xE0) is set
+                 * in register 2?)
+                 */
+                i = get_phy_reg(lynx, 4);
+                if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
         }
-#endif
+
+        hpsb_add_host(host);
+        lynx->state = is_host;
 
         return 0;
+#undef FAIL
 }
-#endif
+
 
 
 static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
@@ -1603,15 +1507,6 @@
         return sizeof(lynx_csr_rom);
 }
 
-static struct hpsb_host_template lynx_template = {
-	name:             PCILYNX_DRIVER_NAME,
-	initialize_host:  lynx_initialize,
-	release_host:     lynx_release,
-	get_rom:          get_lynx_rom,
-	transmit_packet:  lynx_transmit,
-	devctl:           lynx_devctl
-};
-
 static struct pci_device_id pci_table[] __devinitdata = {
 	{
                 vendor:     PCI_VENDOR_ID_TI,
@@ -1622,11 +1517,17 @@
 	{ }			/* Terminating entry */
 };
 
-static struct pci_driver lynx_pcidriver = {
+static struct pci_driver lynx_pci_driver = {
         name:      PCILYNX_DRIVER_NAME,
         id_table:  pci_table,
         probe:     add_card,
-        remove:    remove_card,
+        remove:    __devexit_p(remove_card),
+};
+
+static struct hpsb_host_operations lynx_ops = {
+        get_rom:          get_lynx_rom,
+        transmit_packet:  lynx_transmit,
+        devctl:           lynx_devctl,
 };
 
 MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
@@ -1635,30 +1536,52 @@
 MODULE_SUPPORTED_DEVICE("pcilynx");
 MODULE_DEVICE_TABLE(pci, pci_table);
 
-static void __exit pcilynx_cleanup(void)
-{
-        hpsb_unregister_lowlevel(&lynx_template);
-	pci_unregister_driver(&lynx_pcidriver);
-        PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
-}
-
 static int __init pcilynx_init(void)
 {
         int ret;
 
-        if (hpsb_register_lowlevel(&lynx_template)) {
-                PRINT_G(KERN_ERR, "registering failed");
-                return -ENXIO;
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+        if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
+                PRINT_G(KERN_ERR, "allocation of char major number %d failed",
+                        PCILYNX_MAJOR);
+                return -EBUSY;
+        }
+#endif
+
+        lynx_driver = hpsb_register_lowlevel(&lynx_ops, PCILYNX_DRIVER_NAME);
+        if (!lynx_driver) {
+                ret = -ENOMEM;
+                goto free_char_dev;
         }
 
-        ret = pci_module_init(&lynx_pcidriver);
+        ret = pci_module_init(&lynx_pci_driver);
         if (ret < 0) {
                 PRINT_G(KERN_ERR, "PCI module init failed");
-                hpsb_unregister_lowlevel(&lynx_template);
+                goto unregister_lowlevel;
         }
 
+        return 0;
+
+ unregister_lowlevel:
+        hpsb_unregister_lowlevel(lynx_driver);
+ free_char_dev:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+
         return ret;
 }
 
+static void __exit pcilynx_cleanup(void)
+{
+        pci_unregister_driver(&lynx_pci_driver);
+        hpsb_unregister_lowlevel(lynx_driver);
+
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+        unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+}
+
+
 module_init(pcilynx_init);
 module_exit(pcilynx_cleanup);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/pcilynx.h linux-2.4.19-pre5/drivers/ieee1394/pcilynx.h
--- linux-2.4.19-pre4/drivers/ieee1394/pcilynx.h	Sun Aug 12 12:39:02 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/pcilynx.h	Fri Mar 29 14:49:31 2002
@@ -40,8 +40,8 @@
                 u32 product;
         } phyic;
 
-        enum { clear, have_host_struct,  have_intr, have_aux_buf, have_pcl_mem,
-               have_1394_buffers, have_iomappings } state;
+        enum { clear, have_intr, have_aux_buf, have_pcl_mem,
+               have_1394_buffers, have_iomappings, is_host } state;
         
         /* remapped memory spaces */
         void *registers;
diff -urN linux-2.4.19-pre4/drivers/ieee1394/raw1394.c linux-2.4.19-pre5/drivers/ieee1394/raw1394.c
--- linux-2.4.19-pre4/drivers/ieee1394/raw1394.c	Mon Oct  1 21:24:24 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/raw1394.c	Fri Mar 29 14:49:31 2002
@@ -21,10 +21,7 @@
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
 #include <linux/devfs_fs_kernel.h>
-#endif
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -467,7 +464,7 @@
                                 hi = list_entry(lh, struct host_info, list);
 
                                 khl->nodes = hi->host->node_count;
-                                strcpy(khl->name, hi->host->template->name);
+                                strcpy(khl->name, hi->host->driver->name);
 
                                 khl++;
                         }
@@ -495,7 +492,7 @@
                                 lh = lh->next;
                         }
                         hi = list_entry(lh, struct host_info, list);
-                        hpsb_inc_host_usage(hi->host);
+                        hpsb_ref_host(hi->host);
                         list_add_tail(&fi->list, &hi->file_info_list);
                         fi->host = hi->host;
                         fi->state = connected;
@@ -915,17 +912,13 @@
 {
         struct file_info *fi;
 
-        if (MINOR(inode->i_rdev)) {
+        if (ieee1394_file_to_instance(file) > 0) {
                 return -ENXIO;
         }
 
-        V22_COMPAT_MOD_INC_USE_COUNT;
-
         fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
-        if (fi == NULL) {
-                V22_COMPAT_MOD_DEC_USE_COUNT;
+        if (fi == NULL)
                 return -ENOMEM;
-        }
         
         memset(fi, 0, sizeof(struct file_info));
 
@@ -949,7 +942,6 @@
         struct pending_request *req;
         int done = 0, i;
 
-        lock_kernel();
         for (i = 0; i < 64; i++) {
                 if (fi->listen_channels & (1ULL << i)) {
                         hpsb_unlisten_channel(hl_handle, fi->host, i);
@@ -984,13 +976,11 @@
                 list_del(&fi->list);
                 spin_unlock_irq(&host_info_lock);
 
-                hpsb_dec_host_usage(fi->host);
+                hpsb_unref_host(fi->host);
         }
 
         kfree(fi);
 
-        V22_COMPAT_MOD_DEC_USE_COUNT;
-        unlock_kernel();
         return 0;
 }
 
@@ -1003,12 +993,12 @@
 };
 
 static struct file_operations file_ops = {
-        OWNER_THIS_MODULE
-        read:     raw1394_read, 
-        write:    raw1394_write, 
-        poll:     raw1394_poll, 
-        open:     raw1394_open, 
-        release:  raw1394_release, 
+	owner:		THIS_MODULE,
+        read:		raw1394_read, 
+        write:		raw1394_write, 
+        poll:		raw1394_poll, 
+        open:		raw1394_open, 
+        release:	raw1394_release, 
 };
 
 static int __init init_raw1394(void)
@@ -1019,14 +1009,18 @@
                 return -ENOMEM;
         }
 
-	devfs_handle = devfs_register(NULL, RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
-                                      RAW1394_DEVICE_MAJOR, 0,
+	devfs_handle = devfs_register(NULL,
+				      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+                                      IEEE1394_MAJOR,
+				      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
                                       S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
                                       NULL);
 
-        if (devfs_register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME, 
-                                  &file_ops)) {
-                HPSB_ERR("raw1394 failed to register /dev/raw1394 device");
+        if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
+				      THIS_MODULE, &file_ops)) {
+                HPSB_ERR("raw1394 failed to register minor device block");
+		devfs_unregister(devfs_handle);
+		hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
 	printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
@@ -1035,7 +1029,7 @@
 
 static void __exit cleanup_raw1394(void)
 {
-        devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME);
+        ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
 	devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
 }
diff -urN linux-2.4.19-pre4/drivers/ieee1394/sbp2.c linux-2.4.19-pre5/drivers/ieee1394/sbp2.c
--- linux-2.4.19-pre4/drivers/ieee1394/sbp2.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre5/drivers/ieee1394/sbp2.c	Fri Mar 29 14:49:31 2002
@@ -2,7 +2,7 @@
  * sbp2.c - SBP-2 protocol driver for IEEE-1394
  *
  * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com
+ * jamesg@filanet.com (JSG)
  *
  * 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
@@ -27,6 +27,7 @@
  * driver. It also registers as a SCSI lower-level driver in order to accept
  * SCSI commands for transport using SBP-2.
  *
+ *
  * Driver Loading:
  *
  * Currently, the SBP-2 driver is supported only as a module. Because the 
@@ -45,7 +46,7 @@
  *
  * Currently, the SBP-2 driver will catch any attached SBP-2 devices during the
  * initial scsi bus scan (when the driver is first loaded). To add or remove
- * SBP-2 devices after this initial scan (i.e. if you plug-in or un-plug a 
+ * SBP-2 devices "after" this initial scan (i.e. if you plug-in or un-plug a 
  * device after the SBP-2 driver is loaded), you must either use the scsi procfs
  * add-single-device, remove-single-device, or a shell script such as 
  * rescan-scsi-bus.sh.
@@ -76,14 +77,28 @@
  * fdisk, mkfs, etc.).
  *
  *
+ * Module Load Options:
+ *
+ * sbp2_max_speed 		- Force max speed allowed 
+ *				  (2 = 400mb, 1 = 200mb, 0 = 100mb. default = 2)
+ * sbp2_serialize_io		- Serialize all I/O coming down from the scsi drivers 
+ *				  (0 = deserialized, 1 = serialized, default = 0)
+ * sbp2_max_sectors, 		- Change max sectors per I/O supported (default = 255)
+ * sbp2_max_outstanding_cmds	- Change max outstanding concurrent commands (default = 8)
+ * sbp2_max_cmds_per_lun	- Change max concurrent commands per sbp2 device (default = 1)
+ *
+ * (e.g. insmod sbp2 sbp2_serialize_io = 1)
+ *
+ *
  * Current Support:
  *
  * The SBP-2 driver is still in an early state, but supports a variety of devices.
  * I have read/written many gigabytes of data from/to SBP-2 drives, and have seen 
- * performance of more than 16 MBytes/s on individual drives (limit of the media 
+ * performance of more than 25 MBytes/s on individual drives (limit of the media 
  * transfer rate).
  *
- * Following are the devices that have been tested successfully:
+ *
+ * Following are a sampling of devices that have been tested successfully:
  *
  *	- Western Digital IEEE-1394 hard drives
  *	- Maxtor IEEE-1394 hard drives
@@ -91,7 +106,7 @@
  *	- LaCie IEEE-1394 hard drives (several flavors)
  *	- QPS IEEE-1394 CD-RW/DVD drives and hard drives
  *	- BusLink IEEE-1394 hard drives
- *	- Iomega IEEE-1394 Zip/Jazz drives
+ *	- Iomega IEEE-1394 Zip/Jazz/Peerless drives
  *	- ClubMac IEEE-1394 hard drives
  *	- FirePower IEEE-1394 hard drives
  *	- EzQuest IEEE-1394 hard drives and CD-RW drives
@@ -102,9 +117,8 @@
  *	- APDrives IEEE-1394 hard drives
  *	- Fujitsu IEEE-1394 MO drives
  *	- Sony IEEE-1394 CD-RW drives
- *	- Epson IEEE-1394 scanner
+ *	- Epson IEEE-1394 scanners
  *	- ADS IEEE-1394 memory stick and compact flash readers 
- *	  (e.g. "insmod sbp2 mode_sense_hack=1" for mem stick and flash readers))
  *	- SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges)
  *	- Various other standard IEEE-1394 hard drives and enclosures
  *
@@ -118,10 +132,6 @@
  *
  * Current Issues:
  *
- *	- Currently, all I/O from the scsi stack is serialized by default, as there
- *	  are some stress issues under investigation with deserialized I/O. To enable
- *	  deserialized I/O for testing, do "insmod sbp2 serialize_io=0"
- *
  *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
  *	  but the code needs additional debugging.
  *
@@ -130,10 +140,6 @@
  *	  add some init code to the kernel to support this... and modules are much
  *	  more flexible anyway.   ;-)
  *
- *     - The scsi stack in recent kernels pass down the data transfer
- *       direction as scsicmd->sc_data_direction, which we should use
- *       instead of the sbp2scsi_direction_table.
- *
  *
  * History:
  *
@@ -239,9 +245,42 @@
  *                   upon module unload.  Moved much initialization
  *                   from sbp2scsi_detect to sbp2_module_init.
  *                                 Kristian Hogsberg <hogsberg@users.sf.net>
+ *	01/06/02 - Misc bug fixes/enhancements:	(JSG)
+ *		   * Enable use_new_eh_code for scsi stuff.
+ *		   * Do not write all ones for NULL ORB high/low fields, but
+ *		     rather leave reserved areas zeroed (per SBP2 spec).
+ *		   * Use newer scsi transfer direction passed down instead of our
+ *		     direction table.
+ *		   * Bumped login time-out to 20 seconds, as some devices are slow.
+ *		   * Fixed a couple scsi unregister bugs on module unload
+ *	01/13/02 - Fixed compatibility with certain SBP2 devices, such as Iomega
+ *		   1394 devices (Peerless, Jazz). Also a bit of clean-up of the 
+ *		   driver, thanks to H.J.Lu (hjl@lucon.org). Removed mode_sense_hack
+ *		   module load option, as it's been fixed in the 2.4 scsi stack.
+ *	02/10/02 - Added support for max_sectors, minor fix for inquiry command, make
+ *		   up sbp2 device type from inquiry response data if not part of 
+ *		   device's 1394 unit directory. (JSG)
+ *	02/18/02 - Code clean-up and enhancements: (JSG)
+ *		   * Finish cleaning out hacked code for dealing with broken sbp2 devices
+ *		     which do not support requests of 128KB or greater. Now use 
+ *		     max_sectors scsi host entry to limit transfer sizes.
+ *		   * Change status fifo address from a single address to a set of addresses,
+ *		     with each sbp2 device having it's own status fifo address. This makes
+ *		     it easier to match the status write to the sbp2 device instance.
+ *		   * Minor change to use lun when logging into sbp2 devices. First step in
+ *		     supporting multi-lun devices such as CD/DVD changer devices.
+ *		   * Added a new module load option for setting max sectors. For use by folk
+ *		     who'd like to bump up the max scsi transfer size supported.
+ *		   * Enabled deserialized operation by default, allowing for better performance,
+ *		     particularily when running with multiple sbp2 devices. For debugging,
+ *		     you may enable serialization through use of the sbp2_serialize_io module
+ *		     load option (e.g. insmod sbp2 sbp2_serialize_io=1).
+ *	02/20/02 - Added a couple additional module load options. 
+ *		   Needed to bump down max commands per lun because of the !%@&*^# QPS CDRW 
+ *		   drive I have, which doesn't seem to get along with other sbp2 devices 
+ *		   (or handle linked commands well).  
  */
 
-
 
 /*
  * Includes
@@ -270,6 +309,16 @@
 #include <asm/io.h>
 #include <asm/scatterlist.h>
 
+#ifdef CONFIG_KBUILD_2_5
+#include <scsi.h>
+#include <hosts.h>
+#include <sd.h>
+#else
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+#endif
+
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "ieee1394_core.h"
@@ -278,9 +327,6 @@
 #include "highlevel.h"
 #include "ieee1394_transactions.h"
 #include "ieee1394_hotplug.h"
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
 #include "sbp2.h"
 
 /*
@@ -288,17 +334,7 @@
  */
 
 /*
- * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device,
- * like a 1394 memory stick reader, compact flash reader, or MO drive that
- * does not support mode sense. Allows you to mount the media rw instead
- * of ro.
- */
-MODULE_PARM(mode_sense_hack,"i");
-MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers");
-static int mode_sense_hack = 0;
-
-/*
- * Change max_speed on module load if you have a bad IEEE-1394 controller
+ * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller
  * that has trouble running 2KB packets at 400mb.
  *
  * NOTE: On certain OHCI parts I have seen short packets on async transmit
@@ -306,31 +342,51 @@
  * bump down the speed if you are running into problems.
  *
  * Valid values:
- * max_speed = 2 (default: max speed 400mb)
- * max_speed = 1 (max speed 200mb)
- * max_speed = 0 (max speed 100mb)
+ * sbp2_max_speed = 2 (default: max speed 400mb)
+ * sbp2_max_speed = 1 (max speed 200mb)
+ * sbp2_max_speed = 0 (max speed 100mb)
+ */
+MODULE_PARM(sbp2_max_speed,"i");
+MODULE_PARM_DESC(sbp2_max_speed, "Force max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)");
+static int sbp2_max_speed = SPEED_400;
+
+/*
+ * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to
+ * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices.
+ */
+MODULE_PARM(sbp2_serialize_io,"i");
+MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
+static int sbp2_serialize_io = 0;	/* serialize I/O - available for debugging purposes */
+
+/*
+ * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note 
+ * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB.
+ * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note
+ * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes.
  */
-MODULE_PARM(max_speed,"i");
-MODULE_PARM_DESC(max_speed, "Force down max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)");
-static int max_speed = SPEED_400;
+MODULE_PARM(sbp2_max_sectors,"i");
+MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)");
+static int sbp2_max_sectors = SBP2_MAX_SECTORS;
 
 /*
- * Set serialize_io to 1 if you'd like only one scsi command sent down to
- * us at a time (debugging).
+ * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached
+ * (or if you need to do some debugging).
  */
-MODULE_PARM(serialize_io,"i");
-MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (debugging)");
-static int serialize_io = 1;	/* serialize I/O until stress issues are resolved */
+MODULE_PARM(sbp2_max_outstanding_cmds,"i");
+MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)");
+static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS;
 
 /*
- * Set no_large_packets to 1 if you'd like to limit the size of requests
- * sent down to us (normally the sbp2 driver will break up any requests to
- * any individual devices with 128KB transfer size limits).  Sets max s/g
- * list elements to 0x1f in size and disables s/g clustering.
+ * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked 
+ * command per sbp2 device may allow some performance gains, but some older sbp2 devices have 
+ * firmware bugs resulting in problems when linking commands... so, enable this with care. 
+ * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of 
+ * concurrent/linked commands.  =)
  */
-MODULE_PARM(no_large_packets,"i");
-MODULE_PARM_DESC(no_large_packets, "Do not allow large transfers from scsi drivers (debugging)");
-static int no_large_packets = 0;
+MODULE_PARM(sbp2_max_cmds_per_lun,"i");
+MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)");
+static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN;
+
 
 /*
  * Export information about protocols/devices supported by this driver.
@@ -348,11 +404,16 @@
 MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
 
 /*
- * Debug levels, configured via kernel config.
+ * Debug levels, configured via kernel config, or enable here.
  */
 
+/* #define CONFIG_IEEE1394_SBP2_DEBUG_ORBS */
+/* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */
+/* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */
+/* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */
+
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
-#define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2("__FUNCTION__"): "fmt, ## args)
+#define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
 static u32 global_outstanding_command_orbs = 0;
 #define outstanding_orb_incr global_outstanding_command_orbs++
 #define outstanding_orb_decr global_outstanding_command_orbs--
@@ -364,10 +425,10 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
 #define SBP2_DMA_ALLOC(fmt, args...) \
-	HPSB_ERR("sbp2("__FUNCTION__")alloc(%d): "fmt, \
+	HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \
 		 ++global_outstanding_dmas, ## args)
 #define SBP2_DMA_FREE(fmt, args...) \
-	HPSB_ERR("sbp2("__FUNCTION__")free(%d): "fmt, \
+	HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \
 		 --global_outstanding_dmas, ## args)
 static u32 global_outstanding_dmas = 0;
 #else
@@ -375,7 +436,6 @@
 #define SBP2_DMA_FREE(fmt, args...)
 #endif
 
-
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 2
 #define SBP2_DEBUG(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
 #define SBP2_INFO(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
@@ -388,9 +448,9 @@
 #define SBP2_WARN(fmt, args...)		HPSB_WARN("sbp2: "fmt, ## args)
 #else 
 #define SBP2_DEBUG(fmt, args...)
-#define SBP2_INFO(fmt, args...)
-#define SBP2_NOTICE(fmt, args...)
-#define SBP2_WARN(fmt, args...)
+#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
+#define SBP2_NOTICE(fmt, args...)       HPSB_NOTICE("sbp2: "fmt, ## args)
+#define SBP2_WARN(fmt, args...)         HPSB_WARN("sbp2: "fmt, ## args)
 #endif
 
 #define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
@@ -418,7 +478,6 @@
 static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
 
 static LIST_HEAD(sbp2_host_info_list);
-static int sbp2_host_count = 0;
 
 static struct hpsb_highlevel *sbp2_hl_handle = NULL;
 
@@ -489,7 +548,19 @@
 	struct hpsb_packet *packet;
 	int i;
 
-	/* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */
+	hi->request_packet = kmalloc(sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS, 
+				     GFP_KERNEL);
+
+	if (!hi->request_packet) {
+		SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!");
+		return(-ENOMEM);
+	}
+	memset(hi->request_packet, 0, sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS);
+
+	/* 
+	 * Create a pool of request packets. Just take the max supported 
+	 * concurrent commands and multiply by two to be safe... 
+	 */
 	for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) {
 
 		/*
@@ -546,6 +617,7 @@
 		}
 
 	}
+	kfree(hi->request_packet);
 	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
 
 	return;
@@ -560,7 +632,7 @@
  */
 static struct sbp2_request_packet *
 sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
-				       nodeid_t node, u64 addr,
+				       struct node_entry *ne, u64 addr,
 				       size_t data_size,
 				       quadlet_t data) {
 	struct list_head *lh;
@@ -589,12 +661,11 @@
 		INIT_LIST_HEAD(&packet->list);
 		sema_init(&packet->state_change, 0);
 		packet->state = hpsb_unused;
-		packet->generation = get_hpsb_generation(hi->host);
 		packet->data_be = 1;
+		
+		hpsb_node_fill_packet(ne, packet);
 
-		packet->host = hi->host;
-		packet->tlabel = get_tlabel(hi->host, node, 1);
-		packet->node_id = node;
+		packet->tlabel = get_tlabel(hi->host, packet->node_id, 1);
 
 		if (!data_size) {
 			fill_async_writequad(packet, addr, data);
@@ -716,8 +787,8 @@
 }
 
 /* 
- * This functions finds the sbp2_command for a given outstanding command
- * orb. Only looks at the inuse list.
+ * This function finds the sbp2_command for a given outstanding command
+ * orb.Only looks at the inuse list.
  */
 static struct sbp2_command_info *sbp2util_find_command_for_orb(
 		struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
@@ -744,7 +815,7 @@
 }
 
 /* 
- * This functions finds the sbp2_command for a given outstanding SCpnt.
+ * This function finds the sbp2_command for a given outstanding SCpnt.
  * Only looks at the inuse list.
  */
 static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
@@ -787,7 +858,6 @@
 		command = list_entry(lh, struct sbp2_command_info, list);
 		command->Current_done = Current_done;
 		command->Current_SCpnt = Current_SCpnt;
-		command->linked = 0;
 		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);
 	} else {
 		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
@@ -804,14 +874,26 @@
 	hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0];
 
 	if (hi == NULL) {
-		printk(KERN_ERR __FUNCTION__": hi == NULL\n");
+		printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
 		return;
 	}
 
 	if (command->cmd_dma) {
-		pci_unmap_single(hi->host->pdev, command->cmd_dma,
-				 command->dma_size, command->dma_dir);
-		SBP2_DMA_FREE("single bulk");
+		if (command->dma_type == CMD_DMA_SINGLE) {
+			pci_unmap_single(hi->host->pdev, command->cmd_dma,
+					 command->dma_size, command->dma_dir);
+			SBP2_DMA_FREE("single bulk");
+		} else if (command->dma_type == CMD_DMA_PAGE) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
+			pci_unmap_single(hi->host->pdev, command->cmd_dma,
+					 command->dma_size, command->dma_dir);
+#else
+			pci_unmap_page(hi->host->pdev, command->cmd_dma,
+				       command->dma_size, command->dma_dir);
+#endif /* Linux version < 2.4.13 */
+			SBP2_DMA_FREE("single page");
+		} /* XXX: Check for CMD_DMA_NONE bug */
+		command->dma_type = CMD_DMA_NONE;
 		command->cmd_dma = 0;
 	}
 
@@ -865,7 +947,8 @@
 	 * Register our sbp2 status address space...
 	 */
 	hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
-				SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block));
+				SBP2_STATUS_FIFO_ADDRESS + 
+				SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
 
 	hpsb_register_protocol(&sbp2_driver);
 
@@ -923,7 +1006,8 @@
 
 	if (sbp2_reconnect_device(hi, scsi_id)) {
 		
-		/* Ok, reconnect has failed.  Perhaps we didn't
+		/* 
+		 * Ok, reconnect has failed. Perhaps we didn't
 		 * reconnect fast enough. Try doing a regular login.
 		 */
 		if (sbp2_login_device(hi, scsi_id)) {
@@ -991,13 +1075,14 @@
 
 	sbp2_spin_lock(&sbp2_host_info_lock, flags);
 	list_add_tail(&hi->list, &sbp2_host_info_list);
-	sbp2_host_count++;
 	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
 
 	/* Register our host with the SCSI stack. */
 	hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
-	if (hi->scsi_host)
+	if (hi->scsi_host) {
 		hi->scsi_host->hostdata[0] = (unsigned long)hi;
+		hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
+	}
 	scsi_driver_template.present++;
 
 	return;
@@ -1014,12 +1099,29 @@
 
 	list_for_each (lh, &sbp2_host_info_list) {
 		hi = list_entry(lh, struct sbp2scsi_host_info, list);
-		if (hi->host == host) {
+		if (hi->host == host)
 			return hi;
-		}
 	}
 
-	return(NULL);
+	return NULL;
+}
+
+/*
+ * This function returns a host info structure for a given Scsi_Host
+ * struct.
+ */
+static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host)
+{
+	struct list_head *lh;
+	struct sbp2scsi_host_info *hi;
+
+	list_for_each (lh, &sbp2_host_info_list) {
+		hi = list_entry(lh, struct sbp2scsi_host_info, list);
+		if (hi->scsi_host == host)
+			return hi;
+	}
+
+	return NULL;
 }
 
 /*
@@ -1037,10 +1139,7 @@
 	hi = sbp2_find_host_info(host);
 	if (hi != NULL) {
 		sbp2util_remove_request_packet_pool(hi);
-		sbp2_host_count--;
 		list_del(&hi->list);
-		scsi_unregister(hi->scsi_host);
-		scsi_driver_template.present--;
 		kfree(hi);
 	}
 	else
@@ -1164,19 +1263,11 @@
 	/* 
 	 * Knock the total command orbs down if we are serializing I/O
 	 */
-	if (serialize_io) {
+	if (sbp2_serialize_io) {
 		scsi_id->sbp2_total_command_orbs = 2;	/* one extra for good measure */
 	}
 
 	/*
-	 * Allocate some extra command orb structures for devices with
-	 * 128KB limit.
-	 */
-	if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) {
-		scsi_id->sbp2_total_command_orbs *= 4;
-	} 
-
-	/*
 	 * Find an empty spot to stick our scsi id instance data. 
 	 */
 	for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
@@ -1322,14 +1413,19 @@
 	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
 	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
 	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1);	/* Exclusive access to device */
-	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);		/* Notify us of login complete */
+	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);	/* Notify us of login complete */
+	/* Set the lun if we were able to pull it from the device's unit directory */
+	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
+		scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
+	}
 	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");
 
 	scsi_id->login_orb->passwd_resp_lengths =
 		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
 	SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");
 
-	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
+	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+					     SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
 	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
 					      SBP2_STATUS_FIFO_ADDRESS_HI);
 	SBP2_DEBUG("sbp2_login_device: status FIFO initialized");
@@ -1357,7 +1453,7 @@
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
 	SBP2_DEBUG("sbp2_login_device: prepared to write");
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 	SBP2_DEBUG("sbp2_login_device: written");
 
 	/*
@@ -1367,9 +1463,9 @@
 
 	save_flags(flags);
 	cli();
-	/* 10 second timeout */
+	/* 20 second timeout */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma)
-		sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ);
+		sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ);
 	restore_flags(flags);
 
 	SBP2_DEBUG("sbp2_login_device: initial check");
@@ -1446,7 +1542,8 @@
 	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
 
 	scsi_id->logout_orb->reserved5 = 0x0;
-	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
+	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+					      SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
 	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
 					       SBP2_STATUS_FIFO_ADDRESS_HI);
 
@@ -1462,7 +1559,7 @@
 	data[1] = scsi_id->logout_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/* Wait for device to logout...1 second. */
 	sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
@@ -1500,7 +1597,8 @@
 	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
 
 	scsi_id->reconnect_orb->reserved5 = 0x0;
-	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
+	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+						 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
 	scsi_id->reconnect_orb->status_FIFO_hi =
 		(ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);
 
@@ -1521,7 +1619,7 @@
 	data[1] = scsi_id->reconnect_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/*
 	 * Wait for reconnect status... but, only if the device has not
@@ -1575,7 +1673,7 @@
 	 */
 	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
 
-	if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
+	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
 		SBP2_ERR("sbp2_set_busy_timeout error");
 	}
 
@@ -1594,16 +1692,24 @@
 
 	SBP2_DEBUG("sbp2_parse_unit_directory");
 
+	/* Initialize some fields, in case an entry does not exist */
+	scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;
+	scsi_id->sbp2_management_agent_addr = 0x0;
+	scsi_id->sbp2_command_set_spec_id = 0x0;
+	scsi_id->sbp2_command_set = 0x0;
+	scsi_id->sbp2_unit_characteristics = 0x0;
+	scsi_id->sbp2_firmware_revision = 0x0;
+
 	ud = scsi_id->ud;
 
 	/* Handle different fields in the unit directory, based on keys */
-	for (i = 0; i < ud->arb_count; i++) {
-		switch (ud->arb_keys[i]) {
+	for (i = 0; i < ud->count; i++) {
+		switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
 		case SBP2_CSR_OFFSET_KEY:
 			/* Save off the management agent address */
 			scsi_id->sbp2_management_agent_addr =
-				CONFIG_ROM_INITIAL_MEMORY_SPACE + 
-				(ud->arb_values[i] << 2);
+				CSR_REGISTER_BASE + 
+				(CONFIG_ROM_VALUE(ud->quadlets[i]) << 2);
 
 			SBP2_DEBUG("sbp2_management_agent_addr = %x",
 				   (unsigned int) scsi_id->sbp2_management_agent_addr);
@@ -1611,14 +1717,16 @@
 
 		case SBP2_COMMAND_SET_SPEC_ID_KEY:
 			/* Command spec organization */
-			scsi_id->sbp2_command_set_spec_id = ud->arb_values[i];
+			scsi_id->sbp2_command_set_spec_id
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
 				   (unsigned int) scsi_id->sbp2_command_set_spec_id);
 			break;
 
 		case SBP2_COMMAND_SET_KEY:
 			/* Command set used by sbp2 device */
-			scsi_id->sbp2_command_set = ud->arb_values[i];
+			scsi_id->sbp2_command_set
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_command_set = %x",
 				   (unsigned int) scsi_id->sbp2_command_set);
 			break;
@@ -1628,7 +1736,8 @@
 			 * Unit characterisitcs (orb related stuff
 			 * that I'm not yet paying attention to)
 			 */
-			scsi_id->sbp2_unit_characteristics = ud->arb_values[i];
+			scsi_id->sbp2_unit_characteristics
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_unit_characteristics = %x",
 				   (unsigned int) scsi_id->sbp2_unit_characteristics);
 			break;
@@ -1638,7 +1747,8 @@
 			 * Device type and lun (used for
 			 * detemining type of sbp2 device)
 			 */
-			scsi_id->sbp2_device_type_and_lun = ud->arb_values[i];
+			scsi_id->sbp2_device_type_and_lun
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_device_type_and_lun = %x",
 				   (unsigned int) scsi_id->sbp2_device_type_and_lun);
 			break;
@@ -1651,8 +1761,11 @@
 			 * bridge with 128KB max transfer size
 			 * limitation.
 			 */
-			scsi_id->sbp2_firmware_revision = ud->arb_values[i];
-			if (scsi_id->sbp2_firmware_revision ==
+			scsi_id->sbp2_firmware_revision
+				= CONFIG_ROM_VALUE(ud->quadlets[i]);
+			SBP2_DEBUG("sbp2_firmware_revision = %x",
+				   (unsigned int) scsi_id->sbp2_firmware_revision);
+			if ((scsi_id->sbp2_firmware_revision & 0xffff00) ==
 			    SBP2_128KB_BROKEN_FIRMWARE) {
 				SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size");
 			}
@@ -1682,8 +1795,8 @@
 						  + (scsi_id->ne->nodeid & NODE_MASK)];
 
 	/* Bump down our speed if the user requested it */
-	if (scsi_id->speed_code > max_speed) {
-		scsi_id->speed_code = max_speed;
+	if (scsi_id->speed_code > sbp2_max_speed) {
+		scsi_id->speed_code = sbp2_max_speed;
 		SBP2_ERR("Forcing SBP-2 max speed down to %s",
 			 hpsb_speedto_str[scsi_id->speed_code]);
 	}
@@ -1693,7 +1806,7 @@
 	scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],
 					(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
 
-	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
+	SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]",
 		 NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code],
 		 1 << ((u32)scsi_id->max_payload_size + 2));
 
@@ -1713,7 +1826,7 @@
 	 * Ok, let's write to the target's management agent register
 	 */
 	agent_reset_request_packet =
-		sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,
+		sbp2util_allocate_write_request_packet(hi, scsi_id->ne,
 						       scsi_id->sbp2_command_block_agent_addr +
 						       SBP2_AGENT_RESET_OFFSET,
 						       0, ntohl(SBP2_AGENT_RESET_DATA));
@@ -1753,13 +1866,15 @@
 				   unchar *scsi_cmd,
 				   unsigned int scsi_use_sg,
 				   unsigned int scsi_request_bufflen,
-				   void *scsi_request_buffer, int dma_dir)
+				   void *scsi_request_buffer, 
+				   unsigned char scsi_dir)
 {
 	struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
 	struct sbp2_command_orb *command_orb = &command->command_orb;
 	struct sbp2_unrestricted_page_table *scatter_gather_element =
 		&command->scatter_gather_element[0];
-	u32 sg_count, sg_len;
+	int dma_dir = scsi_to_pci_dma_dir (scsi_dir);
+	u32 sg_count, sg_len, orb_direction;
 	dma_addr_t sg_addr;
 	int i;
 
@@ -1771,25 +1886,49 @@
 	 * that data_size becomes the number of s/g elements, and
 	 * page_size should be zero (for unrestricted).
 	 */
-	command_orb->next_ORB_hi = 0xffffffff;
-	command_orb->next_ORB_lo = 0xffffffff;
+	command_orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
+	command_orb->next_ORB_lo = 0x0;
 	command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size);
 	command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code);
 	command_orb->misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */
 
 	/*
+	 * Get the direction of the transfer. If the direction is unknown, then use our
+	 * goofy table as a back-up.
+	 */
+	switch (scsi_dir) {
+		case SCSI_DATA_NONE:
+			orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
+			break;
+		case SCSI_DATA_WRITE:
+			orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
+			break;
+		case SCSI_DATA_READ:
+			orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
+			break;
+		case SCSI_DATA_UNKNOWN:
+		default:
+			SBP2_ERR("SCSI data transfer direction not specified. "
+				 "Update the SBP2 direction table in sbp2.h if " 
+				 "necessary for your application");
+			print_command (scsi_cmd);
+			orb_direction = sbp2scsi_direction_table[*scsi_cmd];
+			break;
+	}
+
+	/*
 	 * Set-up our pagetable stuff... unfortunately, this has become
 	 * messier than I'd like. Need to clean this up a bit.   ;-)
 	 */
-	if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) {
+	if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
 
 		SBP2_DEBUG("No data transfer");
 
 		/*
 		 * Handle no data transfer
 		 */
-		command_orb->data_descriptor_hi = 0xffffffff;
-		command_orb->data_descriptor_lo = 0xffffffff;
+		command_orb->data_descriptor_hi = 0x0;
+		command_orb->data_descriptor_lo = 0x0;
 		command_orb->misc |= ORB_SET_DIRECTION(1);
 
 	} else if (scsi_use_sg) {
@@ -1804,15 +1943,24 @@
 			SBP2_DEBUG("Only one s/g element");
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
+			command->dma_type = CMD_DMA_PAGE;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
 			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
 							   command->dma_size,
 							   command->dma_dir);
-			SBP2_DMA_ALLOC("single scatter element");
+#else
+			command->cmd_dma = pci_map_page(hi->host->pdev,
+							sgpnt[0].page,
+							sgpnt[0].offset,
+							command->dma_size,
+							command->dma_dir);
+#endif /* Linux version < 2.4.13 */
+			SBP2_DMA_ALLOC("single page scatter element");
 
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->cmd_dma;
 			command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 		} else {
 			int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir);
@@ -1824,7 +1972,7 @@
 
 			/* use page tables (s/g) */
 			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->sge_dma;
 
@@ -1869,6 +2017,7 @@
 
 		command->dma_dir = dma_dir;
 		command->dma_size = scsi_request_bufflen;
+		command->dma_type = CMD_DMA_SINGLE;
 		command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer,
 						   command->dma_size,
 						   command->dma_dir);
@@ -1883,15 +2032,15 @@
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->cmd_dma;
 			command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 			/*
 			 * Sanity, in case our direction table is not
 			 * up-to-date
 			 */
 			if (!scsi_request_bufflen) {
-				command_orb->data_descriptor_hi = 0xffffffff;
-				command_orb->data_descriptor_lo = 0xffffffff;
+				command_orb->data_descriptor_hi = 0x0;
+				command_orb->data_descriptor_lo = 0x0;
 				command_orb->misc |= ORB_SET_DIRECTION(1);
 			}
 
@@ -1905,7 +2054,7 @@
 
 			/* Use page tables (s/g) */
 			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
+			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 			/*
 			 * fill out our sbp-2 page tables (and split up
@@ -1967,9 +2116,15 @@
 	struct sbp2_command_orb *command_orb = &command->command_orb;
 
 	outstanding_orb_incr;
-	SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x",
-			command_orb, command->linked, global_outstanding_command_orbs);
+	SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
+			command_orb, global_outstanding_command_orbs);
 
+	pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+			    sizeof(struct sbp2_command_orb),
+			    PCI_DMA_BIDIRECTIONAL);
+	pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+			    sizeof(command->scatter_gather_element),
+			    PCI_DMA_BIDIRECTIONAL);
 	/*
 	 * Check to see if there are any previous orbs to use
 	 */
@@ -1981,7 +2136,7 @@
 		if (hpsb_node_entry_valid(scsi_id->ne)) {
 
 			command_request_packet =
-				sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,
+				sbp2util_allocate_write_request_packet(hi, scsi_id->ne,
 								scsi_id->sbp2_command_block_agent_addr +
 								SBP2_ORB_POINTER_OFFSET, 8, 0);
 		
@@ -2006,6 +2161,7 @@
 		}
 
 		scsi_id->last_orb = command_orb;
+		scsi_id->last_orb_dma = command->command_orb_dma;
 
 	} else {
 
@@ -2020,15 +2176,17 @@
 			cpu_to_be32(command->command_orb_dma);
 		/* Tells hardware that this pointer is valid */
 		scsi_id->last_orb->next_ORB_hi = 0x0;
+		pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma,
+				    sizeof(struct sbp2_command_orb),
+				    PCI_DMA_BIDIRECTIONAL);
 
 		/*
-		 * Only ring the doorbell if we need to (first parts of
-		 * linked orbs don't need this).
+		 * Ring the doorbell
 		 */
-		if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) {
+		if (hpsb_node_entry_valid(scsi_id->ne)) {
 
 			command_request_packet = sbp2util_allocate_write_request_packet(hi,
-				LOCAL_BUS | scsi_id->ne->nodeid,
+				scsi_id->ne,
 				scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET,
 				0, cpu_to_be32(command->command_orb_dma));
 	
@@ -2047,6 +2205,7 @@
 		}
 
 		scsi_id->last_orb = command_orb;
+		scsi_id->last_orb_dma = command->command_orb_dma;
 
 	}
        	return(0);
@@ -2059,33 +2218,20 @@
 			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
-	u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
+	unsigned int request_bufflen = SCpnt->request_bufflen;
+	u8 device_type
+		= SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
 	struct sbp2_command_info *command;
 
 	SBP2_DEBUG("sbp2_send_command");
-	SBP2_DEBUG("SCSI command = %02x", *cmd);
-	SBP2_DEBUG("SCSI transfer size = %x", SCpnt->request_bufflen);
+	SBP2_DEBUG("SCSI command:");
+#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
+	print_command (cmd);
+#endif
+	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
 	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
 
 	/*
-	 * Check for broken devices that can't handle greater than 128K
-	 * transfers, and deal with them in a hacked ugly way.
-	 */
-	if ((scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) && 
-	    (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && 
-	    (device_type == TYPE_DISK) &&
-	    (SCpnt->use_sg) &&
-	    (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) {
-
-		/*
-		 * Darn, a broken device. We'll need to split up the
-		 * transfer ourselves.
-		 */
-		sbp2_send_split_command(hi, scsi_id, SCpnt, done);
-		return(0);
-	}
-
-	/*
 	 * Allocate a command orb and s/g structure
 	 */
 	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
@@ -2094,14 +2240,24 @@
 	}
 
 	/*
+	 * The scsi stack sends down a request_bufflen which does not match the
+	 * length field in the scsi cdb. This causes some sbp2 devices to 
+	 * reject this inquiry command. Hack fix is to set both buff length and
+	 * length field in cdb to 36. This gives best compatibility.
+	 */
+	if (*cmd == INQUIRY) {
+		request_bufflen = cmd[4] = 0x24;
+	}
+
+	/*
 	 * Now actually fill in the comamnd orb and sbp2 s/g list
 	 */
 	sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg,
-			SCpnt->request_bufflen, SCpnt->request_buffer,
-			scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); 
+				request_bufflen, SCpnt->request_buffer,
+				SCpnt->sc_data_direction); 
 	/*
 	 * Update our cdb if necessary (to handle sbp2 RBC command set
-	 * differences).  This is where the command set hacks go!   =)
+	 * differences). This is where the command set hacks go!   =)
 	 */
 	if ((device_type == TYPE_DISK) ||
 	    (device_type == TYPE_SDAD) ||
@@ -2122,120 +2278,6 @@
 	return(0);
 }
 
-/*
- * This function is called for broken sbp2 device, where we have to break
- * up large transfers.
- */
-static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
-				   Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-{
-	unchar *cmd = (unchar *) SCpnt->cmnd;
-	struct scatterlist *sgpnt = (struct scatterlist *) SCpnt->request_buffer;
-	struct sbp2_command_info *command;
-	unsigned int i, block_count, block_address, block_size;
-	unsigned int current_sg = 0;
-	unsigned int total_transfer = 0;
-	unsigned int total_sg = 0;
-	unchar new_cmd[12];
-
-	memset(new_cmd, 0, 12);
-	memcpy(new_cmd, cmd, COMMAND_SIZE(*cmd));
-
-	/*
-	 * Turns command into 10 byte version
-	 */
-	sbp2_check_sbp2_command(new_cmd);
-        
-	/*
-	 * Pull block size, block address, block count from command sent down
-	 */
-	block_count = (cmd[7] << 8) | cmd[8];
-	block_address = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5]; 
-	block_size = SCpnt->request_bufflen/block_count;
-
-	/*
-	 * Walk the scsi s/g list to determine how much we can transfer in one pop
-	 */
-	for (i=0; i<SCpnt->use_sg; i++) {
-
-		total_transfer+=sgpnt[i].length;
-		total_sg++;
-
-		if (total_transfer > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) {
-
-			/*
-			 * Back everything up one, so that we're less than 128KB
-			 */
-			total_transfer-=sgpnt[i].length;
-			total_sg--;
-			i--;
-
-			command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
-			if (!command) {
-				return(-EIO);
-			}
-
-			/*
-			 * This is not the final piece, so mark it as linked
-			 */
-			command->linked = 1;
-
-			block_count = total_transfer/block_size;
-			new_cmd[2] = (unchar) (block_address >> 24) & 0xff;
-			new_cmd[3] = (unchar) (block_address >> 16) & 0xff;
-			new_cmd[4] = (unchar) (block_address >> 8) & 0xff;
-			new_cmd[5] = (unchar) block_address & 0xff;
-			new_cmd[7] = (unchar) (block_count >> 8) & 0xff;
-			new_cmd[8] = (unchar) block_count & 0xff;
-			block_address+=block_count;
-
-			sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, 
-						total_transfer, &sgpnt[current_sg],
-						scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
-
-			/*
-			 * Link up the orb, and ring the doorbell if needed
-			 */
-			memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
-			sbp2_link_orb_command(hi, scsi_id, command);
-
-			current_sg += total_sg;
-			total_sg = 0;
-			total_transfer = 0;
-
-		}
-
-	}
-
-	/*
-	 * Get the last piece...
-	 */
-	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
-	if (!command) {
-		return(-EIO);
-	}
-
-	block_count = total_transfer/block_size;
-	new_cmd[2] = (unchar) (block_address >> 24) & 0xff;
-	new_cmd[3] = (unchar) (block_address >> 16) & 0xff;
-	new_cmd[4] = (unchar) (block_address >> 8) & 0xff;
-	new_cmd[5] = (unchar) block_address & 0xff;
-	new_cmd[7] = (unchar) (block_count >> 8) & 0xff;
-	new_cmd[8] = (unchar) block_count & 0xff;
-
-	sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, 
-				total_transfer, &sgpnt[current_sg],
-				scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
-
-	/*
-	 * Link up the orb, and ring the doorbell if needed
-	 */
-	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
-	sbp2_link_orb_command(hi, scsi_id, command);
-
-
-	return(0);
-}
 
 /*
  * This function deals with command set differences between Linux scsi
@@ -2367,15 +2409,29 @@
 				     Scsi_Cmnd *SCpnt)
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
-	u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16;
-        
+	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
+
 	SBP2_DEBUG("sbp2_check_sbp2_response");
 
 	switch (SCpnt->cmnd[0]) {
 		
 		case INQUIRY:
 
-			SBP2_DEBUG("Check Inquiry data");
+			/*
+			 * If scsi_id->sbp2_device_type_and_lun is uninitialized, then fill 
+			 * this information in from the inquiry response data. Lun is set to zero.
+			 */
+			if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
+				SBP2_DEBUG("Creating sbp2_device_type_and_lun from scsi inquiry data");
+				scsi_id->sbp2_device_type_and_lun = (scsi_buf[0] & 0x1f) << 16;
+			}
+
+			/*
+			 * Make sure data length is ok. Minimum length is 36 bytes
+			 */
+			if (scsi_buf[4] == 0) {
+				scsi_buf[4] = 36 - 5;
+			}
 
 			/*
 			 * Check for Simple Direct Access Device and change it to TYPE_DISK
@@ -2431,7 +2487,7 @@
 {
 	struct sbp2scsi_host_info *hi = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
-	int i;
+	u32 id;
 	unsigned long flags;
 	Scsi_Cmnd *SCpnt = NULL;
 	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
@@ -2456,17 +2512,11 @@
 	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
 
 	/*
-	 * Find our scsi_id structure
+	 * Find our scsi_id structure by looking at the status fifo address written to by
+	 * the sbp2 device.
 	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-		if (hi->scsi_id[i]) {
-			if ((hi->scsi_id[i]->ne->nodeid & NODE_MASK) == (nodeid & NODE_MASK)) {
-				scsi_id = hi->scsi_id[i];
-				SBP2_DEBUG("SBP-2 status write from node %x", scsi_id->ne->nodeid);
-				break;
-			}
-		}
-	}
+	id = SBP2_STATUS_FIFO_OFFSET_TO_ENTRY((u32)(addr - SBP2_STATUS_FIFO_ADDRESS)); 
+	scsi_id = hi->scsi_id[id];
 
 	if (!scsi_id) {
 		SBP2_ERR("scsi_id is NULL - device is gone?");
@@ -2491,6 +2541,12 @@
 	if (command) {
 
 		SBP2_DEBUG("Found status for command ORB");
+		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+				    sizeof(struct sbp2_command_orb),
+				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+				    sizeof(command->scatter_gather_element),
+				    PCI_DMA_BIDIRECTIONAL);
 
 		SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
 		outstanding_orb_decr;
@@ -2501,25 +2557,30 @@
 		SCpnt = command->Current_SCpnt;
 		sbp2util_mark_command_completed(scsi_id, command);
 
-		if (SCpnt && !command->linked) {
+		if (SCpnt) {
 
 			/*
-			 * Handle check conditions
+			 * See if the target stored any scsi status information
 			 */
-			if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
-
-				SBP2_DEBUG("CHECK CONDITION");
-
+			if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) {
 				/*
 				 * Translate SBP-2 status to SCSI sense data
 				 */
 				scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
+			}
 
+			/*
+			 * Handle check conditions. If there is either SBP status or SCSI status
+			 * then we'll do a fetch agent reset and note that a check condition
+			 * occured.
+			 */
+			if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc) ||
+			    scsi_status) {
 				/*
 				 * Initiate a fetch agent reset. 
 				 */
+				SBP2_DEBUG("CHECK CONDITION");
 				sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
-
 			}
 
 			SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
@@ -2548,7 +2609,6 @@
 	return(RCODE_COMPLETE);
 }
 
-
 
 /**************************************
  * SCSI interface related section
@@ -2613,8 +2673,7 @@
 	}
 
 	/*
-	 * Check to see if there is a command in progress and just return
-	 * busy (to be queued later)
+	 * Check to see if we are in the middle of a bus reset.
 	 */
 	if (!hpsb_node_entry_valid(scsi_id->ne)) {
 		SBP2_ERR("Bus reset in progress - rejecting command");
@@ -2653,8 +2712,14 @@
 		SBP2_DEBUG("Found pending command to complete");
 		lh = scsi_id->sbp2_command_orb_inuse.next;
 		command = list_entry(lh, struct sbp2_command_info, list);
+		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
+				    sizeof(struct sbp2_command_orb),
+				    PCI_DMA_BIDIRECTIONAL);
+		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
+				    sizeof(command->scatter_gather_element),
+				    PCI_DMA_BIDIRECTIONAL);
 		sbp2util_mark_command_completed(scsi_id, command);
-		if (command->Current_SCpnt && !command->linked) {
+		if (command->Current_SCpnt) {
 			void (*done)(Scsi_Cmnd *) = command->Current_done;
 			command->Current_SCpnt->result = status << 16;
 			done (command->Current_SCpnt);
@@ -2710,13 +2775,17 @@
 			/*
 			 * Debug stuff
 			 */
+#if CONFIG_IEEE1394_SBP2_DEBUG >= 1
+			print_command (SCpnt->cmnd);
 			print_sense("bh", SCpnt);
+#endif
 
 			break;
 
 		case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
 			SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
 			SCpnt->result = DID_NO_CONNECT << 16;
+			print_command (SCpnt->cmnd);
 			break;
 
 		case SBP2_SCSI_STATUS_CONDITION_MET:
@@ -2724,6 +2793,7 @@
 		case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
 			SBP2_ERR("Bad SCSI status = %x", scsi_status);
 			SCpnt->result = DID_ERROR << 16;
+			print_command (SCpnt->cmnd);
 			break;
 
 		default:
@@ -2739,19 +2809,6 @@
 	}
 
 	/*
-	 * One more quick hack (not enabled by default). Some sbp2 devices
-	 * do not support mode sense. Turn-on this hack to allow the
-	 * device to pass the sd driver's write-protect test (so that you
-	 * can mount the device rw).
-	 */
-	if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) {
-		SBP2_INFO("Returning success to mode sense command");
-		SCpnt->result = DID_OK;
-		SCpnt->sense_buffer[0] = 0;
-		memset (SCpnt->request_buffer, 0, 8);
-	}
-
-	/*
 	 * If a bus reset is in progress and there was an error, complete
 	 * the command as busy so that it will get retried.
 	 */
@@ -2766,16 +2823,22 @@
 	 * or hot-plug...
 	 */
 	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
-		SBP2_INFO("UNIT ATTENTION - return busy");
+		SBP2_DEBUG("UNIT ATTENTION - return busy");
 		SCpnt->result = DID_BUS_BUSY << 16;
 	}
 
 	/*
 	 * Tell scsi stack that we're done with this command
 	 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	spin_lock_irq(&io_request_lock);
 	done (SCpnt);
 	spin_unlock_irq(&io_request_lock);
+#else
+	spin_lock_irq(&hi->scsi_host->host_lock);
+	done (SCpnt);
+	spin_unlock_irq(&hi->scsi_host->host_lock);
+#endif
 
 	return;
 }
@@ -2792,27 +2855,33 @@
 	unsigned long flags;
 
 	SBP2_ERR("aborting sbp2 command");
-
+	print_command (SCpnt->cmnd);
+        
 	if (scsi_id) {
 
 		/*
 		 * Right now, just return any matching command structures
-		 * to the free pool (there may be more than one because of
-		 * broken up/linked commands).
+		 * to the free pool.
 		 */
 		sbp2_spin_lock(&hi->sbp2_command_lock, flags);
-		do {
-			command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
-			if (command) {
-				SBP2_DEBUG("Found command to abort");
-				sbp2util_mark_command_completed(scsi_id, command);
-				if (command->Current_SCpnt && !command->linked) {
-					void (*done)(Scsi_Cmnd *) = command->Current_done;
-					command->Current_SCpnt->result = DID_ABORT << 16;
-					done (command->Current_SCpnt);
-				}
+		command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
+		if (command) {
+			SBP2_DEBUG("Found command to abort");
+			pci_dma_sync_single(hi->host->pdev,
+					    command->command_orb_dma,
+					    sizeof(struct sbp2_command_orb),
+					    PCI_DMA_BIDIRECTIONAL);
+			pci_dma_sync_single(hi->host->pdev,
+					    command->sge_dma,
+					    sizeof(command->scatter_gather_element),
+					    PCI_DMA_BIDIRECTIONAL);
+			sbp2util_mark_command_completed(scsi_id, command);
+			if (command->Current_SCpnt) {
+				void (*done)(Scsi_Cmnd *) = command->Current_done;
+				command->Current_SCpnt->result = DID_ABORT << 16;
+				done (command->Current_SCpnt);
 			}
-		} while (command);
+		}
 
 		/*
 		 * Initiate a fetch agent reset. 
@@ -2822,24 +2891,25 @@
 		sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
 	}
 
-	return(SCSI_ABORT_SUCCESS);
+	return(SUCCESS);
 }
 
 /*
  * Called by scsi stack when something has really gone wrong.
  */
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) 
+static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) 
 {
 	struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
+	struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->target];
 
 	SBP2_ERR("reset requested");
 
-	if (hi) {
+	if (scsi_id) {
 		SBP2_ERR("Generating IEEE-1394 bus reset");
-		hpsb_reset_bus(hi->host, LONG_RESET);
+		sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
 	}
 
-	return(SCSI_RESET_SUCCESS);
+	return(SUCCESS);
 }
 
 /*
@@ -2868,12 +2938,15 @@
 	return(0);
 }
 
+/*
+ * Called by scsi stack after scsi driver is registered
+ */
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt) 
 {
 	SBP2_DEBUG("sbp2scsi_detect");
 
 	/*
-	 * Call sbp2_init to register with the ieee1394 stack.  This
+	 * Call sbp2_init to register with the ieee1394 stack. This
 	 * results in a callback to sbp2_add_host for each ieee1394
 	 * host controller currently registered, and for each of those
 	 * we register a scsi host with the scsi stack.
@@ -2881,9 +2954,39 @@
 	sbp2_init();
 
 	/* We return the number of hosts registered. */
-	return sbp2_host_count;
+	return scsi_driver_template.present;
+}
+
+
+/*
+ * Called for contents of procfs
+ */
+static const char *sbp2scsi_info (struct Scsi_Host *host)
+{
+	struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host);
+	static char info[1024];
+
+	if (!hi) /* shouldn't happen, but... */
+        	return "IEEE-1394 SBP-2 protocol driver";
+
+	sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n"
+		"SBP-2 module load options:\n"
+		"- Max speed supported: %s\n"
+		"- Max sectors per I/O supported: %d\n"
+		"- Max outstanding commands supported: %d\n"
+		"- Max outstanding commands per lun supported: %d\n"
+                "- Serialized I/O (debug): %s",
+		hi->host->driver->name, 
+		hpsb_speedto_str[sbp2_max_speed],
+		sbp2_max_sectors,
+		sbp2_max_outstanding_cmds,
+		sbp2_max_cmds_per_lun,
+		sbp2_serialize_io ? "yes" : "no");
+
+	return info;
 }
 
+
 MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
 MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
 MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
@@ -2891,24 +2994,23 @@
 
 /* SCSI host template */
 static Scsi_Host_Template scsi_driver_template = {
-	name:		"IEEE-1394 SBP-2 protocol driver",
-	detect:		sbp2scsi_detect,
-	queuecommand:	sbp2scsi_queuecommand,
-	abort:		sbp2scsi_abort,
-	reset:		sbp2scsi_reset,
-	bios_param:	sbp2scsi_biosparam,
-	can_queue:	SBP2SCSI_MAX_OUTSTANDING_CMDS,
-	this_id:	-1,
-	sg_tablesize:	SBP2_MAX_SG_ELEMENTS,
-	cmd_per_lun:	SBP2SCSI_MAX_CMDS_PER_LUN,
-	use_clustering:	SBP2_CLUSTERING,
-	emulated:	1,
-
-	module:         THIS_MODULE,
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
-	proc_name: SBP2_DEVICE_NAME
+	name:			"IEEE-1394 SBP-2 protocol driver",
+	info:			sbp2scsi_info,
+	detect:			sbp2scsi_detect,
+	queuecommand:		sbp2scsi_queuecommand,
+	eh_abort_handler:	sbp2scsi_abort,
+	eh_device_reset_handler:sbp2scsi_reset,
+	eh_bus_reset_handler:	sbp2scsi_reset,
+	eh_host_reset_handler:	sbp2scsi_reset,
+	bios_param:		sbp2scsi_biosparam,
+	this_id:		-1,
+	sg_tablesize:		SBP2_MAX_SG_ELEMENTS,
+	use_clustering:		SBP2_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	use_new_eh_code:	TRUE,
 #endif
+	emulated:		1,
+	proc_name:	SBP2_DEVICE_NAME,
 };
 
 static int sbp2_module_init(void)
@@ -2916,38 +3018,32 @@
 	SBP2_DEBUG("sbp2_module_init");
 
 	/*
-	 * Module load option for force one command at a time
+	 * Module load debug option to force one command at a time (serializing I/O)
 	 */
-	if (serialize_io) {
+	if (sbp2_serialize_io) {
 		SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
 		scsi_driver_template.can_queue = 1;
 		scsi_driver_template.cmd_per_lun = 1;
+	} else {
+		scsi_driver_template.can_queue = sbp2_max_outstanding_cmds;
+		scsi_driver_template.cmd_per_lun = sbp2_max_cmds_per_lun;
 	}
 
-	/*
-	 * Module load option to limit max size of requests from the
-	 * scsi drivers
+	/* 
+	 * Set max sectors (module load option). Default is 255 sectors. 
 	 */
-	if (no_large_packets) {
-		SBP2_ERR("Driver forced to limit max transfer size "
-			 "(no_large_packets = 1)");
-		scsi_driver_template.sg_tablesize = 0x1f;
-		scsi_driver_template.use_clustering = DISABLE_CLUSTERING;
-	}
-
-	if (mode_sense_hack) {
-		SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)");
-	}
+	scsi_driver_template.max_sectors = sbp2_max_sectors;
 
 	/*
 	 * Ideally we would register our scsi_driver_template with the
 	 * scsi stack and after that register with the ieee1394 stack
-	 * and process the add_host callbacks.  However, the detect
+	 * and process the add_host callbacks. However, the detect
 	 * function in the scsi host template requires that we find at
 	 * least one host, so we "nest" the registrations by calling
 	 * sbp2_init from the detect function.
 	 */
-	if (scsi_register_module(MODULE_SCSI_HA, &scsi_driver_template) ||
+	scsi_driver_template.module = THIS_MODULE;
+	if (SCSI_REGISTER_HOST(&scsi_driver_template) ||
 	    !scsi_driver_template.present) {
 		SBP2_ERR("Please load the lower level IEEE-1394 driver "
 			 "(e.g. ohci1394) before sbp2...");
@@ -2970,8 +3066,9 @@
 	 */
 	sbp2_cleanup();
 
-	if (scsi_unregister_module(MODULE_SCSI_HA, &scsi_driver_template))
+	if (SCSI_UNREGISTER_HOST(&scsi_driver_template))
 		SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
+
 }
 
 module_init(sbp2_module_init);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/sbp2.h linux-2.4.19-pre5/drivers/ieee1394/sbp2.h
--- linux-2.4.19-pre4/drivers/ieee1394/sbp2.h	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/ieee1394/sbp2.h	Fri Mar 29 14:49:31 2002
@@ -22,6 +22,15 @@
 #ifndef SBP2_H
 #define SBP2_H
 
+/* Some compatibility code */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define SCSI_REGISTER_HOST(tmpl)	scsi_register_module(MODULE_SCSI_HA, tmpl)
+#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_module(MODULE_SCSI_HA, tmpl)
+#else
+#define SCSI_REGISTER_HOST(tmpl)	scsi_register_host(tmpl)
+#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_host(tmpl)
+#endif
+
 #define SBP2_DEVICE_NAME		"sbp2"
 #define SBP2_DEVICE_NAME_SIZE		4
 
@@ -36,6 +45,7 @@
 #define ORB_DIRECTION_READ_FROM_MEDIA   0x1
 #define ORB_DIRECTION_NO_DATA_TRANSFER  0x2
 
+#define ORB_SET_NULL_PTR(value)			((value & 0x1) << 31)
 #define ORB_SET_NOTIFY(value)                   ((value & 0x1) << 31)
 #define ORB_SET_RQ_FMT(value)                   ((value & 0x3) << 29)
 #define ORB_SET_NODE_ID(value)			((value & 0xffff) << 16)
@@ -185,10 +195,28 @@
  * Miscellaneous SBP2 related config rom defines
  */
 
-#define SBP2_STATUS_FIFO_ADDRESS				0xfffe00000000ULL     /* for write posting! */
+/* 
+ * The status fifo address definition below is used as a status base, with a chunk
+ * separately assigned for each sbp2 device detected. For example, 0xfffe00000000ULL 
+ * is used for the first sbp2 device detected, 0xfffe00000020ULL for the next sbp2 
+ * device, and so on.
+ *
+ * Note: We could use a single status fifo address for all sbp2 devices, and figure 
+ * out which sbp2 device the status belongs to by looking at the source node id of
+ * the status write... but, using separate addresses for each sbp2 device allows for
+ * better code and the ability to support multiple luns within a single 1394 node.
+ *
+ * Also note that we choose the address range below as it is a region specified for
+ * write posting, where the ohci controller will automatically send an ack_complete
+ * when the status is written by the sbp2 device... saving a split transaction.   =)
+ */ 
+#define SBP2_STATUS_FIFO_ADDRESS				0xfffe00000000ULL
 #define SBP2_STATUS_FIFO_ADDRESS_HI                             0xfffe
 #define SBP2_STATUS_FIFO_ADDRESS_LO                             0x0
 
+#define SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(entry)			((entry) << 5)
+#define SBP2_STATUS_FIFO_OFFSET_TO_ENTRY(offset)		((offset) >> 5)
+
 #define SBP2_UNIT_DIRECTORY_OFFSET_KEY				0xd1
 #define SBP2_CSR_OFFSET_KEY					0x54
 #define SBP2_UNIT_SPEC_ID_KEY					0x12
@@ -199,6 +227,9 @@
 #define SBP2_DEVICE_TYPE_AND_LUN_KEY				0x14
 #define SBP2_FIRMWARE_REVISION_KEY				0x3c
 
+#define SBP2_DEVICE_TYPE(q)					(((q) >> 16) & 0x1f)
+#define SBP2_DEVICE_LUN(q)					((q) & 0xffff)
+
 #define SBP2_AGENT_STATE_OFFSET					0x00ULL
 #define SBP2_AGENT_RESET_OFFSET					0x04ULL
 #define SBP2_ORB_POINTER_OFFSET					0x08ULL
@@ -219,18 +250,13 @@
 #define SBP2_SW_VERSION_ENTRY					0x00010483
 
 /*
- * Miscellaneous general config rom related defines
+ * Other misc defines
  */
-
-#define CONFIG_ROM_INITIAL_MEMORY_SPACE 			0xfffff0000000ULL
-
-#define CONFIG_ROM_BASE_ADDRESS					0xfffff0000400ULL
-#define CONFIG_ROM_ROOT_DIR_BASE				0xfffff0000414ULL
-#define CONFIG_ROM_UNIT_DIRECTORY_OFFSET			0xfffff0000424ULL
-
 #define SBP2_128KB_BROKEN_FIRMWARE				0xa0b800
 #define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER			0x20000
 
+#define SBP2_DEVICE_TYPE_LUN_UNINITIALIZED			0xffffffff
+
 /*
  * Flags for SBP-2 functions
  */
@@ -243,16 +269,18 @@
 #define SBP2_MAX_SG_ELEMENTS		SG_ALL
 #define SBP2_CLUSTERING			ENABLE_CLUSTERING
 #define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000
-#define SBP2SCSI_MAX_SCSI_IDS		8
+#define SBP2SCSI_MAX_SCSI_IDS		16	/* Max sbp2 device instances supported */
 #define SBP2SCSI_MAX_OUTSTANDING_CMDS	8	/* Max total outstanding sbp2 commands allowed at a time! */
-#define SBP2SCSI_MAX_CMDS_PER_LUN	4 	/* Max outstanding sbp2 commands per device - tune as needed */
+#define SBP2SCSI_MAX_CMDS_PER_LUN	1 	/* Max outstanding sbp2 commands per device - tune as needed */
+#define SBP2_MAX_SECTORS		255	/* Max sectors supported */
 
 #ifndef TYPE_SDAD
 #define TYPE_SDAD			0x0e	/* simplified direct access device */
 #endif
 
 /*
- * SCSI direction table... since the scsi stack doesn't specify direction...   =(
+ * SCSI direction table... 
+ * (now used as a back-up in case the direction passed down from above is "unknown")
  *
  * DIN = IN data direction
  * DOU = OUT data direction
@@ -286,13 +314,8 @@
 	DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
 };
 
-
-/*
- * Number of request packets available for actual sbp2 I/O requests (these are used
- * for sending command and agent reset packets).
- */
-#define SBP2_MAX_REQUEST_PACKETS	SBP2SCSI_MAX_OUTSTANDING_CMDS	/* Per host adapter instance */
-#define SBP2_MAX_COMMAND_ORBS		SBP2SCSI_MAX_CMDS_PER_LUN * 2	/* Per sbp2 device instance */
+#define SBP2_MAX_REQUEST_PACKETS	(sbp2_max_outstanding_cmds * 2)
+#define SBP2_MAX_COMMAND_ORBS		(sbp2_max_cmds_per_lun * 2)
 
 /*
  * Request packets structure (used for sending command and agent reset packets)
@@ -306,21 +329,26 @@
 
 };
 
+
+/* This is the two dma types we use for cmd_dma below */
+#define CMD_DMA_NONE   0x0
+#define CMD_DMA_PAGE   0x1
+#define CMD_DMA_SINGLE 0x2
+
 /* 
  * Encapsulates all the info necessary for an outstanding command. 
  */
 struct sbp2_command_info {
 
 	struct list_head list;
-	struct sbp2_command_orb command_orb;
-	dma_addr_t command_orb_dma;
+	struct sbp2_command_orb command_orb ____cacheline_aligned;
+	dma_addr_t command_orb_dma ____cacheline_aligned;
 	Scsi_Cmnd *Current_SCpnt;
 	void (*Current_done)(Scsi_Cmnd *);
-	unsigned int linked;
 
 	/* Also need s/g structure for each sbp2 command */
-	struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS];
-	dma_addr_t sge_dma;
+	struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS] ____cacheline_aligned;
+	dma_addr_t sge_dma ____cacheline_aligned;
 	void *sge_buffer;
 	dma_addr_t cmd_dma;
 	int dma_type;
@@ -340,6 +368,7 @@
 	 * Various sbp2 specific structures
 	 */
 	struct sbp2_command_orb *last_orb;
+	dma_addr_t last_orb_dma;
 	struct sbp2_login_orb *login_orb;
 	dma_addr_t login_orb_dma;
 	struct sbp2_login_response *login_response;
@@ -422,7 +451,7 @@
 	 * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions)
 	 * are allocated at init and simply re-initialized when needed.
 	 */
-	struct sbp2_request_packet request_packet[SBP2_MAX_REQUEST_PACKETS];
+	struct sbp2_request_packet *request_packet;
 
 	/*
 	 * SCSI ID instance data (one for each sbp2 device instance possible)
@@ -441,7 +470,7 @@
 static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi);
 static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi);
 static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
-									  nodeid_t node, u64 addr,
+									  struct node_entry *ne, u64 addr,
 									  size_t data_size,
 									  quadlet_t data);
 static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet);
@@ -487,13 +516,12 @@
 				   unchar *scsi_cmd,
 				   unsigned int scsi_use_sg,
 				   unsigned int scsi_request_bufflen,
-				   void *scsi_request_buffer, int dma_dir);
+				   void *scsi_request_buffer, 
+				   unsigned char scsi_dir);
 static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
 				 struct sbp2_command_info *command);
 static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
 			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
-				   Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
 static void sbp2_check_sbp2_command(unchar *cmd);
 static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
@@ -506,10 +534,11 @@
  * Scsi interface related prototypes
  */
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
+static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags); 
+static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
 					   u32 status);
diff -urN linux-2.4.19-pre4/drivers/ieee1394/video1394.c linux-2.4.19-pre5/drivers/ieee1394/video1394.c
--- linux-2.4.19-pre4/drivers/ieee1394/video1394.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre5/drivers/ieee1394/video1394.c	Fri Mar 29 14:49:31 2002
@@ -18,6 +18,9 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/* jds -- add private data to file to keep track of iso contexts associated
+   with each open -- so release won't kill all iso transfers */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -31,19 +34,12 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
 #include <linux/proc_fs.h>
 #include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/devfs_fs_kernel.h>
 
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <asm/segment.h>
+#include <asm/bitops.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
@@ -59,7 +55,6 @@
 
 #include "ohci1394.h"
 
-#define VIDEO1394_MAJOR 172
 #define ISO_CHANNELS 64
 #define ISO_RECEIVE 0
 #define ISO_TRANSMIT 1
@@ -72,6 +67,14 @@
 #define vmalloc_32(x) vmalloc(x)
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3))
+#define remap_page_range_1394(vma, start, addr, size, prot) \
+	remap_page_range(start, addr, size, prot)
+#else
+#define remap_page_range_1394(vma, start, addr, size, prot) \
+	remap_page_range(vma, start, addr, size, prot)
+#endif
+
 struct it_dma_prg {
 	struct dma_cmd begin;
 	quadlet_t data[4];
@@ -81,6 +84,7 @@
 
 struct dma_iso_ctx {
 	struct ti_ohci *ohci;
+	int type; /* ISO_TRANSMIT or ISO_RECEIVE */
 	int ctx;
 	int channel;
 	int last_buffer;
@@ -108,6 +112,8 @@
 	spinlock_t lock;
 	unsigned int syt_offset;
 	int flags;
+
+	struct list_head link;
 };
 
 struct video_card {
@@ -115,9 +121,12 @@
 	struct list_head list;
 	int id;
 	devfs_handle_t devfs;
+};
 
-	struct dma_iso_ctx **ir_context;
-	struct dma_iso_ctx **it_context;
+
+struct file_ctx {
+	struct video_card *video;
+	struct list_head context_list;
 	struct dma_iso_ctx *current_ctx;
 };
 
@@ -145,7 +154,7 @@
 printk(level "video1394_%d: " fmt "\n" , card , ## args)
 
 static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-		 quadlet_t isoXmitIntEvent);
+			quadlet_t isoXmitIntEvent, void *data);
 
 static LIST_HEAD(video1394_cards);
 static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
@@ -153,8 +162,6 @@
 static devfs_handle_t devfs_handle;
 static struct hpsb_highlevel *hl_handle = NULL;
 
-static struct video_template video_tmpl = { irq_handler };
-
 /* Code taken from bttv.c */
 
 /*******************************/
@@ -277,56 +284,75 @@
 }
 /* End of code taken from bttv.c */
 
-static int free_dma_iso_ctx(struct dma_iso_ctx **d)
+static int free_dma_iso_ctx(struct dma_iso_ctx *d)
 {
 	int i;
-	struct ti_ohci *ohci;
+	unsigned long *usage;
 	
-	if ((*d)==NULL) return -1;
+	DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx);
 
-	ohci = (struct ti_ohci *)(*d)->ohci;
+	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
+	ohci1394_unhook_irq(d->ohci, irq_handler, d);
 
-	DBGMSG(ohci->id, "Freeing dma_iso_ctx %d", (*d)->ctx);
+	if (d->buf)
+		rvfree((void *)d->buf, d->num_desc * d->buf_size);
 
-	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
+	if (d->ir_prg) {
+		for (i=0;i<d->num_desc;i++) 
+			if (d->ir_prg[i]) kfree(d->ir_prg[i]);
+		kfree(d->ir_prg);
+	}
+
+	if (d->it_prg) {
+		for (i=0;i<d->num_desc;i++) 
+			if (d->it_prg[i]) kfree(d->it_prg[i]);
+		kfree(d->it_prg);
+	}
+
+	if (d->buffer_status)
+		kfree(d->buffer_status);
+	if (d->buffer_time)
+		kfree(d->buffer_time);
+	if (d->last_used_cmd)
+		kfree(d->last_used_cmd);
+	if (d->next_buffer)
+		kfree(d->next_buffer);
+
+	usage = (d->type == ISO_RECEIVE) ? &d->ohci->ir_ctx_usage :
+		&d->ohci->it_ctx_usage;
+       
+	/* clear the ISO context usage bit */
+	clear_bit(d->ctx, usage);
+	list_del(&d->link);
 
-	if ((*d)->buf) rvfree((void *)(*d)->buf, 
-			      (*d)->num_desc * (*d)->buf_size);
-
-	if ((*d)->ir_prg) {
-		for (i=0;i<(*d)->num_desc;i++) 
-			if ((*d)->ir_prg[i]) kfree((*d)->ir_prg[i]);
-		kfree((*d)->ir_prg);
-	}
-
-	if ((*d)->it_prg) {
-		for (i=0;i<(*d)->num_desc;i++) 
-			if ((*d)->it_prg[i]) kfree((*d)->it_prg[i]);
-		kfree((*d)->it_prg);
-	}
-
-	if ((*d)->buffer_status)
-		kfree((*d)->buffer_status);
-	if ((*d)->buffer_time)
-		kfree((*d)->buffer_time);
-	if ((*d)->last_used_cmd)
-		kfree((*d)->last_used_cmd);
-	if ((*d)->next_buffer)
-		kfree((*d)->next_buffer);
-
-	kfree(*d);
-	*d = NULL;
+	kfree(d);
 
 	return 0;
 }
 
 static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc,
+alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
 		  int buf_size, int channel, unsigned int packet_size)
 {
 	struct dma_iso_ctx *d=NULL;
 	int i;
 
+	unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
+		                                       &ohci->it_ctx_usage;
+
+	/* try to claim the ISO context usage bit */
+	for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) {
+		if (!test_and_set_bit(i, usage)) {
+			PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i);
+			break;
+		}
+	}
+
+	if (i == ohci->nb_iso_rcv_ctx) {
+		PRINT(KERN_ERR, ohci->id, "No DMA contexts available");
+		return NULL;
+	}
+	
 	d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), 
 					  GFP_KERNEL);
 	if (d==NULL) {
@@ -337,7 +363,8 @@
 	memset(d, 0, sizeof(struct dma_iso_ctx));
 
 	d->ohci = (void *)ohci;
-	d->ctx = ctx;
+	d->type = type;
+	d->ctx = i;
 	d->channel = channel;
 	d->num_desc = num_desc;
 	d->frame_size = buf_size;
@@ -350,11 +377,17 @@
 	d->ir_prg = NULL;
 	init_waitqueue_head(&d->waitq);
 
+	if (ohci1394_hook_irq(ohci, irq_handler, d) != 0) {
+		PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed");
+		free_dma_iso_ctx(d);
+		return NULL;
+	}
+
 	d->buf = rvmalloc(d->num_desc * d->buf_size);
 
 	if (d->buf == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	memset(d->buf, 0, d->num_desc * d->buf_size);
@@ -371,7 +404,7 @@
 		if (d->ir_prg == NULL) {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate dma ir prg");
-			free_dma_iso_ctx(&d);
+			free_dma_iso_ctx(d);
 			return NULL;
 		}
 		memset(d->ir_prg, 0, d->num_desc * sizeof(struct dma_cmd *));
@@ -387,7 +420,7 @@
 			if (d->ir_prg[i] == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Failed to allocate dma ir prg");
-				free_dma_iso_ctx(&d);
+				free_dma_iso_ctx(d);
 				return NULL;
 			}
 		}
@@ -403,7 +436,7 @@
 		if (d->it_prg == NULL) {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate dma it prg");
-			free_dma_iso_ctx(&d);
+			free_dma_iso_ctx(d);
 			return NULL;
 		}
 		memset(d->it_prg, 0, d->num_desc*sizeof(struct it_dma_prg *));
@@ -415,7 +448,7 @@
 			      "Packet size %d (page_size: %ld) "
 			      "not yet supported\n",
 			      packet_size, PAGE_SIZE);
-			free_dma_iso_ctx(&d);
+			free_dma_iso_ctx(d);
 			return NULL;
 		}
 
@@ -434,7 +467,7 @@
 			if (d->it_prg[i] == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Failed to allocate dma it prg");
-				free_dma_iso_ctx(&d);
+				free_dma_iso_ctx(d);
 				return NULL;
 			}
 		}
@@ -451,22 +484,22 @@
 
 	if (d->buffer_status == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_status");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	if (d->buffer_time == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_time");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	if (d->last_used_cmd == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	if (d->next_buffer == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate next_buffer");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
@@ -568,38 +601,19 @@
 }
 
 /* find which context is listening to this channel */
-int ir_ctx_listening(struct video_card *video, int channel)
-{
-	int i;
-	struct ti_ohci *ohci = video->ohci;
-
-	for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 
-		if (video->ir_context[i]) {
-			if (video->ir_context[i]->channel==channel)
-				return i;
-		}
-		
-	PRINT(KERN_ERR, ohci->id, "No iso context is listening to channel %d",
-	      channel);
-
-	return -1;
-}
-
-int it_ctx_talking(struct video_card *video, int channel)
+static struct dma_iso_ctx *
+find_ctx(struct list_head *list, int type, int channel)
 {
-	int i;
-	struct ti_ohci *ohci = video->ohci;
+	struct list_head *lh;
 
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 
-		if (video->it_context[i]) {
-			if (video->it_context[i]->channel==channel)
-				return i;
-		}
-		
-	PRINT(KERN_ERR, ohci->id, "No iso context is talking to channel %d",
-	      channel);
+	list_for_each(lh, list) {
+		struct dma_iso_ctx *ctx;
+		ctx = list_entry(lh, struct dma_iso_ctx, link);
+		if (ctx->type == type && ctx->channel == channel)
+			return ctx;
+	}
 
-	return -1;
+	return NULL;
 }
 
 int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) 
@@ -617,7 +631,11 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+			get_fast_time(&d->buffer_time[i]);
+#else
 			do_gettimeofday(&d->buffer_time[i]);
+#endif
 		}
 	}
 	spin_unlock(&d->lock);
@@ -822,13 +840,14 @@
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
 }
 
-static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, 
-		       const char *adr, unsigned long size)
+static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
+		       struct vm_area_struct *vma)
 {
-        unsigned long start=(unsigned long) adr;
-        unsigned long page,pos;
+        unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+        unsigned long page, pos;
 
-        if (size>d->num_desc * d->buf_size) {
+        if (size > d->num_desc * d->buf_size) {
 		PRINT(KERN_ERR, ohci->id, 
 		      "iso context %d buf size is different from mmap size", 
 		      d->ctx);
@@ -840,14 +859,14 @@
 		return -EINVAL;
 	}
 
-        pos=(unsigned long) d->buf;
+	pos = (unsigned long) d->buf;
         while (size > 0) {
                 page = kvirt_to_pa(pos);
-                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                         return -EAGAIN;
-                start+=PAGE_SIZE;
-                pos+=PAGE_SIZE;
-                size-=PAGE_SIZE;
+                start += PAGE_SIZE;
+                pos += PAGE_SIZE;
+                size -= PAGE_SIZE;
         }
         return 0;
 }
@@ -855,29 +874,10 @@
 static int video1394_ioctl(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg)
 {
-	struct video_card *video = NULL;
-	struct ti_ohci *ohci = NULL;
+	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+	struct video_card *video = ctx->video;
+	struct ti_ohci *ohci = video->ohci;
 	unsigned long flags;
-	struct list_head *lh;
-
-	spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == MINOR(inode->i_rdev)) {
-				video = p;
-				ohci = video->ohci;
-				break;
-			}
-		}
-	}
-	spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", MINOR(inode->i_rdev));
-		return -EFAULT;
-	}
 
 	switch(cmd)
 	{
@@ -886,6 +886,7 @@
 	{
 		struct video1394_mmap v;
 		u64 mask;
+		struct dma_iso_ctx *d;
 		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
@@ -897,7 +898,7 @@
 		    for (i=0; i<ISO_CHANNELS; i++) {
 			if (!(ohci->ISO_channel_usage & mask)) {
 			    v.channel = i;
-			    PRINT(KERN_INFO, ohci->id, "Found free channel %d\n", i);
+			    PRINT(KERN_INFO, ohci->id, "Found free channel %d", i);
 			    break;
 			}
 			mask = mask << 1;
@@ -920,7 +921,7 @@
 			return -EFAULT;
 		}
 		ohci->ISO_channel_usage |= mask;
-		
+
 		if (v.buf_size<=0) {
 			PRINT(KERN_ERR, ohci->id,
 			      "Invalid %d length buffer requested",v.buf_size);
@@ -941,67 +942,47 @@
 		}
 
 		if (cmd == VIDEO1394_LISTEN_CHANNEL) {
-			/* find a free iso receive context */
-			for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 
-				if (video->ir_context[i]==NULL) break;
-			    
-			if (i==(ohci->nb_iso_rcv_ctx-1)) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "No iso context available");
-				return -EFAULT;
-			}
+			d = alloc_dma_iso_ctx(ohci, ISO_RECEIVE,
+					      v.nb_buffers, v.buf_size, 
+					      v.channel, 0);
 
-			video->ir_context[i] = 
-				alloc_dma_iso_ctx(ohci, ISO_RECEIVE, i+1, 
-						  v.nb_buffers, v.buf_size, 
-						  v.channel, 0);
-
-			if (video->ir_context[i] == NULL) {
+			if (d == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Couldn't allocate ir context");
 				return -EFAULT;
 			}
-			initialize_dma_ir_ctx(video->ir_context[i], 
-					      v.sync_tag, v.flags);
+			initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
 
-			video->current_ctx = video->ir_context[i];
+			ctx->current_ctx = d;
 
-			v.buf_size = video->ir_context[i]->buf_size;
+			v.buf_size = d->buf_size;
+			list_add_tail(&d->link, &ctx->context_list);
 
 			PRINT(KERN_INFO, ohci->id, 
-			      "iso context %d listen on channel %d", i+1, 
-			      v.channel);
+			      "iso context %d listen on channel %d",
+			      d->ctx, v.channel);
 		}
 		else {
-			/* find a free iso transmit context */
-			for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 
-				if (video->it_context[i]==NULL) break;
-			    
-			if (i==ohci->nb_iso_xmit_ctx) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "No iso context available");
-				return -EFAULT;
-			}
-			
-			video->it_context[i] = 
-				alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, i, 
-						  v.nb_buffers, v.buf_size, 
-						  v.channel, v.packet_size);
+			d = alloc_dma_iso_ctx(ohci, ISO_TRANSMIT,
+					      v.nb_buffers, v.buf_size, 
+					      v.channel, v.packet_size);
 
-			if (video->it_context[i] == NULL) {
+			if (d == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Couldn't allocate it context");
 				return -EFAULT;
 			}
-			initialize_dma_it_ctx(video->it_context[i], 
-					      v.sync_tag, v.syt_offset, v.flags);
+			initialize_dma_it_ctx(d, v.sync_tag, 
+					      v.syt_offset, v.flags);
 
-			video->current_ctx = video->it_context[i];
+			ctx->current_ctx = d;
 
-			v.buf_size = video->it_context[i]->buf_size;
+			v.buf_size = d->buf_size;
+
+			list_add_tail(&d->link, &ctx->context_list);
 
 			PRINT(KERN_INFO, ohci->id, 
-			      "Iso context %d talk on channel %d", i, 
+			      "Iso context %d talk on channel %d", d->ctx,
 			      v.channel);
 		}
 
@@ -1015,7 +996,7 @@
 	{
 		int channel;
 		u64 mask;
-		int i;
+		struct dma_iso_ctx *d;
 
 		if(copy_from_user(&channel, (void *)arg, sizeof(int)))
 			return -EFAULT;
@@ -1031,28 +1012,19 @@
 			      "Channel %d is not being used", channel);
 			return -EFAULT;
 		}
-		ohci->ISO_channel_usage &= ~mask;
-
-		if (cmd == VIDEO1394_UNLISTEN_CHANNEL) {
-			i = ir_ctx_listening(video, channel);
-			if (i<0) return -EFAULT;
 
-			free_dma_iso_ctx(&video->ir_context[i]);
-
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso context %d stop listening on channel %d", 
-			      i+1, channel);
-		}
-		else {
-			i = it_ctx_talking(video, channel);
-			if (i<0) return -EFAULT;
+		/* Mark this channel as unused */
+		ohci->ISO_channel_usage &= ~mask;
 
-			free_dma_iso_ctx(&video->it_context[i]);
+		if (cmd == VIDEO1394_UNLISTEN_CHANNEL)
+			d = find_ctx(&ctx->context_list, ISO_RECEIVE, channel);
+		else
+			d = find_ctx(&ctx->context_list, ISO_TRANSMIT, channel);
 
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso context %d stop talking on channel %d", 
-			      i, channel);
-		}
+		if (d == NULL) return -EFAULT;
+		PRINT(KERN_INFO, ohci->id, "Iso context %d "
+		      "stop talking on channel %d", d->ctx, channel);
+		free_dma_iso_ctx(d);
 		
 		return 0;
 	}
@@ -1060,14 +1032,11 @@
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
-		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = ir_ctx_listening(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->ir_context[i];
+		d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1129,9 +1098,7 @@
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = ir_ctx_listening(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->ir_context[i];
+		d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1208,14 +1175,11 @@
 		struct video1394_wait v;
 		struct video1394_queue_variable qv;
 		struct dma_iso_ctx *d;
-		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = it_ctx_talking(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->it_context[i];
+		d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1300,14 +1264,11 @@
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
-		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		i = it_ctx_talking(video, v.channel);
-		if (i<0) return -EFAULT;
-		d = video->it_context[i];
+		d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1357,60 +1318,36 @@
 
 int video1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct video_card *video = NULL;
-	struct ti_ohci *ohci;
+	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+	struct video_card *video = ctx->video;
+	struct ti_ohci *ohci = video->ohci;
 	int res = -EINVAL;
-	unsigned long flags;
-	struct list_head *lh;
-
-        spin_lock_irqsave(&video1394_cards_lock, flags);
-        if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == MINOR(file->f_dentry->d_inode->i_rdev)) {
-				video = p;
-				break;
-			}
-                }
-        }
-        spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d",
-			MINOR(file->f_dentry->d_inode->i_rdev));
-		return -EFAULT;
-	}
 
 	lock_kernel();
 	ohci = video->ohci;
 
-	if (video->current_ctx == NULL) {
+	if (ctx->current_ctx == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Current iso context not set");
 	} else
-		res = do_iso_mmap(ohci, video->current_ctx, 
-			   (char *)vma->vm_start, 
-			   (unsigned long)(vma->vm_end-vma->vm_start));
+		res = do_iso_mmap(ohci, ctx->current_ctx, vma);
 	unlock_kernel();
 	return res;
 }
 
 static int video1394_open(struct inode *inode, struct file *file)
 {
-	int i = MINOR(inode->i_rdev);
+	int i = ieee1394_file_to_instance(file);
 	unsigned long flags;
 	struct video_card *video = NULL;
 	struct list_head *lh;
+	struct file_ctx *ctx;
 
 	spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == i) {
-				video = p;
-				break;
-			}
+	list_for_each(lh, &video1394_cards) {
+		struct video_card *p = list_entry(lh, struct video_card, list);
+		if (p->id == i) {
+			video = p;
+			break;
 		}
 	}
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
@@ -1418,124 +1355,71 @@
         if (video == NULL)
                 return -EIO;
 
-	V22_COMPAT_MOD_INC_USE_COUNT;
+	ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL);
+	if (ctx == NULL)  {
+		PRINT(KERN_ERR, video->ohci->id, "Cannot malloc file_ctx");
+		return -ENOMEM;
+	}
+
+	memset(ctx, 0, sizeof(struct file_ctx));
+	ctx->video = video;
+	INIT_LIST_HEAD(&ctx->context_list);
+	ctx->current_ctx = NULL;
+	file->private_data = ctx;
 
 	return 0;
 }
 
 static int video1394_release(struct inode *inode, struct file *file)
 {
-	struct video_card *video = NULL;
-	struct ti_ohci *ohci;
+	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+	struct video_card *video = ctx->video;
+	struct ti_ohci *ohci = video->ohci;
+	struct list_head *lh, *next;
 	u64 mask;
-	int i;
-	unsigned long flags;
-	struct list_head *lh;
-
-        spin_lock_irqsave(&video1394_cards_lock, flags);
-        if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == MINOR(inode->i_rdev)) {
-				video = p;
-				break;
-			}
-		}
-	}
-        spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown device for minor %d",
-				MINOR(inode->i_rdev));
-		return 1;
+	lock_kernel();
+	list_for_each_safe(lh, next, &ctx->context_list) {
+		struct dma_iso_ctx *d;
+		d = list_entry(lh, struct dma_iso_ctx, link);
+		mask = (u64) 1 << d->channel;
+		
+		if (!(ohci->ISO_channel_usage & mask))
+			PRINT(KERN_ERR, ohci->id, "On release: Channel %d "
+			      "is not being used", d->channel);
+		else
+			ohci->ISO_channel_usage &= ~mask;
+		PRINT(KERN_INFO, ohci->id, "On release: Iso %s context "
+		      "%d stop listening on channel %d",
+		      d->type == ISO_RECEIVE ? "receive" : "transmit",
+		      d->ctx, d->channel);
+		free_dma_iso_ctx(d);
 	}
 
-	ohci = video->ohci;
-
-	lock_kernel();
-	for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 
-		if (video->ir_context[i]) {
-			mask = (u64)0x1<<video->ir_context[i]->channel;
-			if (!(ohci->ISO_channel_usage & mask))
-				PRINT(KERN_ERR, ohci->id, 
-				      "Channel %d is not being used", 
-				      video->ir_context[i]->channel);
-			else
-				ohci->ISO_channel_usage &= ~mask;
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso receive context %d stop listening "
-			      "on channel %d", i+1, 
-			      video->ir_context[i]->channel);
-			free_dma_iso_ctx(&video->ir_context[i]);
-		}
+	kfree(ctx);
+	file->private_data = NULL;
 	
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 
-		if (video->it_context[i]) {
-			mask = (u64)0x1<<video->it_context[i]->channel;
-			if (!(ohci->ISO_channel_usage & mask))
-				PRINT(KERN_ERR, ohci->id, 
-				      "Channel %d is not being used", 
-				      video->it_context[i]->channel);
-			else
-				ohci->ISO_channel_usage &= ~mask;
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso transmit context %d stop talking "
-			      "on channel %d", i+1, 
-			      video->it_context[i]->channel);
-			free_dma_iso_ctx(&video->it_context[i]);
-		}
-
-	V22_COMPAT_MOD_DEC_USE_COUNT;
-
 	unlock_kernel();
 	return 0;
 }
 
 static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-		 quadlet_t isoXmitIntEvent)
+			quadlet_t isoXmitIntEvent, void *data)
 {
-	int i;
-	unsigned long flags;
-	struct video_card *video = NULL;
-	struct list_head *lh;
+	struct dma_iso_ctx *d = (struct dma_iso_ctx *) data;
 
-	spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == card) {
-				video = p;
-				break;
-			}
-                }
-        }
-        spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, __FUNCTION__": Unknown card number %d!!",
-				card);
-		return;
-	}
-	
 	DBGMSG(card, "Iso event Recv: %08x Xmit: %08x",
 	       isoRecvIntEvent, isoXmitIntEvent);
 
-	for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++)
-		if (isoRecvIntEvent & (1<<(i+1))) 
-			wakeup_dma_ir_ctx(video->ohci,
-					  video->ir_context[i]);
-
-	for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++)
-		if (isoXmitIntEvent & (1<<i)) 
-			wakeup_dma_it_ctx(video->ohci,
-					  video->it_context[i]);
+	if (d->type == ISO_RECEIVE && isoRecvIntEvent & (1 << d->ctx))
+		wakeup_dma_ir_ctx(d->ohci, d);
+	if (d->type == ISO_TRANSMIT && isoXmitIntEvent & (1 << d->ctx))
+		wakeup_dma_it_ctx(d->ohci, d);
 }
 
 static struct file_operations video1394_fops=
 {
-        OWNER_THIS_MODULE
+	owner:		THIS_MODULE,
 	ioctl:		video1394_ioctl,
 	mmap:		video1394_mmap,
 	open:		video1394_open,
@@ -1544,10 +1428,12 @@
 
 static int video1394_init(struct ti_ohci *ohci)
 {
-	struct video_card *video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
+	struct video_card *video;
 	unsigned long flags;
 	char name[16];
+	int minor;
 
+	video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
 	if (video == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Cannot allocate video_card");
 		return -1;
@@ -1560,42 +1446,14 @@
 	list_add_tail(&video->list, &video1394_cards);
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
-	if (ohci1394_register_video(ohci, &video_tmpl)<0) {
-		PRINT(KERN_ERR, ohci->id, "Register_video failed");
-		return -1;
-	}
-
 	video->id = ohci->id;
 	video->ohci = ohci;
 
-	/* Iso receive dma contexts */
-	video->ir_context = (struct dma_iso_ctx **)
-		kmalloc((ohci->nb_iso_rcv_ctx-1)*
-			sizeof(struct dma_iso_ctx *), GFP_KERNEL);
-	if (video->ir_context) 
-		memset(video->ir_context, 0,
-		       (ohci->nb_iso_rcv_ctx-1)*sizeof(struct dma_iso_ctx *));
-	else {
-		PRINT(KERN_ERR, ohci->id, "Cannot allocate ir_context");
-		return -1;
-	}
-
-	/* Iso transmit dma contexts */
-	video->it_context = (struct dma_iso_ctx **)
-		kmalloc(ohci->nb_iso_xmit_ctx *
-			sizeof(struct dma_iso_ctx *), GFP_KERNEL);
-	if (video->it_context) 
-		memset(video->it_context, 0,
-		       ohci->nb_iso_xmit_ctx * sizeof(struct dma_iso_ctx *));
-	else {
-		PRINT(KERN_ERR, ohci->id, "Cannot allocate it_context");
-		return -1;
-	}
-
 	sprintf(name, "%d", video->id);
+	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + video->id;
 	video->devfs = devfs_register(devfs_handle, name,
 				      DEVFS_FL_AUTO_OWNER,
-				      VIDEO1394_MAJOR, 0,
+				      IEEE1394_MAJOR, minor,
 				      S_IFCHR | S_IRUSR | S_IWUSR,
 				      &video1394_fops, NULL);
 
@@ -1605,27 +1463,7 @@
 /* Must be called under spinlock */
 static void remove_card(struct video_card *video)
 {
-	int i;
-
-	ohci1394_unregister_video(video->ohci, &video_tmpl);
-
 	devfs_unregister(video->devfs);
-
-	/* Free the iso receive contexts */
-	if (video->ir_context) {
-		for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++) {
-			free_dma_iso_ctx(&video->ir_context[i]);
-		}
-		kfree(video->ir_context);
-	}
-
-	/* Free the iso transmit contexts */
-	if (video->it_context) {
-		for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++) {
-			free_dma_iso_ctx(&video->it_context[i]);
-		}
-		kfree(video->it_context);
-	}
 	list_del(&video->list);
 
 	kfree(video);
@@ -1639,7 +1477,7 @@
 	struct video_card *p;
 
 	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
 		return;
 
 	ohci = (struct ti_ohci *)host->hostdata;
@@ -1662,7 +1500,7 @@
 	struct ti_ohci *ohci;
 
 	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->template->name, OHCI1394_DRIVER_NAME))
+	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
 		return;
 
 	ohci = (struct ti_ohci *)host->hostdata;
@@ -1687,19 +1525,19 @@
 	hpsb_unregister_highlevel (hl_handle);
 
 	devfs_unregister(devfs_handle);
-	devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
-
+	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
+	
 	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
 }
 
 static int __init video1394_init_module (void)
 {
-	if (devfs_register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME,
-				&video1394_fops)) {
-		PRINT_G(KERN_ERR, "video1394: unable to get major %d\n",
-				VIDEO1394_MAJOR);
-		return -EIO;
-	}
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
+				      THIS_MODULE, &video1394_fops)) {
+		PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
+ 		return -EIO;
+ 	}
+	
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
 			strlen(VIDEO1394_DRIVER_NAME), NULL);
@@ -1711,7 +1549,7 @@
 	if (hl_handle == NULL) {
 		PRINT_G(KERN_ERR, "No more memory for driver\n");
 		devfs_unregister(devfs_handle);
-		devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
 		return -ENOMEM;
 	}
 
diff -urN linux-2.4.19-pre4/drivers/media/video/stradis.c linux-2.4.19-pre5/drivers/media/video/stradis.c
--- linux-2.4.19-pre4/drivers/media/video/stradis.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/media/video/stradis.c	Fri Mar 29 14:49:33 2002
@@ -1972,7 +1972,9 @@
 {
 	struct saa7146 *saa = (struct saa7146 *) dev;
 
-	saa->video_dev.busy = 0;
+	/* FIXME: Don't do it this way, use the video_device->fops
+	 * registration for a sane implementation of multiple opens */
+	saa->video_dev.users--;
 	saa->user++;
 	if (saa->user > 1)
 		return 0;	/* device open already, don't reset */
@@ -1984,7 +1986,7 @@
 {
 	struct saa7146 *saa = (struct saa7146 *) dev;
 	saa->user--;
-	saa->video_dev.busy = 0;
+	saa->video_dev.users++;
 	if (saa->user > 0)	/* still someone using device */
 		return;
 	saawrite(0x007f0000, SAA7146_MC1);	/* stop all overlay dma */
diff -urN linux-2.4.19-pre4/drivers/media/video/zr36067.c linux-2.4.19-pre5/drivers/media/video/zr36067.c
--- linux-2.4.19-pre4/drivers/media/video/zr36067.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre5/drivers/media/video/zr36067.c	Fri Mar 29 14:49:33 2002
@@ -3265,7 +3265,10 @@
 
 			btwrite(IRQ_MASK, ZR36057_ISR);	// Clears interrupts
 			btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
-			dev->busy = 0;	/* Allow second open */
+			/* FIXME: Don't do it this way, use the
+			 * video_device->fops registration for a sane
+			 * implementation of multiple opens */
+			dev->users--;	/* Allow second open */
 		}
 
 		break;
@@ -3323,6 +3326,7 @@
 		}
 	}
 
+	dev->users++;
 	zr->user--;
 
 	MOD_DEC_USE_COUNT;
@@ -4205,9 +4209,7 @@
 
 			/* sleep 1 second */
 
-			timeout = jiffies + 1 * HZ;
-			while (jiffies < timeout)
-				schedule();
+			schedule_timeout(HZ);
 
 			/* Get status of video decoder */
 
@@ -4397,22 +4399,18 @@
 }
 
 static struct video_device zoran_template = {
-	THIS_MODULE,
-	ZORAN_NAME,
-	VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
-	    VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
-	ZORAN_HARDWARE,
-	zoran_open,
-	zoran_close,
-	zoran_read,
-	zoran_write,
-	NULL,
-	zoran_ioctl,
-	zoran_mmap,
-	zoran_init_done,
-	NULL,
-	0,
-	0
+	owner:		THIS_MODULE,
+	name:		ZORAN_NAME,
+	type:		VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
+			VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
+	hardware:	ZORAN_HARDWARE,
+	open:		zoran_open,
+	close:		zoran_close,
+	read:		zoran_read,
+	write:		zoran_write,
+	ioctl:		zoran_ioctl,
+	mmap:		zoran_mmap,
+	initialize:	zoran_init_done,
 };
 
 /*
diff -urN linux-2.4.19-pre4/drivers/message/fusion/Config.in linux-2.4.19-pre5/drivers/message/fusion/Config.in
--- linux-2.4.19-pre4/drivers/message/fusion/Config.in	Fri Jul  6 17:03:11 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/Config.in	Fri Mar 29 14:49:33 2002
@@ -7,10 +7,8 @@
 
   if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
     define_bool CONFIG_FUSION_BOOT y
-    comment "(ability to boot linux kernel from Fusion device is ENABLED!)"
   else
     define_bool CONFIG_FUSION_BOOT n
-    comment "(ability to boot linux kernel from Fusion device is DISABLED!)"
   fi
 
   if [ "$CONFIG_MODULES" = "y" ]; then
diff -urN linux-2.4.19-pre4/drivers/message/fusion/Makefile linux-2.4.19-pre5/drivers/message/fusion/Makefile
--- linux-2.4.19-pre4/drivers/message/fusion/Makefile	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/Makefile	Fri Mar 29 14:49:33 2002
@@ -27,6 +27,7 @@
 #EXTRA_CFLAGS += -DDEBUG
 #EXTRA_CFLAGS += -DMPT_DEBUG
 #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
+#EXTRA_CFLAGS += -DMPT_DEBUG_SG
 #
 # driver/module specifics...
 #
@@ -34,11 +35,13 @@
 #CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
 #CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
 #
-#  For {mptscsih, mptctl}:
+#  For mptscsih:
 #CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH
 #CFLAGS_mptscsih.o += -DMPT_DEBUG_SCANDV
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG
-#CFLAGS_mptctl.o += -DMPT_DEBUG_SG
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_RESET
+#
+#  For mptctl:
+#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
 #
 #  For mptlan:
 #CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG
diff -urN linux-2.4.19-pre4/drivers/message/fusion/isense.c linux-2.4.19-pre5/drivers/message/fusion/isense.c
--- linux-2.4.19-pre4/drivers/message/fusion/isense.c	Thu Oct 11 09:14:32 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/isense.c	Fri Mar 29 14:49:33 2002
@@ -5,12 +5,13 @@
  *      Error Report logging output.  This module implements SCSI-3
  *      Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings.
  *
- *  Copyright (c) 1991-2001 Steven J. Ralston
+ *  Copyright (c) 1991-2002 Steven J. Ralston
  *  Written By: Steven J. Ralston
  *  (yes I wrote some of the orig. code back in 1991!)
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: isense.c,v 1.28.14.1 2001/08/24 20:07:04 sralston Exp $
+ *  $Id: isense.c,v 1.33 2002/02/27 18:44:19 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -49,11 +50,15 @@
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/module.h>
+#include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/version.h>
+#include <asm/io.h>
+#if defined (__sparc__)
+#include <linux/timer.h>
+#endif
 
 /* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -61,7 +66,7 @@
 #endif
 
 #define MODULEAUTHOR "Steven J. Ralston"
-#define COPYRIGHT "Copyright (c) 2001 " MODULEAUTHOR
+#define COPYRIGHT "Copyright (c) 2001-2002 " MODULEAUTHOR
 #include "mptbase.h"
 
 #include "isense.h"
@@ -87,7 +92,6 @@
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
-MODULE_LICENSE("GPL");
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 int __init isense_init(void)
diff -urN linux-2.4.19-pre4/drivers/message/fusion/linux_compat.h linux-2.4.19-pre5/drivers/message/fusion/linux_compat.h
--- linux-2.4.19-pre4/drivers/message/fusion/linux_compat.h	Fri Jul  6 17:03:11 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/linux_compat.h	Fri Mar 29 14:49:33 2002
@@ -11,6 +11,10 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+#ifndef rwlock_init
+#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #	if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
 		typedef unsigned int dma_addr_t;
@@ -58,12 +62,33 @@
 	extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
 	{ return x; }
 
-#else 
+#else
 #define module_init(x)	__initcall(x);
 #define module_exit(x)	__exitcall(x);
 #endif
 /* } block snipped from lk-2.2.18/include/linux/init.h */
 
+/* This block snipped from lk-2.2.18/include/linux/sched.h { */
+/*
+ * Used prior to schedule_timeout calls..
+ */
+#define __set_current_state(state_value)	do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value)		do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value)		__set_current_state(state_value)
+#endif
+/* } block snipped from lk-2.2.18/include/linux/sched.h */
+
+/* procfs compat stuff... */
+#define proc_mkdir(x,y)			create_proc_entry(x, S_IFDIR, y)
+
+/* MUTEX compat stuff... */
+#define DECLARE_MUTEX(name)		struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)	struct semaphore name=MUTEX_LOCKED
+#define init_MUTEX(x)			*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)		*(x)=MUTEX_LOCKED
+
 /* Wait queues. */
 #define DECLARE_WAIT_QUEUE_HEAD(name)	\
 	struct wait_queue * (name) = NULL
@@ -90,6 +115,17 @@
 #endif		/* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
 
 
+/*
+ * Inclined to use:
+ *   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+ * here, but MODULE_LICENSE defined in 2.4.9-6 and 2.4.9-13
+ * breaks the rule:-(
+ */
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(license)
+#endif
+
+
 /* PCI/driver subsystem { */
 #ifndef pci_for_each_dev
 #define pci_for_each_dev(dev)		for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next)
@@ -120,26 +156,6 @@
 #endif		/* } ifndef pci_for_each_dev */
 
 
-/* procfs compat stuff... */
-#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
-#define CREATE_PROCDIR_ENTRY(x,y)  create_proc_entry(x, S_IFDIR, y)
-/* This is a macro so we don't need to pull all the procfs
- * headers into this file. -DaveM
- */
-#define create_proc_read_entry(name, mode, base, __read_proc, __data) \
-({      struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \
-        if (__res) { \
-                __res->read_proc=(__read_proc); \
-                __res->data=(__data); \
-        } \
-        __res; \
-})
-#else
-#define CREATE_PROCDIR_ENTRY(x,y)  proc_mkdir(x, y)
-#endif
-#endif
-
 /* Compatability for the 2.3.x PCI DMA API. */
 #ifndef PCI_DMA_BIDIRECTIONAL
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -194,6 +210,7 @@
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* PCI_DMA_BIDIRECTIONAL */
 
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
 
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/fc_log.h linux-2.4.19-pre5/drivers/message/fusion/lsi/fc_log.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/fc_log.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/fc_log.h	Fri Mar 29 14:49:33 2002
@@ -7,7 +7,7 @@
  *                  in the IOCLogInfo field of a MPI Default Reply Message.
  *
  *  CREATION DATE:  6/02/2000
- *  ID:             $Id: fc_log.h,v 4.5 2001/06/07 19:18:00 sschremm Exp $
+ *  ID:             $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $
  */
 
 
@@ -62,7 +62,7 @@
     MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP     = 0x2100000a, /* Manual Response not sent due to a LIP */
     MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3             = 0x2100000b, /* not sent because remote node does not support Class 3 */
     MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID        = 0x2100000c, /* not sent because login to remote node not validated */
-    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound after a logout */
+    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound queue after a logout */
     MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN    = 0x2100000f, /* cleared waiting for data after a logout */
 
     MPI_IOCLOGINFO_FC_LAN_BASE                      = 0x22000000,
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi.h	Fri Mar 29 14:49:33 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.01.07
+ *    MPI Version:  01.02.03
  *
  *  Version History
  *  ---------------
@@ -39,6 +39,11 @@
  *                      Added function codes for RAID.
  *  04-09-01  01.01.07  Added alternate define for MPI_DOORBELL_ACTIVE,
  *                      MPI_DOORBELL_USED, to better match the spec.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Changed MPI_VERSION_MINOR from 0x01 to 0x02.
+ *                      Added define MPI_FUNCTION_TOOLBOX.
+ *  09-28-01  01.02.02  New function code MPI_SCSI_ENCLOSURE_PROCESSOR.
+ *  11-01-01  01.02.03  Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR.
  *  --------------------------------------------------------------------------
  */
 
@@ -53,7 +58,7 @@
 *****************************************************************************/
 
 #define MPI_VERSION_MAJOR                   (0x01)
-#define MPI_VERSION_MINOR                   (0x01)
+#define MPI_VERSION_MINOR                   (0x02)
 #define MPI_VERSION            ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
 
 /* Note: The major versions of 0xe0 through 0xff are reserved */
@@ -216,9 +221,13 @@
 #define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND       (0x13)
 #define MPI_FUNCTION_FC_PRIMITIVE_SEND              (0x14)
 
-#define MPI_FUNCTION_RAID_VOLUME                    (0x15)
+#define MPI_FUNCTION_RAID_ACTION                    (0x15)
 #define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH       (0x16)
 
+#define MPI_FUNCTION_TOOLBOX                        (0x17)
+
+#define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR       (0x18)
+
 #define MPI_FUNCTION_LAN_SEND                       (0x20)
 #define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
 #define MPI_FUNCTION_LAN_RESET                      (0x22)
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_cnfg.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_cnfg.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_cnfg.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_cnfg.h	Fri Mar 29 14:49:33 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.01.11
+ *    MPI Version:  01.02.05
  *
  *  Version History
  *  ---------------
@@ -72,6 +72,42 @@
  *                      Added IO Unit Page 3.
  *                      Modified defines for Scsi Port Page 2.
  *                      Modified RAID Volume Pages.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Added SepID and SepBus to RVP2 IMPhysicalDisk struct.
+ *                      Added defines for the SEP bits in RVP2 VolumeSettings.
+ *                      Modified the DeviceSettings field in RVP2 to use the
+ *                      proper structure.
+ *                      Added defines for SES, SAF-TE, and cross channel for
+ *                      IOCPage2 CapabilitiesFlags.
+ *                      Removed define for MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE.
+ *                      Removed define for
+ *                      MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE.
+ *                      Added define for MPI_CONFIG_PAGEATTR_RO_PERSISTENT.
+ *  08-29-01 01.02.02   Fixed value for MPI_MANUFACTPAGE_DEVID_53C1035.
+ *                      Added defines for MPI_FCPORTPAGE1_FLAGS_HARD_ALPA_ONLY
+ *                      and MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY.
+ *                      Removed MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS,
+ *                      MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED.
+ *                      Added defines for MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED
+ *                      and MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED.
+ *                      Added OnBusTimerValue to CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added rejected bits to SCSI Device Page 0 Information.
+ *                      Increased size of ALPA array in FC Port Page 2 by one
+ *                      and removed a one byte reserved field.
+ *  09-28-01 01.02.03   Swapped NegWireSpeedLow and NegWireSpeedLow in
+ *                      CONFIG_PAGE_LAN_1 to match preferred 64-bit ordering.
+ *                      Added structures for Manufacturing Page 4, IO Unit
+ *                      Page 3, IOC Page 3, IOC Page 4, RAID Volume Page 0, and
+ *                      RAID PhysDisk Page 0.
+ *  10-04-01 01.02.04   Added define for MPI_CONFIG_PAGETYPE_RAID_PHYSDISK.
+ *                      Modified some of the new defines to make them 32
+ *                      character unique.
+ *                      Modified how variable length pages (arrays) are defined.
+ *                      Added generic defines for hot spare pools and RAID
+ *                      volume types.
+ *  11-01-01 01.02.05   Added define for MPI_IOUNITPAGE1_DISABLE_IR.
  *  --------------------------------------------------------------------------
  */
 
@@ -104,12 +140,13 @@
   fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
 
 
-/****************************************************************************/
-/*  PageType field values                                                   */
-/****************************************************************************/
+/****************************************************************************
+*   PageType field values
+****************************************************************************/
 #define MPI_CONFIG_PAGEATTR_READ_ONLY               (0x00)
 #define MPI_CONFIG_PAGEATTR_CHANGEABLE              (0x10)
 #define MPI_CONFIG_PAGEATTR_PERSISTENT              (0x20)
+#define MPI_CONFIG_PAGEATTR_RO_PERSISTENT           (0x30)
 #define MPI_CONFIG_PAGEATTR_MASK                    (0xF0)
 
 #define MPI_CONFIG_PAGETYPE_IO_UNIT                 (0x00)
@@ -122,29 +159,21 @@
 #define MPI_CONFIG_PAGETYPE_LAN                     (0x07)
 #define MPI_CONFIG_PAGETYPE_RAID_VOLUME             (0x08)
 #define MPI_CONFIG_PAGETYPE_MANUFACTURING           (0x09)
+#define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK           (0x0A)
 #define MPI_CONFIG_PAGETYPE_MASK                    (0x0F)
 
 #define MPI_CONFIG_TYPENUM_MASK                     (0x0FFF)
 
 
 /****************************************************************************
- *  PageAddres field values
- ****************************************************************************/
+*   PageAddress field values
+****************************************************************************/
 #define MPI_SCSI_PORT_PGAD_PORT_MASK                (0x000000FF)
 
-#define MPI_SCSI_DEVICE_FORM_MASK                   (0xF0000000)
-#define MPI_SCSI_DEVICE_FORM_TARGETID               (0x00000000)
-#define MPI_SCSI_DEVICE_FORM_RAID_PHYS_DEV_NUM      (0x10000000)
 #define MPI_SCSI_DEVICE_TARGET_ID_MASK              (0x000000FF)
 #define MPI_SCSI_DEVICE_TARGET_ID_SHIFT             (0)
 #define MPI_SCSI_DEVICE_BUS_MASK                    (0x0000FF00)
 #define MPI_SCSI_DEVICE_BUS_SHIFT                   (8)
-#define MPI_SCSI_DEVICE_VOLUME_TARG_ID_MASK         (0x000000FF)
-#define MPI_SCSI_DEVICE_VOLUME_TARG_ID_SHIFT        (0)
-#define MPI_SCSI_DEVICE_VOLUME_BUS_MASK             (0x0000FF00)
-#define MPI_SCSI_DEVICE_VOLUME_BUS_SHIFT            (8)
-#define MPI_SCSI_DEVICE_PHYS_DISK_NUM_MASK          (0x00FF0000)
-#define MPI_SCSI_DEVICE_PHYS_DISK_NUM_SHIFT         (16)
 
 #define MPI_FC_PORT_PGAD_PORT_MASK                  (0xF0000000)
 #define MPI_FC_PORT_PGAD_PORT_SHIFT                 (28)
@@ -167,10 +196,14 @@
 #define MPI_FC_DEVICE_PGAD_BT_TID_MASK              (0x000000FF)
 #define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT             (0)
 
+#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK          (0x000000FF)
+#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT         (0)
+
 
-/****************************************************************************/
-/*  Config Request Message                                                          */
-/****************************************************************************/
+
+/****************************************************************************
+*   Config Request Message
+****************************************************************************/
 typedef struct _MSG_CONFIG
 {
     U8                      Action;                     /* 00h */
@@ -181,16 +214,16 @@
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
     U8                      Reserved2[8];               /* 0Ch */
-   fCONFIG_PAGE_HEADER      Header;                     /* 14h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 14h */
     U32                     PageAddress;                /* 18h */
     SGE_IO_UNION            PageBufferSGE;              /* 1Ch */
 } MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG,
   Config_t, MPI_POINTER pConfig_t;
 
 
-/****************************************************************************/
-/*  Action field values                                                     */
-/****************************************************************************/
+/****************************************************************************
+*   Action field values
+****************************************************************************/
 #define MPI_CONFIG_ACTION_PAGE_HEADER               (0x00)
 #define MPI_CONFIG_ACTION_PAGE_READ_CURRENT         (0x01)
 #define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT        (0x02)
@@ -213,7 +246,7 @@
     U8                      Reserved2[2];               /* 0Ch */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
-   fCONFIG_PAGE_HEADER      Header;                     /* 14h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 14h */
 } MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY,
   ConfigReply_t, MPI_POINTER pConfigReply_t;
 
@@ -225,19 +258,24 @@
 *
 *****************************************************************************/
 
-/****************************************************************************/
-/*  Manufacturing Config pages                                              */
-/****************************************************************************/
+/****************************************************************************
+*   Manufacturing Config pages
+****************************************************************************/
 #define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919X            (0x0628)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
-#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0035)
+#define MPI_MANUFACTPAGE_DEVID_1030_53C1035         (0x0032)
+#define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035       (0x0033)
+#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0040)
+#define MPI_MANUFACTPAGE_DEVID_53C1035ZC            (0x0041)
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U8                      ChipName[16];               /* 04h */
     U8                      ChipRevision[8];            /* 14h */
     U8                      BoardName[16];              /* 1Ch */
@@ -252,7 +290,7 @@
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U8                      VPD[256];                   /* 04h */
 } fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1,
   ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t;
@@ -269,35 +307,72 @@
   MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t;
 
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_MAN_PAGE_2_HW_SETTINGS_WORDS
+#define MPI_MAN_PAGE_2_HW_SETTINGS_WORDS    (1)
+#endif
+
 typedef struct _CONFIG_PAGE_MANUFACTURING_2
 {
-   fCONFIG_PAGE_HEADER                  Header;         /* 00h */
-    MPI_CHIP_REVISION_ID                ChipId;         /* 04h */
-    U32                                 HwSettings[1];  /* 08h */
+    fCONFIG_PAGE_HEADER      Header;                                 /* 00h */
+    MPI_CHIP_REVISION_ID    ChipId;                                 /* 04h */
+    U32                     HwSettings[MPI_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 08h */
 } fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2,
   ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t;
 
 #define MPI_MANUFACTURING2_PAGEVERSION                  (0x00)
 
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_MAN_PAGE_3_INFO_WORDS
+#define MPI_MAN_PAGE_3_INFO_WORDS           (1)
+#endif
+
 typedef struct _CONFIG_PAGE_MANUFACTURING_3
 {
-   fCONFIG_PAGE_HEADER                  Header;         /* 00h */
-    MPI_CHIP_REVISION_ID                ChipId;         /* 04h */
-    U32                                 Info[1];        /* 08h */
+    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
+    MPI_CHIP_REVISION_ID                ChipId;                     /* 04h */
+    U32                                 Info[MPI_MAN_PAGE_3_INFO_WORDS];/* 08h */
 } fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3,
   ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t;
 
 #define MPI_MANUFACTURING3_PAGEVERSION                  (0x00)
 
 
-/****************************************************************************/
-/*  IO Unit Config Pages                                                    */
-/****************************************************************************/
+typedef struct _CONFIG_PAGE_MANUFACTURING_4
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U32                             Reserved1;          /* 04h */
+    U8                              InfoOffset0;        /* 08h */
+    U8                              InfoSize0;          /* 09h */
+    U8                              InfoOffset1;        /* 0Ah */
+    U8                              InfoSize1;          /* 0Bh */
+    U8                              InquirySize;        /* 0Ch */
+    U8                              Reserved2;          /* 0Dh */
+    U16                             Reserved3;          /* 0Eh */
+    U8                              InquiryData[56];    /* 10h */
+    U32                             ISVolumeSettings;   /* 48h */
+    U32                             IMEVolumeSettings;  /* 4Ch */
+    U32                             IMVolumeSettings;   /* 50h */
+} fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
+  ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
+
+#define MPI_MANUFACTURING4_PAGEVERSION                  (0x00)
+
+
+/****************************************************************************
+*   IO Unit Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_IO_UNIT_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U64                     UniqueValue;                /* 04h */
 } fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0,
   IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t;
@@ -307,18 +382,20 @@
 
 typedef struct _CONFIG_PAGE_IO_UNIT_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
 } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
   IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
 
 #define MPI_IOUNITPAGE1_PAGEVERSION                     (0x00)
 
+/* IO Unit Page 1 Flags defines */
+
 #define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
 #define MPI_IOUNITPAGE1_SINGLE_FUNCTION                 (0x00000001)
 #define MPI_IOUNITPAGE1_MULTI_PATHING                   (0x00000002)
 #define MPI_IOUNITPAGE1_SINGLE_PATHING                  (0x00000000)
-
+#define MPI_IOUNITPAGE1_DISABLE_IR                      (0x00000040)
 #define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
 
 
@@ -335,7 +412,7 @@
 
 typedef struct _CONFIG_PAGE_IO_UNIT_2
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U32                     BiosVersion;                /* 08h */
     MPI_ADAPTER_INFO        AdapterOrder[4];            /* 0Ch */
@@ -344,38 +421,45 @@
 
 #define MPI_IOUNITPAGE2_PAGEVERSION                     (0x00)
 
-#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE              (0x00000001)
 #define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR            (0x00000002)
 #define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE            (0x00000004)
 #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE       (0x00000008)
 #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40          (0x00000010)
 
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX
+#define MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX     (1)
+#endif
+
 typedef struct _CONFIG_PAGE_IO_UNIT_3
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
-    U32                     VolumeSettings;             /* 04h */
-    U8                      InfoOffset0;                /* 08h */
-    U8                      InfoSize0;                  /* 09h */
-    U8                      InfoOffset1;                /* 0Ah */
-    U8                      InfoSize1;                  /* 0Bh */
-    U8                      InquirySize;                /* 0Ch */
-    U8                      Reserved;                   /* 0Dh */
-    U16                     Reserved2;                  /* 0Eh */
-    U8                      InquiryData[56];            /* 10h */
+    fCONFIG_PAGE_HEADER      Header;                                   /* 00h */
+    U8                      GPIOCount;                                /* 04h */
+    U8                      Reserved1;                                /* 05h */
+    U16                     Reserved2;                                /* 06h */
+    U16                     GPIOVal[MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX]; /* 08h */
 } fCONFIG_PAGE_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_3,
   IOUnitPage3_t, MPI_POINTER pIOUnitPage3_t;
 
-#define MPI_IOUNITPAGE3_PAGEVERSION                     (0x00)
+#define MPI_IOUNITPAGE3_PAGEVERSION                     (0x01)
+
+#define MPI_IOUNITPAGE3_GPIO_FUNCTION_MASK              (0xFC)
+#define MPI_IOUNITPAGE3_GPIO_FUNCTION_SHIFT             (2)
+#define MPI_IOUNITPAGE3_GPIO_SETTING_OFF                (0x00)
+#define MPI_IOUNITPAGE3_GPIO_SETTING_ON                 (0x01)
 
 
-/****************************************************************************/
-/*  IOC Config Pages                                                        */
-/****************************************************************************/
+/****************************************************************************
+*   IOC Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_IOC_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     TotalNVStore;               /* 04h */
     U32                     FreeNVStore;                /* 08h */
     U16                     VendorID;                   /* 0Ch */
@@ -393,7 +477,7 @@
 
 typedef struct _CONFIG_PAGE_IOC_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U32                     CoalescingTimeout;          /* 08h */
     U8                      CoalescingDepth;            /* 0Ch */
@@ -408,53 +492,120 @@
 
 typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
 {
-    U8                      VolumeTargetID;             /* 00h */
-    U8                      VolumeBus;                  /* 01h */
-    U16                     Reserved;                   /* 02h */
-    U8                      VolumeVersionMinor;         /* 04h */
-    U8                      VolumeVersionMajor;         /* 05h */
-    U8                      VolumeRaidType;             /* 06h */
-    U8                      Reserved1;                  /* 07h */
+    U8                          VolumeID;               /* 00h */
+    U8                          VolumeBus;              /* 01h */
+    U8                          VolumeIOC;              /* 02h */
+    U8                          VolumePageNumber;       /* 03h */
+    U8                          VolumeType;             /* 04h */
+    U8                          Reserved2;              /* 05h */
+    U16                         Reserved3;              /* 06h */
 } fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
   ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_2_RAID_VOLUME_MAX
+#define MPI_IOC_PAGE_2_RAID_VOLUME_MAX      (1)
+#endif
+
 typedef struct _CONFIG_PAGE_IOC_2
 {
-   fCONFIG_PAGE_HEADER          Header;                 /* 00h */
-    U32                         CapabilitiesFlags;      /* 04h */
-    U8                          NumActiveVolumes;       /* 08h */
-    U8                          MaxVolumes;             /* 09h */
-    U16                         Reserved;               /* 0Ah */
-   fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[1];          /* 0Ch */
+    fCONFIG_PAGE_HEADER          Header;                              /* 00h */
+    U32                         CapabilitiesFlags;                   /* 04h */
+    U8                          NumActiveVolumes;                    /* 08h */
+    U8                          MaxVolumes;                          /* 09h */
+    U8                          NumActivePhysDisks;                  /* 0Ah */
+    U8                          MaxPhysDisks;                        /* 0Bh */
+    fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[MPI_IOC_PAGE_2_RAID_VOLUME_MAX];/* 0Ch */
 } fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
   IOCPage2_t, MPI_POINTER pIOCPage2_t;
 
-#define MPI_IOCPAGE2_PAGEVERSION                        (0x00)
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x01)
 
 /* IOC Page 2 Capabilities flags */
 
-#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT           (0x00000001)
-#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT           (0x00000002)
-#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT       (0x00000004)
-#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT           (0x00000008)
-#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT          (0x00000010)
-
-/* IOC Page 2 Volume RAID Type values */
-
-#define MPI_IOCPAGE2_VOL_TYPE_RAID_0                    (0x00)
-#define MPI_IOCPAGE2_VOL_TYPE_RAID_1                    (0x01)
-#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR                (0x02)
-#define MPI_IOCPAGE2_VOL_TYPE_RAID_5                    (0x05)
-#define MPI_IOCPAGE2_VOL_TYPE_RAID_10                   (0x0A)
-
-
-/****************************************************************************/
-/*  SCSI Port Config Pages                                                  */
-/****************************************************************************/
+#define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT               (0x00000001)
+#define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT              (0x00000002)
+#define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT               (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT              (0x20000000)
+#define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT            (0x40000000)
+#define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT    (0x80000000)
+
+/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
+
+#define MPI_RAID_VOL_TYPE_IS                        (0x00)
+#define MPI_RAID_VOL_TYPE_IME                       (0x01)
+#define MPI_RAID_VOL_TYPE_IM                        (0x02)
+
+
+typedef struct _IOC_3_PHYS_DISK
+{
+    U8                          PhysDiskID;             /* 00h */
+    U8                          PhysDiskBus;            /* 01h */
+    U8                          PhysDiskIOC;            /* 02h */
+    U8                          PhysDiskNum;            /* 03h */
+} IOC_3_PHYS_DISK, MPI_POINTER PTR_IOC_3_PHYS_DISK,
+  Ioc3PhysDisk_t, MPI_POINTER pIoc3PhysDisk_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_3_PHYSDISK_MAX
+#define MPI_IOC_PAGE_3_PHYSDISK_MAX         (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_3
+{
+    fCONFIG_PAGE_HEADER          Header;                                /* 00h */
+    U8                          NumPhysDisks;                          /* 04h */
+    U8                          Reserved1;                             /* 05h */
+    U16                         Reserved2;                             /* 06h */
+    IOC_3_PHYS_DISK             PhysDisk[MPI_IOC_PAGE_3_PHYSDISK_MAX]; /* 08h */
+} fCONFIG_PAGE_IOC_3, MPI_POINTER PTR_CONFIG_PAGE_IOC_3,
+  IOCPage3_t, MPI_POINTER pIOCPage3_t;
+
+#define MPI_IOCPAGE3_PAGEVERSION                        (0x00)
+
+
+typedef struct _IOC_4_SEP
+{
+    U8                          SEPTargetID;            /* 00h */
+    U8                          SEPBus;                 /* 01h */
+    U16                         Reserved;               /* 02h */
+} IOC_4_SEP, MPI_POINTER PTR_IOC_4_SEP,
+  Ioc4Sep_t, MPI_POINTER pIoc4Sep_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_4_SEP_MAX
+#define MPI_IOC_PAGE_4_SEP_MAX              (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_4
+{
+    fCONFIG_PAGE_HEADER          Header;                         /* 00h */
+    U8                          ActiveSEP;                      /* 04h */
+    U8                          MaxSEP;                         /* 05h */
+    U16                         Reserved1;                      /* 06h */
+    IOC_4_SEP                   SEP[MPI_IOC_PAGE_4_SEP_MAX];    /* 08h */
+} fCONFIG_PAGE_IOC_4, MPI_POINTER PTR_CONFIG_PAGE_IOC_4,
+  IOCPage4_t, MPI_POINTER pIOCPage4_t;
+
+#define MPI_IOCPAGE4_PAGEVERSION                        (0x00)
+
+
+/****************************************************************************
+*   SCSI Port Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Capabilities;               /* 04h */
     U32                     PhysicalInterface;          /* 08h */
 } fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0,
@@ -465,7 +616,6 @@
 #define MPI_SCSIPORTPAGE0_CAP_IU                        (0x00000001)
 #define MPI_SCSIPORTPAGE0_CAP_DT                        (0x00000002)
 #define MPI_SCSIPORTPAGE0_CAP_QAS                       (0x00000004)
-#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS          (0x00000008)
 #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK      (0x0000FF00)
 #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
 #define MPI_SCSIPORTPAGE0_CAP_WIDE                      (0x20000000)
@@ -479,12 +629,13 @@
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Configuration;              /* 04h */
+    U32                     OnBusTimerValue;            /* 08h */
 } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
   SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
 
-#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x01)
+#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x02)
 
 #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
 #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
@@ -500,7 +651,7 @@
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_2
 {
-   fCONFIG_PAGE_HEADER  Header;                         /* 00h */
+    fCONFIG_PAGE_HEADER  Header;                         /* 00h */
     U32                 PortFlags;                      /* 04h */
     U32                 PortSettings;                   /* 08h */
     MPI_DEVICE_INFO     DeviceSettings[16];             /* 0Ch */
@@ -510,7 +661,6 @@
 #define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x01)
 
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW       (0x00000001)
-#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE          (0x00000002)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET       (0x00000004)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS          (0x00000008)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE    (0x00000010)
@@ -536,47 +686,48 @@
 #define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE                (0x0020)
 
 
-/****************************************************************************/
-/*  SCSI Target Device Config Pages                                         */
-/****************************************************************************/
+/****************************************************************************
+*   SCSI Target Device Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     NegotiatedParameters;       /* 04h */
     U32                     Information;                /* 08h */
 } fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
   SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
 
-#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x01)
+#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x02)
 
 #define MPI_SCSIDEVPAGE0_NP_IU                          (0x00000001)
 #define MPI_SCSIDEVPAGE0_NP_DT                          (0x00000002)
 #define MPI_SCSIDEVPAGE0_NP_QAS                         (0x00000004)
-#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS            (0x00000008)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
 #define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
 #define MPI_SCSIDEVPAGE0_NP_AIP                         (0x80000000)
 
 #define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED         (0x00000001)
+#define MPI_SCSIDEVPAGE0_INFO_SDTR_REJECTED             (0x00000002)
+#define MPI_SCSIDEVPAGE0_INFO_WDTR_REJECTED             (0x00000004)
+#define MPI_SCSIDEVPAGE0_INFO_PPR_REJECTED              (0x00000008)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     RequestedParameters;        /* 04h */
     U32                     Reserved;                   /* 08h */
     U32                     Configuration;              /* 0Ch */
 } fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
   SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
 
-#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x02)
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x03)
 
 #define MPI_SCSIDEVPAGE1_RP_IU                          (0x00000001)
 #define MPI_SCSIDEVPAGE1_RP_DT                          (0x00000002)
 #define MPI_SCSIDEVPAGE1_RP_QAS                         (0x00000004)
-#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS            (0x00000008)
 #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK        (0x0000FF00)
 #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK        (0x00FF0000)
 #define MPI_SCSIDEVPAGE1_RP_WIDE                        (0x20000000)
@@ -585,12 +736,13 @@
 #define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK     (0x00000003)
 #define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK           (0x00000300)
 
-#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED               (0x00000001)
+#define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED           (0x00000002)
+#define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED           (0x00000004)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     DomainValidation;           /* 04h */
     U32                     ParityPipeSelect;           /* 08h */
     U32                     DataPipeSelect;             /* 0Ch */
@@ -629,13 +781,13 @@
 #define MPI_SCSIDEVPAGE2_DPS_BIT_15_PL_SELECT_MASK      (0xC0000000)
 
 
-/****************************************************************************/
-/*  FC Port Config Pages                                                    */
-/****************************************************************************/
+/****************************************************************************
+*   FC Port Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_FC_PORT_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U8                      MPIPortNumber;              /* 08h */
     U8                      LinkType;                   /* 09h */
@@ -715,7 +867,7 @@
 
 typedef struct _CONFIG_PAGE_FC_PORT_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U64                     NoSEEPROMWWNN;              /* 08h */
     U64                     NoSEEPROMWWPN;              /* 10h */
@@ -726,8 +878,10 @@
 } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
   FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
 
-#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x01)
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x02)
 
+#define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
+#define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
 
@@ -747,22 +901,21 @@
 #define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG             (0x03)
 #define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO              (0x0F)
 
-#define MPI_FCPORTPAGE1_TOPOLGY_MASK                    (0x0F)
-#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT                  (0x01)
-#define MPI_FCPORTPAGE1_TOPOLGY_NPORT                   (0x02)
-#define MPI_FCPORTPAGE1_TOPOLGY_AUTO                    (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLOGY_MASK                   (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLOGY_NLPORT                 (0x01)
+#define MPI_FCPORTPAGE1_TOPOLOGY_NPORT                  (0x02)
+#define MPI_FCPORTPAGE1_TOPOLOGY_AUTO                   (0x0F)
 
 
 typedef struct _CONFIG_PAGE_FC_PORT_2
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U8                      NumberActive;               /* 04h */
-    U8                      ALPA[126];                  /* 05h */
-    U8                      Reserved;                   /* 83h */
+    U8                      ALPA[127];                  /* 05h */
 } fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2,
   FCPortPage2_t, MPI_POINTER pFCPortPage2_t;
 
-#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x00)
+#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x01)
 
 
 typedef struct _WWN_FORMAT
@@ -795,10 +948,18 @@
 #define MPI_PERSISTENT_FLAGS_BOOT_DEVICE                (0x0008)
 #define MPI_PERSISTENT_FLAGS_BY_DID                     (0x0080)
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_FC_PORT_PAGE_3_ENTRY_MAX
+#define MPI_FC_PORT_PAGE_3_ENTRY_MAX        (1)
+#endif
+
 typedef struct _CONFIG_PAGE_FC_PORT_3
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
-    FC_PORT_PERSISTENT      Entry[1];                   /* 04h */
+    fCONFIG_PAGE_HEADER      Header;                                 /* 00h */
+    FC_PORT_PERSISTENT      Entry[MPI_FC_PORT_PAGE_3_ENTRY_MAX];    /* 04h */
 } fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3,
   FCPortPage3_t, MPI_POINTER pFCPortPage3_t;
 
@@ -807,7 +968,7 @@
 
 typedef struct _CONFIG_PAGE_FC_PORT_4
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     PortFlags;                  /* 04h */
     U32                     PortSettings;               /* 08h */
 } fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4,
@@ -833,13 +994,22 @@
     U16     Reserved;                                   /* 02h */
     U64     AliasWWNN;                                  /* 04h */
     U64     AliasWWPN;                                  /* 0Ch */
-} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
   FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_FC_PORT_PAGE_5_ALIAS_MAX
+#define MPI_FC_PORT_PAGE_5_ALIAS_MAX        (1)
+#endif
+
 typedef struct _CONFIG_PAGE_FC_PORT_5
 {
-   fCONFIG_PAGE_HEADER                  Header;         /* 00h */
-   fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[1];   /* 04h */
+    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
+    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[MPI_FC_PORT_PAGE_5_ALIAS_MAX];/* 04h */
 } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
   FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
 
@@ -851,7 +1021,7 @@
 
 typedef struct _CONFIG_PAGE_FC_PORT_6
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Reserved;                   /* 04h */
     U64                     TimeSinceReset;             /* 08h */
     U64                     TxFrames;                   /* 10h */
@@ -877,7 +1047,7 @@
 
 typedef struct _CONFIG_PAGE_FC_PORT_7
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Reserved;                   /* 04h */
     U8                      PortSymbolicName[256];      /* 08h */
 } fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7,
@@ -888,7 +1058,7 @@
 
 typedef struct _CONFIG_PAGE_FC_PORT_8
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     BitVector[8];               /* 04h */
 } fCONFIG_PAGE_FC_PORT_8, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_8,
   FCPortPage8_t, MPI_POINTER pFCPortPage8_t;
@@ -898,7 +1068,7 @@
 
 typedef struct _CONFIG_PAGE_FC_PORT_9
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Reserved;                   /* 04h */
     U64                     GlobalWWPN;                 /* 08h */
     U64                     GlobalWWNN;                 /* 10h */
@@ -916,13 +1086,13 @@
 #define MPI_FCPORTPAGE9_PAGEVERSION                     (0x00)
 
 
-/****************************************************************************/
-/*  FC Device Config Pages                                                  */
-/****************************************************************************/
+/****************************************************************************
+*   FC Device Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_FC_DEVICE_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U64                     WWNN;                       /* 04h */
     U64                     WWPN;                       /* 0Ch */
     U32                     PortIdentifier;             /* 14h */
@@ -947,112 +1117,191 @@
 #define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET             (0x02)
 #define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR          (0x04)
 
-#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK              (MPI_FC_DEVICE_PGAD_PORT_MASK)
-#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK              (MPI_FC_DEVICE_PGAD_FORM_MASK)
-#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID          (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
-#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID           (MPI_FC_DEVICE_PGAD_FORM_BUS_TID)
-#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK               (MPI_FC_DEVICE_PGAD_ND_DID_MASK)
-#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK               (MPI_FC_DEVICE_PGAD_BT_BUS_MASK)
-#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT              (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
-#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK               (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
-
-
-/****************************************************************************/
-/*  RAID Volume Config Pages                                                  */
-/****************************************************************************/
-
-typedef struct _RAIDVOL2_IM_PHYS_ID
-{
-    U8                      TargetID;                   /* 00h */
-    U8                      Bus;                        /* 01h */
-    U8                      IocNumber;                  /* 02h */
-    U8                      PhysDiskNumber;             /* 03h */
-    U8                      Reserved[8];                /* 04h */
-    U8                      PhysicalDiskIdentifier[16]; /* 0Ch */
-    U8                      VendorId[8];                /* 1Ch */
-    U8                      ProductId[16];              /* 24h */
-    U8                      ProductRevLevel[4];         /* 34h */
-    U32                     Reserved1;                  /* 38h */
-    U8                      Info[32];                   /* 3Ch */
-} RAIDVOL2_IM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_IM_PHYS_ID,
-  RaidVol2ImPhysicalID_t, MPI_POINTER pRaidVol2ImPhysicalID_t;
-
-typedef struct _RAIDVOL2_IM_DISK_INFO
-{
-    U32                     DiskStatus;                 /* 00h */
-    U32                     DeviceSettings;             /* 04h */
-    U16                     ErrorCount;                 /* 08h */
-    U16                     Reserved;                   /* 0Ah */
-    U8                      ErrorCdbByte;               /* 0Ch */
-    U8                      ErrorSenseKey;              /* 0Dh */
-    U8                      ErrorASC;                   /* 0Eh */
-    U8                      ErrorASCQ;                  /* 0Fh */
-    U16                     SmartCount;                 /* 10h */
-    U8                      SmartASC;                   /* 12h */
-    U8                      SmartASCQ;                  /* 13h */
-} RAIDVOL2_IM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_IM_DISK_INFO,
-  RaidVol2ImDiskInfo_t, MPI_POINTER pRaidVol2ImDiskInfo_t;
+#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK      (MPI_FC_DEVICE_PGAD_PORT_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK      (MPI_FC_DEVICE_PGAD_FORM_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID  (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID   (MPI_FC_DEVICE_PGAD_FORM_BUS_TID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK       (MPI_FC_DEVICE_PGAD_ND_DID_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK       (MPI_FC_DEVICE_PGAD_BT_BUS_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT      (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
+#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK       (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
+
+
+/****************************************************************************
+*   RAID Volume Config Pages
+****************************************************************************/
+
+typedef struct _RAID_VOL0_PHYS_DISK
+{
+    U16                         Reserved;               /* 00h */
+    U8                          PhysDiskMap;            /* 02h */
+    U8                          PhysDiskNum;            /* 03h */
+} RAID_VOL0_PHYS_DISK, MPI_POINTER PTR_RAID_VOL0_PHYS_DISK,
+  RaidVol0PhysDisk_t, MPI_POINTER pRaidVol0PhysDisk_t;
+
+#define MPI_RAIDVOL0_PHYSDISK_PRIMARY                   (0x01)
+#define MPI_RAIDVOL0_PHYSDISK_SECONDARY                 (0x02)
+
+typedef struct _RAID_VOL0_STATUS
+{
+    U8                          Flags;                  /* 00h */
+    U8                          State;                  /* 01h */
+    U16                         Reserved;               /* 02h */
+} RAID_VOL0_STATUS, MPI_POINTER PTR_RAID_VOL0_STATUS,
+  RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t;
+
+/* RAID Volume Page 0 VolumeStatus defines */
+
+#define MPI_RAIDVOL0_STATUS_FLAG_ENABLED                (0x01)
+#define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED               (0x02)
+#define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS     (0x04)
+
+#define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL               (0x00)
+#define MPI_RAIDVOL0_STATUS_STATE_DEGRADED              (0x01)
+#define MPI_RAIDVOL0_STATUS_STATE_FAILED                (0x02)
+
+typedef struct _RAID_VOL0_SETTINGS
+{
+    U16                         Settings;       /* 00h */
+    U8                          HotSparePool;   /* 01h */ /* MPI_RAID_HOT_SPARE_POOL_ */
+    U8                          Reserved;       /* 02h */
+} RAID_VOL0_SETTINGS, MPI_POINTER PTR_RAID_VOL0_SETTINGS,
+  RaidVol0Settings, MPI_POINTER pRaidVol0Settings;
+
+/* RAID Volume Page 0 VolumeSettings defines */
+
+#define MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE       (0x0001)
+#define MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART           (0x0002)
+#define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE             (0x0004)
+#define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC            (0x0008)
+#define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX      (0x0010)
+#define MPI_RAIDVOL0_SETTING_USE_DEFAULTS               (0x8000)
+
+/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
+#define MPI_RAID_HOT_SPARE_POOL_0                       (0x01)
+#define MPI_RAID_HOT_SPARE_POOL_1                       (0x02)
+#define MPI_RAID_HOT_SPARE_POOL_2                       (0x04)
+#define MPI_RAID_HOT_SPARE_POOL_3                       (0x08)
+#define MPI_RAID_HOT_SPARE_POOL_4                       (0x10)
+#define MPI_RAID_HOT_SPARE_POOL_5                       (0x20)
+#define MPI_RAID_HOT_SPARE_POOL_6                       (0x40)
+#define MPI_RAID_HOT_SPARE_POOL_7                       (0x80)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX
+#define MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX        (1)
+#endif
+
+typedef struct _CONFIG_PAGE_RAID_VOL_0
+{
+    fCONFIG_PAGE_HEADER      Header;         /* 00h */
+    U8                      VolumeID;       /* 04h */
+    U8                      VolumeBus;      /* 05h */
+    U8                      VolumeIOC;      /* 06h */
+    U8                      VolumeType;     /* 07h */ /* MPI_RAID_VOL_TYPE_ */
+    RAID_VOL0_STATUS        VolumeStatus;   /* 08h */
+    RAID_VOL0_SETTINGS      VolumeSettings; /* 0Ch */
+    U32                     MaxLBA;         /* 10h */
+    U32                     Reserved1;      /* 14h */
+    U32                     StripeSize;     /* 18h */
+    U32                     Reserved2;      /* 1Ch */
+    U32                     Reserved3;      /* 20h */
+    U8                      NumPhysDisks;   /* 24h */
+    U8                      Reserved4;      /* 25h */
+    U16                     Reserved5;      /* 26h */
+    RAID_VOL0_PHYS_DISK     PhysDisk[MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX];/* 28h */
+} fCONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
+  RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
+
+#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x00)
+
+
+/****************************************************************************
+*   RAID Physical Disk Config Pages
+****************************************************************************/
+
+typedef struct _RAID_PHYS_DISK0_ERROR_DATA
+{
+    U8                      ErrorCdbByte;               /* 00h */
+    U8                      ErrorSenseKey;              /* 01h */
+    U16                     Reserved;                   /* 02h */
+    U16                     ErrorCount;                 /* 04h */
+    U8                      ErrorASC;                   /* 06h */
+    U8                      ErrorASCQ;                  /* 07h */
+    U16                     SmartCount;                 /* 08h */
+    U8                      SmartASC;                   /* 0Ah */
+    U8                      SmartASCQ;                  /* 0Bh */
+} RAID_PHYS_DISK0_ERROR_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_ERROR_DATA,
+  RaidPhysDisk0ErrorData_t, MPI_POINTER pRaidPhysDisk0ErrorData_t;
+
+typedef struct _RAID_PHYS_DISK_INQUIRY_DATA
+{
+    U8                          VendorID[8];            /* 00h */
+    U8                          ProductID[16];          /* 08h */
+    U8                          ProductRevLevel[4];     /* 18h */
+    U8                          Info[32];               /* 1Ch */
+} RAID_PHYS_DISK0_INQUIRY_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_INQUIRY_DATA,
+  RaidPhysDisk0InquiryData, MPI_POINTER pRaidPhysDisk0InquiryData;
+
+typedef struct _RAID_PHYS_DISK0_SETTINGS
+{
+    U8              SepID;              /* 00h */
+    U8              SepBus;             /* 01h */
+    U8              HotSparePool;       /* 02h */ /* MPI_RAID_HOT_SPARE_POOL_ */
+    U8              PhysDiskSettings;   /* 03h */
+} RAID_PHYS_DISK0_SETTINGS, MPI_POINTER PTR_RAID_PHYS_DISK0_SETTINGS,
+  RaidPhysDiskSettings_t, MPI_POINTER pRaidPhysDiskSettings_t;
+
+typedef struct _RAID_PHYS_DISK0_STATUS
+{
+    U8                              Flags;              /* 00h */
+    U8                              State;              /* 01h */
+    U16                             Reserved;           /* 02h */
+} RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS,
+  RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t;
 
 /* RAID Volume 2 IM Physical Disk DiskStatus flags */
 
-#define MPI_RVP2_PHYS_DISK_PRIMARY                      (0x00000001)
-#define MPI_RVP2_PHYS_DISK_SECONDARY                    (0x00000002)
-#define MPI_RVP2_PHYS_DISK_HOT_SPARE                    (0x00000004)
-#define MPI_RVP2_PHYS_DISK_OUT_OF_SYNC                  (0x00000008)
-#define MPI_RVP2_PHYS_DISK_STATUS_MASK                  (0x00000F00)
-#define MPI_RVP2_PHYS_DISK_STATUS_ONLINE                (0x00000000)
-#define MPI_RVP2_PHYS_DISK_STATUS_MISSING               (0x00000100)
-#define MPI_RVP2_PHYS_DISK_STATUS_NOT_COMPATIBLE        (0x00000200)
-#define MPI_RVP2_PHYS_DISK_STATUS_FAILED                (0x00000300)
-#define MPI_RVP2_PHYS_DISK_STATUS_INITIALIZING          (0x00000400)
-#define MPI_RVP2_PHYS_DISK_STATUS_OFFLINE_REQUESTED     (0x00000500)
-#define MPI_RVP2_PHYS_DISK_STATUS_OTHER_OFFLINE         (0x00000F00)
-
-
-typedef struct _RAIDVOL2_IM_PHYSICAL_DISK
-{
-    RAIDVOL2_IM_PHYS_ID     Id;                         /* 00h */
-    RAIDVOL2_IM_DISK_INFO   Info;                       /* 5Ch */
-} RAIDVOL2_IM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_IM_PHYSICAL_DISK,
-  RaidVol2ImPhysicalDisk_t, MPI_POINTER pRaidVol2ImPhysicalDisk_t;
-
-#define MPI_RAIDVOLPAGE2_MAX_DISKS                      (3)
-
-typedef struct _CONFIG_PAGE_RAID_VOL_2
-{
-   fCONFIG_PAGE_HEADER          Header;                 /* 00h */
-    U32                         VolumeStatus;           /* 04h */
-    U32                         VolumeSettings;         /* 08h */
-    U32                         Reserved;               /* 0Ch */
-    U64                         MaxLba;                 /* 10h */
-    U32                         BlockSize;              /* 18h */
-    U8                          Reserved1;              /* 1Ch */
-    U8                          NumPhysicalDisks;       /* 1Dh */
-    U16                         Reserved2;              /* 1Eh */
-    RAIDVOL2_IM_PHYSICAL_DISK   IMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS];
-} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2,
-  RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t;
-
-#define MPI_RAIDVOLPAGE2_PAGEVERSION                    (0x00)
-
-/* RAID Volume Page 2 VolumeStatus defines */
-
-#define MPI_RAIDVOLPAGE2_STATUS_ENABLED                 (0x00000001)
-#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED                (0x00000002)
-#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS      (0x00000004)
-#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED                (0x00000008)
-
-/* RAID Volume Page 2 VolumeSettings defines */
-
-#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE   (0x00000001)
-#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART       (0x00000002)
-#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE         (0x00000004)
-#define MPI_RAIDVOLPAGE2_SETTING_USE_DEFAULTS           (0x80000000)
-
-
-/****************************************************************************/
-/* LAN Config Pages                                                         */
-/****************************************************************************/
+#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC           (0x01)
+#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED              (0x02)
+
+#define MPI_PHYSDISK0_STATUS_ONLINE                     (0x00)
+#define MPI_PHYSDISK0_STATUS_MISSING                    (0x01)
+#define MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE             (0x02)
+#define MPI_PHYSDISK0_STATUS_FAILED                     (0x03)
+#define MPI_PHYSDISK0_STATUS_INITIALIZING               (0x04)
+#define MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED          (0x05)
+#define MPI_PHYSDISK0_STATUS_FAILED_REQUESTED           (0x06)
+#define MPI_PHYSDISK0_STATUS_OTHER_OFFLINE              (0xFF)
+
+typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U8                              PhysDiskID;         /* 04h */
+    U8                              PhysDiskBus;        /* 05h */
+    U8                              PhysDiskIOC;        /* 06h */
+    U8                              PhysDiskNum;        /* 07h */
+    RAID_PHYS_DISK0_SETTINGS        PhysDiskSettings;   /* 08h */
+    U32                             Reserved1;          /* 0Ch */
+    U32                             Reserved2;          /* 10h */
+    U32                             Reserved3;          /* 14h */
+    U8                              DiskIdentifier[16]; /* 18h */
+    RAID_PHYS_DISK0_INQUIRY_DATA    InquiryData;        /* 28h */
+    RAID_PHYS_DISK0_STATUS          PhysDiskStatus;     /* 64h */
+    U32                             MaxLBA;             /* 68h */
+    RAID_PHYS_DISK0_ERROR_DATA      ErrorData;          /* 6Ch */
+} fCONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0,
+  RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t;
+
+#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION           (0x00)
+
+
+/****************************************************************************
+*   LAN Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_LAN_0
 {
@@ -1083,8 +1332,8 @@
     U32                     MaxWireSpeedHigh;           /* 1Ch */
     U32                     BucketsRemaining;           /* 20h */
     U32                     MaxReplySize;               /* 24h */
-    U32                     NegWireSpeedHigh;           /* 28h */
-    U32                     NegWireSpeedLow;            /* 2Ch */
+    U32                     NegWireSpeedLow;            /* 28h */
+    U32                     NegWireSpeedHigh;           /* 2Ch */
 } fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1,
   LANPage1_t, MPI_POINTER pLANPage1_t;
 
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_fc.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_fc.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_fc.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_fc.h	Fri Mar 29 14:49:34 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Fibre Channel messages and structures
  *  Creation Date:  June 12, 2000
  *
- *    MPI Version:  01.01.07
+ *    MPI Version:  01.02.02
  *
  *  Version History
  *  ---------------
@@ -32,6 +32,9 @@
  *                      Added MPI_FC_PRIM_SEND_FLAGS_RESET_LINK define.
  *                      Added structure offset comments.
  *  04-09-01  01.01.07  Added RspLength field to MSG_LINK_SERVICE_RSP_REQUEST.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Change name of reserved field in
+ *                      MSG_LINK_SERVICE_RSP_REPLY.
  *  --------------------------------------------------------------------------
  */
 
@@ -172,7 +175,7 @@
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
     U16                     Reserved1;          /* 04h */
-    U8                      Reserved2;          /* 06h */
+    U8                      Reserved_0100_InitiatorIndex; /* 06h */ /* obsolete InitiatorIndex */
     U8                      MsgFlags;           /* 07h */
     U32                     MsgContext;         /* 08h */
     U16                     Reserved3;          /* 0Ch */
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_init.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_init.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_init.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_init.h	Fri Mar 29 14:49:34 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    MPI Version:  01.01.05
+ *    MPI Version:  01.02.04
  *
  *  Version History
  *  ---------------
@@ -22,6 +22,13 @@
  *  02-20-01  01.01.03  Started using MPI_POINTER.
  *  03-27-01  01.01.04  Added structure offset comments.
  *  04-10-01  01.01.05  Added new MsgFlag for MSG_SCSI_TASK_MGMT.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  08-29-01  01.02.02  Added MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET.
+ *                      Added MPI_SCSI_STATE_QUEUE_TAG_REJECTED for
+ *                      MSG_SCSI_IO_REPLY.
+ *  09-28-01  01.02.03  Added structures and defines for SCSI Enclosure
+ *                      Processor messages.
+ *  10-04-01  01.02.04  Added defines for SEP request Action field.
  *  --------------------------------------------------------------------------
  */
 
@@ -151,6 +158,7 @@
 #define MPI_SCSI_STATE_NO_SCSI_STATUS           (0x04)
 #define MPI_SCSI_STATE_TERMINATED               (0x08)
 #define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
+#define MPI_SCSI_STATE_QUEUE_TAG_REJECTED       (0x20)
 
 /* SCSIIO Reply ResponseInfo values */
 /* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
@@ -191,6 +199,7 @@
 #define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET         (0x02)
 #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET          (0x03)
 #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS             (0x04)
+#define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET    (0x05)
 
 /* MsgFlags bits */
 #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION   (0x00)
@@ -216,4 +225,91 @@
 } MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
   SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
 
+
+/****************************************************************************/
+/*  SCSI Enclosure Processor messages                                       */
+/****************************************************************************/
+
+typedef struct _MSG_SEP_REQUEST
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Action;             /* 04h */
+    U8                      Reserved1;          /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     SlotStatus;         /* 0Ch */
+} MSG_SEP_REQUEST, MPI_POINTER PTR_MSG_SEP_REQUEST,
+  SEPRequest_t, MPI_POINTER pSEPRequest_t;
+
+/* Action defines */
+#define MPI_SEP_REQ_ACTION_WRITE_STATUS                 (0x00)
+#define MPI_SEP_REQ_ACTION_READ_STATUS                  (0x01)
+
+/* SlotStatus bits for MSG_SEP_REQUEST */
+#define MPI_SEP_REQ_SLOTSTATUS_NO_ERROR                 (0x00000001)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_FAULTY               (0x00000002)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_REBUILDING           (0x00000004)
+#define MPI_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY          (0x00000008)
+#define MPI_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY        (0x00000010)
+#define MPI_SEP_REQ_SLOTSTATUS_PARITY_CHECK             (0x00000020)
+#define MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT          (0x00000040)
+#define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED             (0x00000080)
+#define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE                (0x00000100)
+#define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED          (0x00000200)
+#define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST         (0x00020000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE           (0x00040000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT           (0x00080000)
+#define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE              (0x00400000)
+#define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS          (0x04000000)
+#define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS          (0x08000000)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF                  (0x10000000)
+#define MPI_SEP_REQ_SLOTSTATUS_SWAP_RESET               (0x80000000)
+
+
+typedef struct _MSG_SEP_REPLY
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Action;             /* 04h */
+    U8                      Reserved1;          /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     SlotStatus;         /* 14h */
+} MSG_SEP_REPLY, MPI_POINTER PTR_MSG_SEP_REPLY,
+  SEPReply_t, MPI_POINTER pSEPReply_t;
+
+/* SlotStatus bits for MSG_SEP_REPLY */
+#define MPI_SEP_REPLY_SLOTSTATUS_NO_ERROR               (0x00000001)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_FAULTY             (0x00000002)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING         (0x00000004)
+#define MPI_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY        (0x00000008)
+#define MPI_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY      (0x00000010)
+#define MPI_SEP_REPLY_SLOTSTATUS_PARITY_CHECK           (0x00000020)
+#define MPI_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT        (0x00000040)
+#define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED           (0x00000080)
+#define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE              (0x00000100)
+#define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED        (0x00000200)
+#define MPI_SEP_REPLY_SLOTSTATUS_REPORT                 (0x00010000)
+#define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST       (0x00020000)
+#define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY           (0x00040000)
+#define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY           (0x00080000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE          (0x00400000)
+#define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED       (0x01000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED       (0x02000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS        (0x04000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_A_ENABLE_BYPASS        (0x08000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_OFF                (0x10000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_FAULT_SENSED           (0x40000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_SWAPPED                (0x80000000)
+
 #endif
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_ioc.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_ioc.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_ioc.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_ioc.h	Fri Mar 29 14:49:34 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    MPI Version:  01.01.07
+ *    MPI Version:  01.02.04
  *
  *  Version History
  *  ---------------
@@ -38,6 +38,19 @@
  *  03-27-01  01.01.06  Added defines for ProductId field of MPI_FW_HEADER.
  *                      Added structure offset comments.
  *  04-09-01  01.01.07  Added structure EVENT_DATA_EVENT_CHANGE.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      New format for FWVersion and ProductId in
+ *                      MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
+ *  08-31-01  01.02.02  Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ *                      related structure and defines.
+ *                      Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
+ *                      Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
+ *                      Replaced a reserved field in MSG_IOC_FACTS_REPLY with
+ *                      IOCExceptions and changed DataImageSize to reserved.
+ *                      Added MPI_FW_DOWNLOAD_ITYPE_NVSTORE_DATA and
+ *                      MPI_FW_UPLOAD_ITYPE_NVDATA.
+ *  09-28-01  01.02.03  Modified Event Data for Integrated RAID.
+ *  11-01-01  01.02.04  Added defines for MPI_EXT_IMAGE_HEADER ImageType field.
  *  --------------------------------------------------------------------------
  */
 
@@ -73,6 +86,17 @@
 } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
   IOCInit_t, MPI_POINTER pIOCInit_t;
 
+/* WhoInit values */
+#define MPI_WHOINIT_NO_ONE                      (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS                 (0x01)
+#define MPI_WHOINIT_ROM_BIOS                    (0x02)
+#define MPI_WHOINIT_PCI_PEER                    (0x03)
+#define MPI_WHOINIT_HOST_DRIVER                 (0x04)
+#define MPI_WHOINIT_MANUFACTURER                (0x05)
+
+/* Flags values */
+#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE      (0x01)
+
 typedef struct _MSG_IOC_INIT_REPLY
 {
     U8                      WhoInit;                    /* 00h */
@@ -90,14 +114,6 @@
 } MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY,
   IOCInitReply_t, MPI_POINTER pIOCInitReply_t;
 
-/* WhoInit values */
-
-#define MPI_WHOINIT_NO_ONE                      (0x00)
-#define MPI_WHOINIT_SYSTEM_BIOS                 (0x01)
-#define MPI_WHOINIT_ROM_BIOS                    (0x02)
-#define MPI_WHOINIT_PCI_PEER                    (0x03)
-#define MPI_WHOINIT_HOST_DRIVER                 (0x04)
-#define MPI_WHOINIT_MANUFACTURER                (0x05)
 
 
 /****************************************************************************/
@@ -115,8 +131,21 @@
 } MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS,
   IOCFacts_t, MPI_POINTER pIOCFacts_t;
 
-/* IOC Facts Reply */
+typedef struct _MPI_FW_VERSION_STRUCT
+{
+    U8                      Dev;                        /* 00h */
+    U8                      Unit;                       /* 01h */
+    U8                      Minor;                      /* 02h */
+    U8                      Major;                      /* 03h */
+} MPI_FW_VERSION_STRUCT;
+
+typedef union _MPI_FW_VERSION
+{
+    MPI_FW_VERSION_STRUCT   Struct;
+    U32                     Word;
+} MPI_FW_VERSION;
 
+/* IOC Facts Reply */
 typedef struct _MSG_IOC_FACTS_REPLY
 {
     U16                     MsgVersion;                 /* 00h */
@@ -126,7 +155,7 @@
     U8                      IOCNumber;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCExceptions;              /* 0Ch */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
     U8                      MaxChainDepth;              /* 14h */
@@ -135,7 +164,7 @@
     U8                      Flags;                      /* 17h */
     U16                     ReplyQueueDepth;            /* 18h */
     U16                     RequestFrameSize;           /* 1Ah */
-    U16                     FWVersion;                  /* 1Ch */
+    U16                     Reserved_0101_FWVersion;    /* 1Ch */ /* obsolete 16-bit FWVersion */
     U16                     ProductID;                  /* 1Eh */
     U32                     CurrentHostMfaHighAddr;     /* 20h */
     U16                     GlobalCredits;              /* 24h */
@@ -146,18 +175,20 @@
     U8                      MaxDevices;                 /* 2Eh */
     U8                      MaxBuses;                   /* 2Fh */
     U32                     FWImageSize;                /* 30h */
-    U32                     DataImageSize;              /* 34h */
+    U32                     Reserved4;                  /* 34h */
+    MPI_FW_VERSION          FWVersion;                  /* 38h */
 } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
   IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
 
-#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK      (0xFF00)
-#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK      (0x00FF)
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK          (0xFF00)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK          (0x00FF)
+
+#define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
 
-#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT     (0x01)
-#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD    (0x02)
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
 
-#define MPI_IOCFACTS_EVENTSTATE_DISABLED        (0x00)
-#define MPI_IOCFACTS_EVENTSTATE_ENABLED         (0x01)
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED            (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED             (0x01)
 
 
 
@@ -326,7 +357,6 @@
 } MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY,
   EventAckReply_t, MPI_POINTER pEventAckReply_t;
 
-
 /* Switch */
 
 #define MPI_EVENT_NOTIFICATION_SWITCH_OFF   (0x00)
@@ -345,7 +375,9 @@
 #define MPI_EVENT_LOOP_STATE_CHANGE         (0x00000008)
 #define MPI_EVENT_LOGOUT                    (0x00000009)
 #define MPI_EVENT_EVENT_CHANGE              (0x0000000A)
-#define MPI_EVENT_RAID_STATUS_CHANGE        (0x0000000B)
+#define MPI_EVENT_INTEGRATED_RAID           (0x0000000B)
+#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C)
+#define MPI_EVENT_ON_BUS_TIMER_EXPIRED      (0x0000000D)
 
 /* AckRequired field values */
 
@@ -372,6 +404,27 @@
 } EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI,
   EventDataScsi_t, MPI_POINTER pEventDataScsi_t;
 
+/* SCSI Device Status Change Event data */
+
+typedef struct _EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE
+{
+    U8                      TargetID;                   /* 00h */
+    U8                      Bus;                        /* 01h */
+    U8                      ReasonCode;                 /* 02h */
+    U8                      LUN;                        /* 03h */
+    U8                      ASC;                        /* 04h */
+    U8                      ASCQ;                       /* 05h */
+    U16                     Reserved;                   /* 06h */
+} EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE,
+  MPI_POINTER PTR_EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE,
+  MpiEventDataScsiDeviceStatusChange_t,
+  MPI_POINTER pMpiEventDataScsiDeviceStatusChange_t;
+
+/* MPI SCSI Device Status Change Event data ReasonCode values */
+#define MPI_EVENT_SCSI_DEV_STAT_RC_ADDED                (0x03)
+#define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING       (0x04)
+#define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA           (0x05)
+
 /* MPI Link Status Change Event data */
 
 typedef struct _EVENT_DATA_LINK_STATUS
@@ -417,29 +470,34 @@
 } EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
   EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
 
-/* MPI RAID Status Change Event data */
+/* MPI Integrated RAID Event data */
 
-typedef struct _EVENT_DATA_RAID_STATUS_CHANGE
+typedef struct _EVENT_DATA_RAID
 {
-    U8                      VolumeTargetID;             /* 00h */
+    U8                      VolumeID;                   /* 00h */
     U8                      VolumeBus;                  /* 01h */
     U8                      ReasonCode;                 /* 02h */
     U8                      PhysDiskNum;                /* 03h */
     U8                      ASC;                        /* 04h */
     U8                      ASCQ;                       /* 05h */
     U16                     Reserved;                   /* 06h */
-} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE,
-  MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t;
-
-
-/* MPI RAID Status Change Event data ReasonCode values */
-
-#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL       (0x00)
-#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED      (0x01)
-#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC       (0x02)
-#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED           (0x03)
-#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING  (0x04)
-#define MPI_EVENT_RAID_DATA_RC_SMART_DATA           (0x05)
+    U32                     SettingsStatus;             /* 08h */
+} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID,
+  MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t;
+
+/* MPI Integrated RAID Event data ReasonCode values */
+#define MPI_EVENT_RAID_RC_VOLUME_CREATED                (0x00)
+#define MPI_EVENT_RAID_RC_VOLUME_DELETED                (0x01)
+#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED       (0x02)
+#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED         (0x03)
+#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED       (0x04)
+#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED              (0x05)
+#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED              (0x06)
+#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED     (0x07)
+#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED       (0x08)
+#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED             (0x09)
+#define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
+#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
 
 
 /*****************************************************************************
@@ -468,6 +526,7 @@
 #define MPI_FW_DOWNLOAD_ITYPE_RESERVED      (0x00)
 #define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
 #define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
+#define MPI_FW_DOWNLOAD_ITYPE_NVDATA        (0x03)
 
 
 typedef struct _FWDownloadTCSGE
@@ -476,7 +535,7 @@
     U8                      ContextSize;                /* 01h */
     U8                      DetailsLength;              /* 02h */
     U8                      Flags;                      /* 03h */
-    U32                     Reserved1;                  /* 04h */
+    U32                     Reserved_0100_Checksum;     /* 04h */ /* obsolete Checksum */
     U32                     ImageOffset;                /* 08h */
     U32                     ImageSize;                  /* 0Ch */
 } FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE,
@@ -519,7 +578,7 @@
 #define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM      (0x00)
 #define MPI_FW_UPLOAD_ITYPE_FW_FLASH        (0x01)
 #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH      (0x02)
-#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM    (0x03)
+#define MPI_FW_UPLOAD_ITYPE_NVDATA          (0x03)
 
 typedef struct _FWUploadTCSGE
 {
@@ -563,11 +622,10 @@
     U32                     Checksum;                   /* 1Ch */
     U16                     VendorId;                   /* 20h */
     U16                     ProductId;                  /* 22h */
-    U16                     FwVersion;                  /* 24h */
-    U16                     Reserved1;                  /* 26h */
+    MPI_FW_VERSION          FWVersion;                  /* 24h */
     U32                     SeqCodeVersion;             /* 28h */
     U32                     ImageSize;                  /* 2Ch */
-    U32                     Reserved2;                  /* 30h */
+    U32                     NextImageHeaderOffset;      /* 30h */
     U32                     LoadStartAddress;           /* 34h */
     U32                     IopResetVectorValue;        /* 38h */
     U32                     IopResetRegAddr;            /* 3Ch */
@@ -581,30 +639,49 @@
 #define MPI_FW_HEADER_WHAT_SIGNATURE        (0x29232840)
 
 /* defines for using the ProductId field */
-#define MPI_FW_HEADER_PID_TYPE_MASK         (0xF000)
-#define MPI_FW_HEADER_PID_TYPE_SCSI         (0x0000)
-#define MPI_FW_HEADER_PID_TYPE_FC           (0x1000)
-
-#define MPI_FW_HEADER_PID_FW_VENDOR_MASK    (0x0F00)
-#define MPI_FW_HEADER_PID_FW_VENDOR_LSI     (0x0000)
-
-#define MPI_FW_HEADER_PID_FAMILY_MASK       (0x000F)
-#define MPI_FW_HEADER_PID_FAMILY_1030_SCSI  (0x0000)
-#define MPI_FW_HEADER_PID_FAMILY_909_FC     (0x0000)
-#define MPI_FW_HEADER_PID_FAMILY_919_FC     (0x0001)
-#define MPI_FW_HEADER_PID_FAMILY_919X_FC    (0x0002)
-
-
-typedef struct _MPI_DATA_HEADER
-{
-    U32                     Signature;                  /* 00h */
-    U16                     FunctionNumber;             /* 04h */
-    U16                     Length;                     /* 06h */
-    U32                     Checksum;                   /* 08h */
-    U32                     LoadStartAddress;           /* 0Ch */
-} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER,
-  MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t;
+#define MPI_FW_HEADER_PID_TYPE_MASK             (0xF000)
+#define MPI_FW_HEADER_PID_TYPE_SCSI             (0x0000)
+#define MPI_FW_HEADER_PID_TYPE_FC               (0x1000)
+
+#define MPI_FW_HEADER_PID_PROD_MASK                     (0x0F00)
+#define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI           (0x0100)
+#define MPI_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI    (0x0200)
+#define MPI_FW_HEADER_PID_PROD_TARGET_SCSI              (0x0300)
+#define MPI_FW_HEADER_PID_PROD_IM_SCSI                  (0x0400)
+#define MPI_FW_HEADER_PID_PROD_IS_SCSI                  (0x0500)
+#define MPI_FW_HEADER_PID_PROD_CTX_SCSI                 (0x0600)
+
+#define MPI_FW_HEADER_PID_FAMILY_MASK           (0x00FF)
+#define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI    (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI    (0x0002)
+#define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI    (0x0003)
+#define MPI_FW_HEADER_PID_FAMILY_1030C0_SCSI    (0x0004)
+#define MPI_FW_HEADER_PID_FAMILY_1020A0_SCSI    (0x0005)
+#define MPI_FW_HEADER_PID_FAMILY_1020B0_SCSI    (0x0006)
+#define MPI_FW_HEADER_PID_FAMILY_1020B1_SCSI    (0x0007)
+#define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI    (0x0008)
+#define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI    (0x0009)
+#define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI    (0x000A)
+#define MPI_FW_HEADER_PID_FAMILY_909_FC         (0x0000)
+#define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002)
 
-#define MPI_DATA_HEADER_SIGNATURE           (0x43504147)
+typedef struct _MPI_EXT_IMAGE_HEADER
+{
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U16                     Reserved1;                  /* 02h */
+    U32                     Checksum;                   /* 04h */
+    U32                     ImageSize;                  /* 08h */
+    U32                     NextImageHeaderOffset;      /* 0Ch */
+    U32                     LoadStartAddress;           /* 10h */
+    U32                     Reserved2;                  /* 14h */
+} MPI_EXT_IMAGE_HEADER, MPI_POINTER PTR_MPI_EXT_IMAGE_HEADER,
+  MpiExtImageHeader_t, MPI_POINTER pMpiExtImageHeader_t;
+
+/* defines for the ImageType field */
+#define MPI_EXT_IMAGE_TYPE_UNSPECIFIED          (0x00)
+#define MPI_EXT_IMAGE_TYPE_FW                   (0x01)
+#define MPI_EXT_IMAGE_TYPE_NVDATA               (0x03)
 
 #endif
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_lan.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_lan.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_lan.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_lan.h	Fri Mar 29 14:49:34 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI LAN messages and structures
  *  Creation Date:  June 30, 2000
  *
- *    MPI Version:  01.01.03
+ *    MPI Version:  01.02.01
  *
  *  Version History
  *  ---------------
@@ -27,6 +27,7 @@
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  02-20-01  01.01.02  Started using MPI_POINTER.
  *  03-27-01  01.01.03  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
  *  --------------------------------------------------------------------------
  */
 
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_raid.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_raid.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_raid.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_raid.h	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,178 @@
+/*
+ *  Copyright (c) 2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_RAID.H
+ *          Title:  MPI RAID message and structures
+ *  Creation Date:  February 27, 2001
+ *
+ *    MPI Version:  01.02.04
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  02-27-01  01.01.01  Original release for this file.
+ *  03-27-01  01.01.02  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Major rework for MPI v1.2 Integrated RAID changes.
+ *  10-04-01  01.02.03  Added ActionData defines for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME action.
+ *  11-01-01  01.02.04  Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_RAID_H
+#define MPI_RAID_H
+
+
+/******************************************************************************
+*
+*        R A I D    M e s s a g e s
+*
+*******************************************************************************/
+
+
+/****************************************************************************/
+/* RAID Volume Request                                                      */
+/****************************************************************************/
+
+typedef struct _MSG_RAID_ACTION
+{
+    U8                      Action;             /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      VolumeID;           /* 04h */
+    U8                      VolumeBus;          /* 05h */
+    U8                      PhysDiskNum;        /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved2;          /* 0Ch */
+    U32                     ActionDataWord;     /* 10h */
+    SGE_SIMPLE_UNION        ActionDataSGE;      /* 14h */
+} MSG_RAID_ACTION_REQUEST, MPI_POINTER PTR_MSG_RAID_ACTION_REQUEST,
+  MpiRaidActionRequest_t , MPI_POINTER pMpiRaidActionRequest_t;
+
+
+/* RAID Action request Action values */
+
+#define MPI_RAID_ACTION_STATUS                      (0x00)
+#define MPI_RAID_ACTION_INDICATOR_STRUCT            (0x01)
+#define MPI_RAID_ACTION_CREATE_VOLUME               (0x02)
+#define MPI_RAID_ACTION_DELETE_VOLUME               (0x03)
+#define MPI_RAID_ACTION_DISABLE_VOLUME              (0x04)
+#define MPI_RAID_ACTION_ENABLE_VOLUME               (0x05)
+#define MPI_RAID_ACTION_QUIESCE_PHYS_IO             (0x06)
+#define MPI_RAID_ACTION_ENABLE_PHYS_IO              (0x07)
+#define MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS      (0x08)
+#define MPI_RAID_ACTION_PHYSDISK_OFFLINE            (0x0A)
+#define MPI_RAID_ACTION_PHYSDISK_ONLINE             (0x0B)
+#define MPI_RAID_ACTION_CHANGE_PHYSDISK_SETTINGS    (0x0C)
+#define MPI_RAID_ACTION_CREATE_PHYSDISK             (0x0D)
+#define MPI_RAID_ACTION_DELETE_PHYSDISK             (0x0E)
+#define MPI_RAID_ACTION_FAIL_PHYSDISK               (0x0F)
+#define MPI_RAID_ACTION_REPLACE_PHYSDISK            (0x10)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC           (0x00000001)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DELETE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
+#define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
+
+
+/* RAID Action reply message */
+
+typedef struct _MSG_RAID_ACTION_REPLY
+{
+    U8                      Action;             /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      VolumeID;           /* 04h */
+    U8                      VolumeBus;          /* 05h */
+    U8                      PhysDiskNum;        /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     ActionStatus;       /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     VolumeStatus;       /* 14h */
+    U32                     ActionData;         /* 18h */
+} MSG_RAID_ACTION_REPLY, MPI_POINTER PTR_MSG_RAID_ACTION_REPLY,
+  MpiRaidActionReply_t, MPI_POINTER pMpiRaidActionReply_t;
+
+
+/* RAID Volume reply ActionStatus values */
+
+#define MPI_RAID_ACTION_ASTATUS_SUCCESS             (0x0000)
+#define MPI_RAID_ACTION_ASTATUS_INVALID_ACTION      (0x0001)
+#define MPI_RAID_ACTION_ASTATUS_FAILURE             (0x0002)
+#define MPI_RAID_ACTION_ASTATUS_IN_PROGRESS         (0x0003)
+
+
+/* RAID Volume reply RAID Volume Indicator structure */
+
+typedef struct _MPI_RAID_VOL_INDICATOR
+{
+    U64                     TotalBlocks;        /* 00h */
+    U64                     BlocksRemaining;    /* 08h */
+} MPI_RAID_VOL_INDICATOR, MPI_POINTER PTR_MPI_RAID_VOL_INDICATOR,
+  MpiRaidVolIndicator_t, MPI_POINTER pMpiRaidVolIndicator_t;
+
+
+/****************************************************************************/
+/* SCSI IO RAID Passthrough Request                                         */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_RAID_PT_REQUEST
+{
+    U8                      PhysDiskNum;        /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      LUN[8];             /* 0Ch */
+    U32                     Control;            /* 14h */
+    U8                      CDB[16];            /* 18h */
+    U32                     DataLength;         /* 28h */
+    U32                     SenseBufferLowAddr; /* 2Ch */
+    SGE_IO_UNION            SGL;                /* 30h */
+} MSG_SCSI_IO_RAID_PT_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REQUEST,
+  SCSIIORaidPassthroughRequest_t, MPI_POINTER pSCSIIORaidPassthroughRequest_t;
+
+
+/* SCSI IO RAID Passthrough reply structure */
+
+typedef struct _MSG_SCSI_IO_RAID_PT_REPLY
+{
+    U8                      PhysDiskNum;        /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      SCSIStatus;         /* 0Ch */
+    U8                      SCSIState;          /* 0Dh */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferCount;      /* 14h */
+    U32                     SenseCount;         /* 18h */
+    U32                     ResponseInfo;       /* 1Ch */
+} MSG_SCSI_IO_RAID_PT_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REPLY,
+  SCSIIORaidPassthroughReply_t, MPI_POINTER pSCSIIORaidPassthroughReply_t;
+
+
+#endif
+
+
+
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_targ.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_targ.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_targ.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_targ.h	Fri Mar 29 14:49:34 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI Version:  01.01.04
+ *    MPI Version:  01.02.04
  *
  *  Version History
  *  ---------------
@@ -26,6 +26,14 @@
  *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
  *                      MPI_TARGET_FCP_CMD_BUFFER.
  *  03-27-01  01.01.04  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Added structure for MPI_TARGET_SCSI_SPI_STATUS_IU.
+ *                      Added PriorityReason field to some replies and
+ *                      defined more PriorityReason codes.
+ *                      Added some defines for to support previous version
+ *                      of MPI.
+ *  10-04-01  01.02.03  Added PriorityReason to MSG_TARGET_ERROR_REPLY.
+ *  11-01-01  01.02.04  Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY.
  *  --------------------------------------------------------------------------
  */
 
@@ -78,6 +86,7 @@
 #define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR       (0x80)
 
 #define CMD_BUFFER_POST_IO_INDEX_MASK           (0x00003FFF)
+#define CMD_BUFFER_POST_IO_INDEX_MASK_0100      (0x000003FF) /* obsolete */
 
 
 typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
@@ -97,7 +106,7 @@
 } MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY,
   TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t;
 
-
+/* the following structure is obsolete as of MPI v1.2 */
 typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
 {
     U16                     Reserved;                   /* 00h */
@@ -117,6 +126,13 @@
 
 #define PRIORITY_REASON_NO_DISCONNECT           (0x00)
 #define PRIORITY_REASON_SCSI_TASK_MANAGEMENT    (0x01)
+#define PRIORITY_REASON_CMD_PARITY_ERR          (0x02)
+#define PRIORITY_REASON_MSG_OUT_PARITY_ERR      (0x03)
+#define PRIORITY_REASON_LQ_CRC_ERR              (0x04)
+#define PRIORITY_REASON_CMD_CRC_ERR             (0x05)
+#define PRIORITY_REASON_PROTOCOL_ERR            (0x06)
+#define PRIORITY_REASON_DATA_OUT_PARITY_ERR     (0x07)
+#define PRIORITY_REASON_DATA_OUT_CRC_ERR        (0x08)
 #define PRIORITY_REASON_UNKNOWN                 (0xFF)
 
 
@@ -129,7 +145,8 @@
     U8                      Reserved2;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U16                     Reserved3;                  /* 0Ch */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
     U32                     ReplyWord;                  /* 14h */
@@ -204,7 +221,8 @@
     U8                      Reserved2;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U16                     Reserved3;                  /* 0Ch */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
     U32                     ReplyWord;                  /* 14h */
@@ -234,8 +252,34 @@
   TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t;
 
 #define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
+#define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY      (0x04)
 #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
 
+typedef struct _MPI_TARGET_FCP_RSP_BUFFER
+{
+    U8      Reserved0[8];                               /* 00h */
+    U8      FcpStatus;                                  /* 08h */
+    U8      FcpFlags;                                   /* 09h */
+    U8      Reserved1[2];                               /* 0Ah */
+    U32     FcpResid;                                   /* 0Ch */
+    U32     FcpSenseLength;                             /* 10h */
+    U32     FcpResponseLength;                          /* 14h */
+    U8      FcpResponseData[8];                         /* 18h */
+    U8      FcpSenseData[32]; /* Pad to 64 bytes */     /* 20h */
+} MPI_TARGET_FCP_RSP_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_RSP_BUFFER,
+  MpiTargetFcpRspBuffer, MPI_POINTER pMpiTargetFcpRspBuffer;
+
+typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU
+{
+    U8      Reserved0;                                  /* 00h */
+    U8      Reserved1;                                  /* 01h */
+    U8      Valid;                                      /* 02h */
+    U8      Status;                                     /* 03h */
+    U32     SenseDataListLength;                        /* 04h */
+    U32     PktFailuresListLength;                      /* 08h */
+    U8      SenseData[52]; /* Pad the IU to 64 bytes */ /* 0Ch */
+} MPI_TARGET_SCSI_SPI_STATUS_IU, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_STATUS_IU,
+  TargetScsiSpiStatusIU_t, MPI_POINTER pTargetScsiSpiStatusIU_t;
 
 /****************************************************************************/
 /* Target Mode Abort Request                                                */
@@ -324,6 +368,41 @@
                                     (((p) << TARGET_MODE_REPLY_PORT_SHIFT) &   \
                                                   TARGET_MODE_REPLY_PORT_MASK))
 
+/* the following obsolete values are for MPI v1.0 support */
+#define TARGET_MODE_REPLY_0100_MASK_HOST_INDEX       (0x000003FF)
+#define TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX      (0)
+#define TARGET_MODE_REPLY_0100_MASK_IOC_INDEX        (0x001FF800)
+#define TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX       (11)
+#define TARGET_MODE_REPLY_0100_PORT_MASK             (0x00400000)
+#define TARGET_MODE_REPLY_0100_PORT_SHIFT            (22)
+#define TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX  (0x1F800000)
+#define TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX (23)
+
+#define GET_HOST_INDEX_0100(x) (((x) & TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) \
+                                  >> TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX)
+
+#define SET_HOST_INDEX_0100(t, hi)                                             \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) |           \
+                         (((hi) << TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX) &  \
+                                      TARGET_MODE_REPLY_0100_MASK_HOST_INDEX))
+
+#define GET_IOC_INDEX_0100(x)   (((x) & TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) \
+                                  >> TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX)
+
+#define SET_IOC_INDEX_0100(t, ii)                                              \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) |            \
+                        (((ii) << TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX) &    \
+                                     TARGET_MODE_REPLY_0100_MASK_IOC_INDEX))
+
+#define GET_INITIATOR_INDEX_0100(x)                                            \
+            (((x) & TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX)               \
+                              >> TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX)
+
+#define SET_INITIATOR_INDEX_0100(t, ii)                                        \
+        ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX) |          \
+                   (((ii) << TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX) &   \
+                                TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX))
+
 
 #endif
 
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_tool.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_tool.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_tool.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_tool.h	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,129 @@
+/*
+ *  Copyright (c) 2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TOOL.H
+ *          Title:  MPI Toolbox structures and definitions
+ *  Creation Date:  July 30, 2001
+ *
+ *    MPI Version:  01.02.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  08-08-01  01.02.01  Original release.
+ *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TOOL_H
+#define MPI_TOOL_H
+
+#define MPI_TOOLBOX_CLEAN_TOOL                      (0x00)
+#define MPI_TOOLBOX_MEMORY_MOVE_TOOL                (0x01)
+#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL           (0x02)
+
+
+/****************************************************************************/
+/* Toolbox reply                                                            */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_REPLY
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved3;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY,
+  ToolboxReply_t, MPI_POINTER pToolboxReply_t;
+
+
+/****************************************************************************/
+/* Toolbox Clean Tool request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_CLEAN_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Flags;                      /* 0Ch */
+} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST,
+  ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t;
+
+#define MPI_TOOLBOX_CLEAN_NVSRAM                    (0x00000001)
+#define MPI_TOOLBOX_CLEAN_SEEPROM                   (0x00000002)
+#define MPI_TOOLBOX_CLEAN_FLASH                     (0x00000004)
+
+
+/****************************************************************************/
+/* Toolbox Memory Move request                                              */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    SGE_SIMPLE_UNION        SGL;                        /* 0Ch */
+} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST,
+  ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t;
+
+
+/****************************************************************************/
+/* Toolbox Diagnostic Data Upload request                                   */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Flags;                      /* 0Ch */
+    U32                     Reserved3;                  /* 10h */
+    SGE_SIMPLE_UNION        SGL;                        /* 14h */
+} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t;
+
+typedef struct _DIAG_DATA_UPLOAD_HEADER
+{
+    U32                     DiagDataLength;             /* 00h */
+    U8                      FormatCode;                 /* 04h */
+    U8                      Reserved;                   /* 05h */
+    U16                     Reserved1;                  /* 06h */
+} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER,
+  DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t;
+
+#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1            (0x01)
+#define MPI_TB_DIAG_FORMAT_SCSI_2                   (0x02)
+#define MPI_TB_DIAG_FORMAT_SCSI_3                   (0x03)
+#define MPI_TB_DIAG_FORMAT_FC_TRACE_1               (0x04)
+
+
+#endif
+
+
diff -urN linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_type.h linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_type.h
--- linux-2.4.19-pre4/drivers/message/fusion/lsi/mpi_type.h	Fri Jul  6 17:03:11 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/lsi/mpi_type.h	Fri Mar 29 14:49:34 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Basic type definitions
  *  Creation Date:  June 6, 2000
  *
- *    MPI Version:  01.01.02
+ *    MPI Version:  01.02.01
  *
  *  Version History
  *  ---------------
@@ -17,6 +17,7 @@
  *  06-06-00  01.00.01  Update version number for 1.0 release.
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
  *  --------------------------------------------------------------------------
  */
 
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptbase.c linux-2.4.19-pre5/drivers/message/fusion/mptbase.c
--- linux-2.4.19-pre4/drivers/message/fusion/mptbase.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptbase.c	Fri Mar 29 14:49:34 2002
@@ -20,6 +20,12 @@
  *      And to Roger Hickerson (LSI Logic) for tirelessly supporting
  *      this driver project.
  *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
  *      All manner of help from Stephen Shirron (LSI Logic):
  *      low-level FC analysis, debug + various fixes in FCxx firmware,
  *      initial port to alpha platform, various driver code optimizations,
@@ -38,11 +44,12 @@
  *      for gobs of hard work fixing and optimizing LAN code.
  *      THANK YOU!
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.53.4.3 2001/09/18 03:54:54 sralston Exp $
+ *  $Id: mptbase.c,v 1.110 2002/02/27 18:44:20 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -93,11 +100,14 @@
 #include <linux/kdev_t.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
-#include <linux/proc_fs.h>
+#include <linux/interrupt.h>		/* needed for in_interrupt() proto */
 #include <asm/io.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
+#ifdef __sparc__
+#include <asm/irq.h>			/* needed for __irq_itoa() proto */
+#endif
 
 #include "mptbase.h"
 
@@ -110,27 +120,33 @@
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
 
-
 /*
  *  cmd line parameters
  */
 MODULE_PARM(PortIo, "0-1i");
 MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
-MODULE_PARM(HardReset, "0-1i");
-MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset");
 static int PortIo = 0;
-static int HardReset = 1;
+
+#ifdef MFCNT
+static int mfcounter = 0;
+#define PRINT_MF_COUNT 20000
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Public data...
  */
-int mpt_lan_index = 0;
-int mpt_stm_index = 0;
+int mpt_lan_index = -1;
+int mpt_stm_index = -1;
+
+struct proc_dir_entry *mpt_proc_root_dir;
+
+DmpServices_t *DmpService;
+
+void *mpt_v_ASCQ_TablePtr;
+const char **mpt_ScsiOpcodesPtr;
+int mpt_ASCQ_TableSz;
 
-void *mpt_v_ASCQ_TablePtr = NULL;
-const char **mpt_ScsiOpcodesPtr = NULL;
-int mpt_ASCQ_TableSz = 0;
 
 #define WHOINIT_UNKNOWN		0xAA
 
@@ -139,12 +155,12 @@
  *  Private data...
  */
 					/* Adapter lookup table */
-static MPT_ADAPTER		*mpt_adapters[MPT_MAX_ADAPTERS] = {0};
+       MPT_ADAPTER		*mpt_adapters[MPT_MAX_ADAPTERS];
 static MPT_ADAPTER_TRACKER	 MptAdapters;
 					/* Callback lookup table */
 static MPT_CALLBACK		 MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
 					/* Protocol driver class lookup table */
-static int	 		 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
+static int			 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
 					/* Event handler lookup table */
 static MPT_EVHANDLER		 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 					/* Reset handler lookup table */
@@ -152,6 +168,10 @@
 
 static int	FusionInitCalled = 0;
 static int	mpt_base_index = -1;
+static int	last_drv_idx = -1;
+static int	isense_idx = -1;
+
+static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -160,49 +180,84 @@
 static void	mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
 static int	mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
 
-static int 	mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason);
-static int 	mpt_adapter_install(struct pci_dev *pdev);
-static void	mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static int	mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
+static int	mpt_adapter_install(struct pci_dev *pdev);
+static void	mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
 static void	mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup);
 static void	mpt_adapter_dispose(MPT_ADAPTER *ioc);
 
 static void	MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
-static int	MakeIocReady(MPT_ADAPTER *ioc, int force);
-static u32	GetIocState(MPT_ADAPTER *ioc, int cooked);
-static int	GetIocFacts(MPT_ADAPTER *ioc);
-static int	GetPortFacts(MPT_ADAPTER *ioc, int portnum);
-static int	SendIocInit(MPT_ADAPTER *ioc);
-static int	SendPortEnable(MPT_ADAPTER *ioc, int portnum);
-static int	mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore);
-static int	KickStart(MPT_ADAPTER *ioc, int ignore);
-static int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
+static int	MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
+//static u32	mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int	GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
+static int	GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int	SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
+static int	SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int	mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
+static int	mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);
+static int	mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int	KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
 static int	PrimeIocFifos(MPT_ADAPTER *ioc);
-static int	HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait);
-static int	WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong);
-static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong);
-static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong);
+static int	WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int	GetLanConfigPages(MPT_ADAPTER *ioc);
+static int	GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
+static int	GetIoUnitPage2(MPT_ADAPTER *ioc);
+static int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
+static int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
+static int	mpt_findImVolumes(MPT_ADAPTER *ioc);
+static void	mpt_timer_expired(unsigned long data);
 static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
 static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
 
-static int	procmpt_create(void);
 #ifdef CONFIG_PROC_FS
+static int	procmpt_create(void);
 static int	procmpt_destroy(void);
+static int	procmpt_summary_read(char *buf, char **start, off_t offset,
+				int request, int *eof, void *data);
+static int	procmpt_version_read(char *buf, char **start, off_t offset,
+				int request, int *eof, void *data);
+static int	procmpt_iocinfo_read(char *buf, char **start, off_t offset,
+				int request, int *eof, void *data);
 #endif
-static int	procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int	procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data);
-/*static int	procmpt_info(char *buf, char **start, off_t offset, int len);*/
+static void	mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
 
+//int		mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 static int	ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
 static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void	mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
 
-static struct proc_dir_entry	*procmpt_root_dir = NULL;
-
 int		fusion_init(void);
 static void	fusion_exit(void);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  more Private data...
+ */
+#ifdef CONFIG_PROC_FS
+struct _mpt_proc_list {
+	const char	*name;
+	int		(*f)(char *, char **, off_t, int, int *, void *);
+} mpt_proc_list[] = {
+	{ "summary", procmpt_summary_read},
+	{ "version", procmpt_version_read},
+};
+#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0]))
+
+struct _mpt_ioc_proc_list {
+	const char	*name;
+	int		(*f)(char *, char **, off_t, int, int *, void *);
+} mpt_ioc_proc_list[] = {
+	{ "info", procmpt_iocinfo_read},
+	{ "summary", procmpt_summary_read},
+};
+#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0]))
+
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* 20000207 -sralston
  *  GRRRRR...  IOSpace (port i/o) register access (for the 909) is back!
  * 20000517 -sralston
@@ -225,9 +280,18 @@
 		writel(v, a);
 }
 
+static inline void CHIPREG_PIO_WRITE32(volatile u32 *a, u32 v)
+{
+	outl(v, (unsigned long)a);
+}
+
+static inline u32 CHIPREG_PIO_READ32(volatile u32 *a)
+{
+	return inl((unsigned long)a);
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
  *	@irq: irq number (not used)
  *	@bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
@@ -252,8 +316,7 @@
 	MPT_FRAME_HDR	*mf;
 	MPT_FRAME_HDR	*mr;
 	u32		 pa;
-	u32		*m;
-	int		 req_idx;
+	int		 req_idx = -1;
 	int		 cb_idx;
 	int		 type;
 	int		 freeme;
@@ -262,6 +325,21 @@
 	ioc = bus_id;
 
 	/*
+	 * Verify ioc pointer is ok
+	 */
+	{
+		MPT_ADAPTER	*iocCmp;
+		iocCmp = mpt_adapter_find_first();
+		while ((ioc != iocCmp)  && iocCmp)
+			iocCmp = mpt_adapter_find_next(iocCmp);
+
+		if (!iocCmp) {
+			printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n");
+			return;
+		}
+	}
+
+	/*
 	 *  Drain the reply FIFO!
 	 *
 	 * NOTES: I've seen up to 10 replies processed in this loop, so far...
@@ -281,25 +359,27 @@
 		 *  Check for non-TURBO reply!
 		 */
 		if (pa & MPI_ADDRESS_REPLY_A_BIT) {
-			dma_addr_t reply_dma_addr;
+			u32 reply_dma_low;
 			u16 ioc_stat;
 
 			/* non-TURBO reply!  Hmmm, something may be up...
 			 *  Newest turbo reply mechanism; get address
 			 *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
 			 */
-			reply_dma_addr = (pa = (pa << 1));
 
-			/* Map DMA address of reply header to cpu address. */
-			m = (u32 *) ((u8 *)ioc->reply_frames +
-					(reply_dma_addr - ioc->reply_frames_dma));
+			/* Map DMA address of reply header to cpu address.
+			 * pa is 32 bits - but the dma address may be 32 or 64 bits
+			 * get offset based only only the low addresses
+			 */
+			reply_dma_low = (pa = (pa << 1));
+			mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
+					 (reply_dma_low - ioc->reply_frames_low_dma));
 
-			mr = (MPT_FRAME_HDR *) m;
 			req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
 			cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
 			mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
 
-			dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n",
+			dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n",
 					ioc->name, mr));
 			DBG_DUMP_REPLY_FRAME(mr)
 
@@ -307,7 +387,7 @@
 			 *  Check/log IOC log info
 			 */
 			ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
-	 		if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+			if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
 				u32	 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
 				if ((int)ioc->chip_type <= (int)FC929)
 					mpt_fc_log_info(ioc, log_info);
@@ -318,7 +398,7 @@
 			/*
 			 *  Process turbo (context) reply...
 			 */
-			dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa));
+			dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa));
 			type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
 			if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
 				cb_idx = mpt_stm_index;
@@ -357,6 +437,34 @@
 			pa = 0;					/* No reply flush! */
 		}
 
+		if ((int)ioc->chip_type > (int)FC929) {
+			/* Verify mf, mf are reasonable.
+			 */
+			if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
+				|| (mf < ioc->req_frames)) ) {
+				printk(MYIOC_s_WARN_FMT 
+					"mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, mf, req_idx);
+				cb_idx = 0;
+				pa = 0;
+				freeme = 0;
+			}
+			if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
+				|| (mr < ioc->reply_frames)) ) {
+				printk(MYIOC_s_WARN_FMT 
+					"mpt_interrupt: Invalid rf (%p)!\n", ioc->name, mr);
+				cb_idx = 0;
+				pa = 0;
+				freeme = 0;
+			}
+			if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
+				printk(MYIOC_s_WARN_FMT 
+					"mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
+				cb_idx = 0;
+				pa = 0;
+				freeme = 0;
+			}
+		}
+
 		/*  Check for (valid) IO callback!  */
 		if (cb_idx) {
 			/*  Do the callback!  */
@@ -374,15 +482,18 @@
 			/*  Put Request back on FreeQ!  */
 			spin_lock_irqsave(&ioc->FreeQlock, flags);
 			Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+			ioc->mfcnt--;
+#endif
 			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 		}
 
 		count++;
-		dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count));
+		dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count));
 		mb();
 
 		if (count >= MPT_MAX_REPLIES_PER_ISR) {
-			dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.",
+			dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.",
 					ioc->name, count));
 			dirqprintk((" Giving this ISR a break!\n"));
 			return;
@@ -409,17 +520,17 @@
 	int freereq = 1;
 	u8 func;
 
-	dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name));
+	dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
 
 	if ((mf == NULL) ||
 	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-		printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n",
+		printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
 				ioc->name, mf);
 		return 1;
 	}
 
 	if (reply == NULL) {
-		dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n",
+		dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
 				ioc->name));
 		return 1;
 	}
@@ -430,7 +541,7 @@
 	}
 
 	func = reply->u.hdr.Function;
-	dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n",
+	dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
 			ioc->name, func));
 
 	if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
@@ -441,30 +552,77 @@
 		results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
 		if (results != evHandlers) {
 			/* CHECKME! Any special handling needed here? */
-			dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n",
+			dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
 					ioc->name, evHandlers, results));
 		}
 
 		/*
-		 *  Hmmm...  It seems that EventNotificationReply is an exception
-		 *  to the rule of one reply per request.
+		 *	Hmmm...  It seems that EventNotificationReply is an exception
+		 *	to the rule of one reply per request.
 		 */
 		if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
 			freereq = 0;
+
 #ifdef CONFIG_PROC_FS
 //		LogEvent(ioc, pEvReply);
 #endif
+
 	} else if (func == MPI_FUNCTION_EVENT_ACK) {
-		dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n",
+		dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
 				ioc->name));
+	} else if (func == MPI_FUNCTION_CONFIG) {
+		CONFIGPARMS *pCfg;
+		unsigned long flags;
+
+		dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+				ioc->name, mf, reply));
+
+		pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
+
+		if (pCfg) {
+			/* disable timer and remove from linked list */
+			del_timer(&pCfg->timer);
+
+			spin_lock_irqsave(&ioc->FreeQlock, flags);
+			Q_DEL_ITEM(&pCfg->linkage);
+			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+			/*
+			 *	If IOC Status is SUCCESS, save the header
+			 *	and set the status code to GOOD.
+			 */
+			pCfg->status = MPT_CONFIG_ERROR;
+			if (reply) {
+				ConfigReply_t	*pReply = (ConfigReply_t *)reply;
+				u16		 status;
+
+				status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+				dprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+				     status, le32_to_cpu(pReply->IOCLogInfo)));
+
+				pCfg->status = status;
+				if (status == MPI_IOCSTATUS_SUCCESS) {
+					pCfg->hdr->PageVersion = pReply->Header.PageVersion;
+					pCfg->hdr->PageLength = pReply->Header.PageLength;
+					pCfg->hdr->PageNumber = pReply->Header.PageNumber;
+					pCfg->hdr->PageType = pReply->Header.PageType;
+				}
+			}
+
+			/*
+			 *	Wake up the original calling thread
+			 */
+			pCfg->wait_done = 1;
+			wake_up(&mpt_waitq);
+		}
 	} else {
-		printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n",
+		printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
 				ioc->name, func);
 	}
 
 	/*
-	 *  Conditionally tell caller to free the original
-	 *  EventNotification/EventAck/unexpected request frame!
+	 *	Conditionally tell caller to free the original
+	 *	EventNotification/EventAck/unexpected request frame!
 	 */
 	return freereq;
 }
@@ -480,21 +638,22 @@
  *	protocol-specific driver must do this before it will be able to
  *	use any IOC resources, such as obtaining request frames.
  *
- *	NOTES: The SCSI protocol driver currently calls this routine twice
- *	in order to register separate callbacks; one for "normal" SCSI IO
- *	and another for MptScsiTaskMgmt requests.
+ *	NOTES: The SCSI protocol driver currently calls this routine thrice
+ *	in order to register separate callbacks; one for "normal" SCSI IO;
+ *	one for MptScsiTaskMgmt requests; one for Scan/DV requests.
  *
  *	Returns a positive integer valued "handle" in the
- *	range (and S.O.D. order) {7,6,...,1} if successful.
+ *	range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
  *	Any non-positive return value (including zero!) should be considered
  *	an error by the caller.
  */
 int
 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
 {
-	int r = -1;
 	int i;
 
+	last_drv_idx = -1;
+
 #ifndef MODULE
 	/*
 	 *  Handle possibility of the mptscsih_detect() routine getting
@@ -512,7 +671,7 @@
 #endif
 
 	/*
-	 *  Search for empty callback slot in this order: {7,6,...,1}
+	 *  Search for empty callback slot in this order: {N,...,7,6,5,...,1}
 	 *  (slot/handle 0 is reserved!)
 	 */
 	for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
@@ -520,7 +679,7 @@
 			MptCallbacks[i] = cbfunc;
 			MptDriverClass[i] = dclass;
 			MptEvHandlers[i] = NULL;
-			r = i;
+			last_drv_idx = i;
 			if (cbfunc != mpt_base_reply) {
 				MOD_INC_USE_COUNT;
 			}
@@ -528,7 +687,7 @@
 		}
 	}
 
-	return r;
+	return last_drv_idx;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -546,6 +705,11 @@
 		MptCallbacks[cb_idx] = NULL;
 		MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
 		MptEvHandlers[cb_idx] = NULL;
+
+		last_drv_idx++;
+		if (isense_idx != -1 && isense_idx <= cb_idx)
+			isense_idx++;
+
 		if (cb_idx != mpt_base_index) {
 			MOD_DEC_USE_COUNT;
 		}
@@ -639,7 +803,8 @@
  *	@handle: Handle of registered MPT protocol driver
  *	@iocid: IOC unique identifier (integer)
  *
- *	Returns pointer to a MPT request frame or %NULL if none are available.
+ *	Returns pointer to a MPT request frame or %NULL if none are available
+ *	or IOC is not active.
  */
 MPT_FRAME_HDR*
 mpt_get_msg_frame(int handle, int iocid)
@@ -650,6 +815,16 @@
 
 	/* validate handle and ioc identifier */
 	iocp = mpt_adapters[iocid];
+
+#ifdef MFCNT
+	if (!iocp->active)
+		printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+#endif
+
+	/* If interrupts are not attached, do not return a request frame */
+	if (!iocp->active)
+		return NULL;
+
 	spin_lock_irqsave(&iocp->FreeQlock, flags);
 	if (! Q_IS_EMPTY(&iocp->FreeQ)) {
 		int req_offset;
@@ -662,8 +837,20 @@
 		mf->u.frame.hwhdr.msgctxu.fld.req_idx =
 				cpu_to_le16(req_offset / iocp->req_sz);
 		mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+#ifdef MFCNT
+		iocp->mfcnt++;
+#endif
 	}
 	spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+
+#ifdef MFCNT
+	if (mf == NULL)
+		printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth);
+	mfcounter++;
+	if (mfcounter == PRINT_MF_COUNT)
+		printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth);
+#endif
+
 	dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
 			iocp->name, handle, iocid, mf));
 	return mf;
@@ -687,7 +874,7 @@
 
 	iocp = mpt_adapters[iocid];
 	if (iocp != NULL) {
-		dma_addr_t mf_dma_addr;
+		u32 mf_dma_addr;
 		int req_offset;
 
 		/* ensure values are reset properly! */
@@ -700,23 +887,23 @@
 #ifdef MPT_DEBUG_MSG_FRAME
 		{
 			u32	*m = mf->u.frame.hwhdr.__hdr;
-			int	 i, n;
+			int	 ii, n;
 
 			printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
 					iocp->name, m);
 			n = iocp->req_sz/4 - 1;
 			while (m[n] == 0)
 				n--;
-			for (i=0; i<=n; i++) {
-				if (i && ((i%8)==0))
+			for (ii=0; ii<=n; ii++) {
+				if (ii && ((ii%8)==0))
 					printk("\n" KERN_INFO " ");
-				printk(" %08x", le32_to_cpu(m[i]));
+				printk(" %08x", le32_to_cpu(m[ii]));
 			}
 			printk("\n");
 		}
 #endif
 
-		mf_dma_addr = iocp->req_frames_dma + req_offset;
+		mf_dma_addr = iocp->req_frames_low_dma + req_offset;
 		CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
 	}
 }
@@ -742,6 +929,9 @@
 		/*  Put Request back on FreeQ!  */
 		spin_lock_irqsave(&iocp->FreeQlock, flags);
 		Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+		iocp->mfcnt--;
+#endif
 		spin_unlock_irqrestore(&iocp->FreeQlock, flags);
 	}
 }
@@ -754,8 +944,9 @@
  *	@iocid: IOC unique identifier (integer)
  *	@reqBytes: Size of the request in bytes
  *	@req: Pointer to MPT request frame
+ *	@sleepFlag: Use schedule if CAN_SLEEP else use udelay.
  *
- *	This routine is used exclusively by mptscsih to send MptScsiTaskMgmt
+ *	This routine is used exclusively to send MptScsiTaskMgmt
  *	requests since they are required to be sent via doorbell handshake.
  *
  *	NOTE: It is the callers responsibility to byte-swap fields in the
@@ -764,41 +955,30 @@
  *	Returns 0 for success, non-zero for failure.
  */
 int
-mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag)
 {
 	MPT_ADAPTER	*iocp;
 	int		 r = 0;
 
 	iocp = mpt_adapters[iocid];
 	if (iocp != NULL) {
-		u8		*req_as_bytes;
-		u32		 ioc_raw_state;
-		int		 i;
-
-		/* YIKES!  We already know something is amiss.
-		 * Do upfront check on IOC state.
-		 */
-		ioc_raw_state = GetIocState(iocp, 0);
-		if ((ioc_raw_state & MPI_DOORBELL_ACTIVE) ||
-		    ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)) {
-			printk(KERN_WARNING MYNAM ": %s: Bad IOC state (%08x) WARNING!\n",
-					iocp->name, ioc_raw_state);
-			if ((r = mpt_do_ioc_recovery(iocp, MPT_HOSTEVENT_IOC_RECOVER)) != 0) {
-				printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
-						r, iocp->name);
-				return r;
-			}
-		}
+		u8	*req_as_bytes;
+		int	 ii;
+
+		/* State is known to be good upon entering
+		 * this function so issue the bus reset
+		 * request.
+		 */
 
 		/*
 		 * Emulate what mpt_put_msg_frame() does /wrt to sanity
 		 * setting cb_idx/req_idx.  But ONLY if this request
 		 * is in proper (pre-alloc'd) request buffer range...
 		 */
-		i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
-		if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) {
+		ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+		if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) {
 			MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
-			mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i);
+			mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
 			mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
 		}
 
@@ -810,36 +990,40 @@
 				 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
 
 		/* Wait for IOC doorbell int */
-		if ((i = WaitForDoorbellInt(iocp, 2)) < 0) {
-			return i;
+		if ((ii = WaitForDoorbellInt(iocp, 2, sleepFlag)) < 0) {
+			return ii;
 		}
 
+		/* Read doorbell and check for active bit */
+		if (!(CHIPREG_READ32(&iocp->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+				return -5;
+
 		dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
-				iocp->name, i));
+				iocp->name, ii));
 
 		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 
-		if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
+		if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
 			return -2;
 		}
 
 		/* Send request via doorbell handshake */
 		req_as_bytes = (u8 *) req;
-		for (i = 0; i < reqBytes/4; i++) {
+		for (ii = 0; ii < reqBytes/4; ii++) {
 			u32 word;
 
-			word = ((req_as_bytes[(i*4) + 0] <<  0) |
-				(req_as_bytes[(i*4) + 1] <<  8) |
-				(req_as_bytes[(i*4) + 2] << 16) |
-				(req_as_bytes[(i*4) + 3] << 24));
+			word = ((req_as_bytes[(ii*4) + 0] <<  0) |
+				(req_as_bytes[(ii*4) + 1] <<  8) |
+				(req_as_bytes[(ii*4) + 2] << 16) |
+				(req_as_bytes[(ii*4) + 3] << 24));
 			CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
-			if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
+			if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
 				r = -3;
 				break;
 			}
 		}
 
-		if ((r = WaitForDoorbellInt(iocp, 2)) >= 0)
+		if ((r = WaitForDoorbellInt(iocp, 10, sleepFlag)) >= 0)
 			r = 0;
 		else
 			r = -4;
@@ -871,8 +1055,8 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- * 	mpt_adapter_find_next - Find next MPT adapter pointer.
- * 	@prev: Pointer to previous MPT adapter
+ *	mpt_adapter_find_next - Find next MPT adapter pointer.
+ *	@prev: Pointer to previous MPT adapter
  *
  *	Returns next MPT adapter pointer or %NULL if there are no more.
  */
@@ -888,13 +1072,13 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	mpt_pci_scan - Scan PCI devices for MPT adapters.
  *
  *	Returns count of MPT adapters found, keying off of PCI vendor and
  *	device_id's.
  */
-int __init
+static int __init
 mpt_pci_scan(void)
 {
 	struct pci_dev *pdev;
@@ -906,7 +1090,7 @@
 	dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
 
 	/*
-	 *  NOTE: The 929 (I believe) will appear as 2 separate PCI devices,
+	 *  NOTE: The 929 and 1030 will appear as 2 separate PCI devices,
 	 *  one for each channel.
 	 */
 	pci_for_each_dev(pdev) {
@@ -917,9 +1101,9 @@
 		if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
 #if 0
 		    /* FIXME! C103x family */
-		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) &&
 #endif
@@ -929,7 +1113,7 @@
 		}
 
 		/* GRRRRR
-		 * 929 dual function devices may be presented in Func 1,0 order,
+		 * dual function devices (929, 1030) may be presented in Func 1,0 order,
 		 * but we'd really really rather have them in Func 0,1 order.
 		 * Do some kind of look ahead here...
 		 */
@@ -937,11 +1121,11 @@
 			pdev2 = pci_peek_next_dev(pdev);
 			if (pdev2 && (pdev2->vendor == 0x1000) &&
 			    (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
-			    (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+			    (pdev2->device == pdev->device) &&
 			    (pdev2->bus->number == pdev->bus->number) &&
 			    !(pdev2->devfn & 1)) {
 				dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
-			 		pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
+					pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
 				found++;
 				if ((r = mpt_adapter_install(pdev2)) == 0)
 					count++;
@@ -969,9 +1153,7 @@
 	}
 
 #ifdef CONFIG_PROC_FS
-	if (procmpt_create() != 0)
-		printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n",
-				MPT_PROCFS_MPTBASEDIR);
+	(void) procmpt_create();
 #endif
 
 	return count;
@@ -1004,7 +1186,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	mpt_adapter_install - Install a PCI intelligent MPT adapter.
  *	@pdev: Pointer to pci_dev structure
  *
@@ -1030,7 +1212,7 @@
 	unsigned long	 port;
 	u32		 msize;
 	u32		 psize;
-	int		 i;
+	int		 ii;
 	int		 r = -ENODEV;
 	int		 len;
 
@@ -1040,41 +1222,68 @@
 		return -ENOMEM;
 	}
 	memset(ioc, 0, sizeof(*ioc));
-	ioc->req_sz = MPT_REQ_SIZE;			/* avoid div by zero! */
 	ioc->alloc_total = sizeof(MPT_ADAPTER);
+	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
+	ioc->reply_sz = ioc->req_sz;
 
 	ioc->pcidev = pdev;
+	ioc->diagPending = 0;
+	spin_lock_init(&ioc->diagLock);
+
+	/* Initialize the event logging.
+	 */
+	ioc->eventTypes = 0;	/* None */
+	ioc->eventContext = 0;
+	ioc->eventLogSize = 0;
+	ioc->events = NULL;
+
+#ifdef MFCNT
+	ioc->mfcnt = 0;
+#endif
+
+	/* Initialize the FW and Data image pointers.
+	 */
+	ioc->FWImage = NULL;
+	ioc->FWImage_dma = 0;
+
+	/* Initilize SCSI Config Data structure
+	 */
+	memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
+
+	/* Initialize the running configQ head.
+	 */
+	Q_INIT(&ioc->configQ, Q_ITEM);
 
 	/* Find lookup slot. */
-	for (i=0; i < MPT_MAX_ADAPTERS; i++) {
-		if (mpt_adapters[i] == NULL) {
-			ioc->id = i;		/* Assign adapter unique id (lookup) */
+	for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) {
+		if (mpt_adapters[ii] == NULL) {
+			ioc->id = ii;		/* Assign adapter unique id (lookup) */
 			break;
 		}
 	}
-	if (i == MPT_MAX_ADAPTERS) {
-		printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i);
+	if (ii == MPT_MAX_ADAPTERS) {
+		printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii);
 		kfree(ioc);
 		return -ENFILE;
 	}
 
 	mem_phys = msize = 0;
 	port = psize = 0;
-	for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
-		if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) {
+	for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
+		if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* Get I/O space! */
-			port = pdev->PCI_BASEADDR_START(i);
-			psize = PCI_BASEADDR_SIZE(pdev,i);
+			port = pdev->PCI_BASEADDR_START(ii);
+			psize = PCI_BASEADDR_SIZE(pdev,ii);
 		} else {
 			/* Get memmap */
-			mem_phys = pdev->PCI_BASEADDR_START(i);
-			msize = PCI_BASEADDR_SIZE(pdev,i);
+			mem_phys = pdev->PCI_BASEADDR_START(ii);
+			msize = PCI_BASEADDR_SIZE(pdev,ii);
 			break;
 		}
 	}
 	ioc->mem_size = msize;
 
-	if (i == DEVICE_COUNT_RESOURCE) {
+	if (ii == DEVICE_COUNT_RESOURCE) {
 		printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
 		kfree(ioc);
 		return -EINVAL;
@@ -1098,6 +1307,8 @@
 	}
 	dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
 
+	dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
+			&ioc->facts, &ioc->pfacts[0]));
 	if (PortIo) {
 		u8 *pmem = (u8*)port;
 		ioc->mem_phys = port;
@@ -1107,6 +1318,13 @@
 		ioc->chip = (SYSIF_REGS*)mem;
 	}
 
+	/* Save Port IO values incase we need to do downloadboot */
+	{
+		u8 *pmem = (u8*)port;
+		ioc->pio_mem_phys = port;
+		ioc->pio_chip = (SYSIF_REGS*)pmem;
+	}
+
 	ioc->chip_type = FCUNK;
 	if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
 		ioc->chip_type = FC909;
@@ -1120,12 +1338,19 @@
 		ioc->chip_type = FC919;
 		ioc->prod_name = "LSIFC919";
 	}
-#if 0
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->chip_type = C1030;
 		ioc->prod_name = "LSI53C1030";
+		{
+			/* 1030 Chip Fix. Disable Split transactions
+			 * for PCIX. Set bits 4 - 6 to zero.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF8F;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
-#endif
 
 	myname = "iocN";
 	len = strlen(myname);
@@ -1145,8 +1370,13 @@
 		r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
 
 		if (r < 0) {
-			printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n",
+#ifndef __sparc__
+			printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
 					ioc->name, pdev->irq);
+#else
+			printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
+					ioc->name, __irq_itoa(pdev->irq));
+#endif
 			iounmap(mem);
 			kfree(ioc);
 			return -EBUSY;
@@ -1156,7 +1386,11 @@
 
 		pci_set_master(pdev);			/* ?? */
 
+#ifndef __sparc__
 		dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+#else
+		dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
+#endif
 	}
 
 	/* tack onto tail of our MPT adapter list */
@@ -1166,12 +1400,12 @@
 	mpt_adapters[ioc->id] = ioc;
 
 	/* NEW!  20010220 -sralston
-	 * Check for "929 bound ports" to reduce redundant resets.
+	 * Check for "bound ports" (929, 1030) to reduce redundant resets.
 	 */
-	if (ioc->chip_type == FC929)
-		mpt_detect_929_bound_ports(ioc, pdev);
+	if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030))
+		mpt_detect_bound_ports(ioc, pdev);
 
-	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) {
+	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
 		printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
 				ioc->name, r);
 	}
@@ -1180,10 +1414,11 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	mpt_do_ioc_recovery - Initialize or recover MPT adapter.
  *	@ioc: Pointer to MPT adapter structure
  *	@reason: Event word / reason
+ *	@sleepFlag: Use schedule if CAN_SLEEP else use udelay.
  *
  *	This routine performs all the steps necessary to bring the IOC
  *	to a OPERATIONAL state.
@@ -1191,16 +1426,21 @@
  *	This routine also pre-fetches the LAN MAC address of a Fibre Channel
  *	MPT adapter.
  *
- *	Returns 0 for success.
+ *	Returns:
+ *		 0 for success
+ *		-1 if failed to get board READY
+ *		-2 if READY but IOCFacts Failed
+ *		-3 if READY but PrimeIOCFifos Failed
+ *		-4 if READY but IOCInit Failed
  */
 static int
-mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason)
+mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 {
 	int	 hard_reset_done = 0;
 	int	 alt_ioc_ready = 0;
 	int	 hard;
 	int	 r;
-	int	 i;
+	int	 ii;
 	int	 handlers;
 
 	printk(KERN_INFO MYNAM ": Initiating %s %s\n",
@@ -1211,156 +1451,106 @@
 	ioc->active = 0;
 	/* NOTE: Access to IOC's request FreeQ is now blocked! */
 
-// FIXME? Cleanup all IOC requests here! (or below?)
-// But watch out for event associated request?
+	if (ioc->alt_ioc) {
+		/* Disable alt-IOC's reply interrupts for a bit ... */
+		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
+		ioc->alt_ioc->active = 0;
+		/* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
+	}
 
-	hard = HardReset;
-	if (ioc->alt_ioc && (reason == MPT_HOSTEVENT_IOC_BRINGUP))
+	hard = 1;
+	if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
 		hard = 0;
 
-	if ((hard_reset_done = MakeIocReady(ioc, hard)) < 0) {
+	if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
 		printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
 				ioc->name);
 		return -1;
 	}
 
-// NEW!
-#if 0						// Kiss-of-death!?!
-	if (ioc->alt_ioc) {
-// Grrr... Hold off any alt-IOC interrupts (and events) while
-// handshaking to <this> IOC, needed because?
-		/* Disable alt-IOC's reply interrupts for a bit ... */
-		alt_ioc_intmask = CHIPREG_READ32(&ioc->alt_ioc->chip->IntMask);
-		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
-		ioc->alt_ioc->active = 0;
-		/* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
-	}
-#endif
-
+	/* hard_reset_done = 0 if a soft reset was performed
+	 * and 1 if a hard reset was performed.
+	 */
 	if (hard_reset_done && ioc->alt_ioc) {
-		if ((r = MakeIocReady(ioc->alt_ioc, 0)) == 0)
+		if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
 			alt_ioc_ready = 1;
 		else
-			printk(KERN_WARNING MYNAM ": alt-%s: (%d) Not ready WARNING!\n",
+			printk(KERN_WARNING MYNAM
+					": alt-%s: (%d) Not ready WARNING!\n",
 					ioc->alt_ioc->name, r);
 	}
 
+	/* Get IOC facts! */
+	if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
+		return -2;
 	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
-		/* Get IOC facts! */
-		if ((r = GetIocFacts(ioc)) != 0)
-			return -2;
 		MptDisplayIocCapabilities(ioc);
 	}
 
-	/*
-	 * Call each currently registered protocol IOC reset handler
-	 * with pre-reset indication.
-	 * NOTE: If we're doing _IOC_BRINGUP, there can be no
-	 * MptResetHandlers[] registered yet.
-	 */
-	if (hard_reset_done) {
-		r = handlers = 0;
-		for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
-			if (MptResetHandlers[i]) {
-				dprintk((KERN_INFO MYNAM ": %s: Calling IOC pre_reset handler #%d\n",
-						ioc->name, i));
-				r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_PRE_RESET);
-				handlers++;
-
-				if (alt_ioc_ready) {
-					dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC pre_reset handler #%d\n",
-							ioc->alt_ioc->name, i));
-					r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
-					handlers++;
-				}
-			}
-		}
-		/* FIXME?  Examine results here? */
-	}
-
-	// May need to check/upload firmware & data here!
-
-	if ((r = SendIocInit(ioc)) != 0)
-		return -3;
-// NEW!
 	if (alt_ioc_ready) {
-		if ((r = SendIocInit(ioc->alt_ioc)) != 0) {
-			alt_ioc_ready = 0;
-			printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n",
-					ioc->alt_ioc->name, r);
-		}
-	}
-
-	/*
-	 * Call each currently registered protocol IOC reset handler
-	 * with post-reset indication.
-	 * NOTE: If we're doing _IOC_BRINGUP, there can be no
-	 * MptResetHandlers[] registered yet.
-	 */
-	if (hard_reset_done) {
-		r = handlers = 0;
-		for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
-			if (MptResetHandlers[i]) {
-				dprintk((KERN_INFO MYNAM ": %s: Calling IOC post_reset handler #%d\n",
-						ioc->name, i));
-				r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_POST_RESET);
-				handlers++;
-
-				if (alt_ioc_ready) {
-					dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC post_reset handler #%d\n",
-							ioc->alt_ioc->name, i));
-					r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
-					handlers++;
-				}
-			}
+		if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0)
+			return -2;
+		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+			MptDisplayIocCapabilities(ioc->alt_ioc);
 		}
-		/* FIXME?  Examine results here? */
 	}
 
 	/*
 	 * Prime reply & request queues!
-	 * (mucho alloc's)
+	 * (mucho alloc's) Must be done prior to
+	 * init as upper addresses are needed for init.
 	 */
 	if ((r = PrimeIocFifos(ioc)) != 0)
+		return -3;
+
+	// May need to check/upload firmware & data here!
+	if ((r = SendIocInit(ioc, sleepFlag)) != 0)
 		return -4;
 // NEW!
 	if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
 		printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
 				ioc->alt_ioc->name, r);
+		alt_ioc_ready = 0;
 	}
 
-// FIXME! Cleanup all IOC (and alt-IOC?) requests here!
+	if (alt_ioc_ready) {
+		if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
+			alt_ioc_ready = 0;
+			printk(KERN_WARNING MYNAM
+				": alt-%s: (%d) init failure WARNING!\n",
+					ioc->alt_ioc->name, r);
+		}
+	}
 
-	if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
-	    (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
-		/*
-		 *  Pre-fetch the ports LAN MAC address!
-		 *  (LANPage1_t stuff)
-		 */
-		(void) GetLanConfigPages(ioc);
-#ifdef MPT_DEBUG
-		{
-			u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
-			dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
-					ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+	if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
+		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+			dprintk((MYIOC_s_INFO_FMT
+				"firmware upload required!\n", ioc->name));
+
+			r = mpt_do_upload(ioc, sleepFlag);
+			if (r != 0)
+				printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+			/* Handle the alt IOC too */
+			if (alt_ioc_ready){
+				r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
+				if (r != 0)
+					printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+			}
 		}
-#endif
 	}
 
+
 	/* Enable! (reply interrupt) */
 	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
 	ioc->active = 1;
 
-// NEW!
-#if 0						// Kiss-of-death!?!
-	if (alt_ioc_ready && (r==0)) {
+	if (ioc->alt_ioc) {
 		/* (re)Enable alt-IOC! (reply interrupt) */
 		dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
 				ioc->alt_ioc->name));
 		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
 		ioc->alt_ioc->active = 1;
 	}
-#endif
 
 	/* NEW!  20010120 -sralston
 	 *  Enable MPT base driver management of EventNotification
@@ -1368,19 +1558,95 @@
 	 */
 	if (!ioc->facts.EventState)
 		(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
-// NEW!
-// FIXME!?!
-//	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) {
-//		(void) SendEventNotification(ioc->alt_ioc, 1);	/* 1=Enable EventNotification */
-//	}
+
+	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+		(void) SendEventNotification(ioc->alt_ioc, 1);	/* 1=Enable EventNotification */
+
+	/* (Bugzilla:fibrebugs, #513)
+	 * Bug fix (part 2)!  20010905 -sralston
+	 *	Add additional "reason" check before call to GetLanConfigPages
+	 *	(combined with GetIoUnitPage2 call).  This prevents a somewhat
+	 *	recursive scenario; GetLanConfigPages times out, timer expired
+	 *	routine calls HardResetHandler, which calls into here again,
+	 *	and we try GetLanConfigPages again...
+	 */
+	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+		if ((int)ioc->chip_type <= (int)FC929) {
+			/*
+			 *  Pre-fetch FC port WWN and stuff...
+			 *  (FCPortPage0_t stuff)
+			 */
+			for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+				(void) GetFcPortPage0(ioc, ii);
+			}
+
+			if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+			    (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
+				/*
+				 *  Pre-fetch the ports LAN MAC address!
+				 *  (LANPage1_t stuff)
+				 */
+				(void) GetLanConfigPages(ioc);
+#ifdef MPT_DEBUG
+				{
+					u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+					dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+							ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+				}
+#endif
+			}
+		} else {
+			/* Get NVRAM and adapter maximums from SPP 0 and 2
+			 */
+			mpt_GetScsiPortSettings(ioc, 0);
+
+			/* Get version and length of SDP 1 
+			 */
+			mpt_readScsiDevicePageHeaders(ioc, 0);
+
+			/* Find IM volumes 
+			 */
+			if (ioc->facts.MsgVersion >= 0x0102)
+				mpt_findImVolumes(ioc);
+		}
+
+		GetIoUnitPage2(ioc);
+	}
+
+	/*
+	 * Call each currently registered protocol IOC reset handler
+	 * with post-reset indication.
+	 * NOTE: If we're doing _IOC_BRINGUP, there can be no
+	 * MptResetHandlers[] registered yet.
+	 */
+	if (hard_reset_done) {
+		r = handlers = 0;
+		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+			if (MptResetHandlers[ii]) {
+				dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
+						ioc->name, ii));
+				r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
+				handlers++;
+
+				if (alt_ioc_ready) {
+					dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+							ioc->name, ioc->alt_ioc->name, ii));
+					r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+					handlers++;
+				}
+			}
+		}
+		/* FIXME?  Examine results here? */
+	}
 
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mpt_detect_929_bound_ports - Search for PCI bus/dev_function
- *	which matches PCI bus/dev_function (+/-1) for newly discovered 929.
+ *	mpt_detect_bound_ports - Search for PCI bus/dev_function
+ *	which matches PCI bus/dev_function (+/-1) for newly discovered 929
+ *	or 1030.
  *	@ioc: Pointer to MPT adapter structure
  *	@pdev: Pointer to (struct pci_dev) structure
  *
@@ -1388,22 +1654,22 @@
  *	using alt_ioc pointer fields in their %MPT_ADAPTER structures.
  */
 static void
-mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
 {
 	MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
 	unsigned int match_lo, match_hi;
 
 	match_lo = pdev->devfn-1;
 	match_hi = pdev->devfn+1;
-	dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
+	dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
 			ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
 
 	while (ioc_srch != NULL) {
 		struct pci_dev *_pcidev = ioc_srch->pcidev;
 
-		if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
-		     (_pcidev->bus->number == pdev->bus->number) &&
-		     (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+		if ((_pcidev->device == pdev->device) &&
+		    (_pcidev->bus->number == pdev->bus->number) &&
+		    (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
 			/* Paranoia checks */
 			if (ioc->alt_ioc != NULL) {
 				printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
@@ -1418,8 +1684,6 @@
 					ioc->name, ioc_srch->name));
 			ioc_srch->alt_ioc = ioc;
 			ioc->alt_ioc = ioc_srch;
-			ioc->sod_reset = ioc->alt_ioc->sod_reset;
-			ioc->last_kickstart = ioc->alt_ioc->last_kickstart;
 			break;
 		}
 		ioc_srch = mpt_adapter_find_next(ioc_srch);
@@ -1440,10 +1704,10 @@
 		u32 state;
 
 		/* Disable the FW */
-		state = GetIocState(this, 1);
+		state = mpt_GetIocState(this, 1);
 		if (state == MPI_IOC_STATE_OPERATIONAL) {
-			if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET) != 0)
-				(void) KickStart(this, 1);
+			if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0)
+				(void) KickStart(this, 1, NO_SLEEP);
 		}
 
 		/* Disable adapter interrupts! */
@@ -1475,12 +1739,37 @@
 		}
 
 		if (freeup && this->sense_buf_pool != NULL) {
-			sz = (this->req_depth * 256);
+			sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC);
 			pci_free_consistent(this->pcidev, sz,
 					this->sense_buf_pool, this->sense_buf_pool_dma);
 			this->sense_buf_pool = NULL;
 			this->alloc_total -= sz;
 		}
+
+		if (freeup && this->events != NULL){
+			sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+			kfree(this->events);
+			this->events = NULL;
+			this->alloc_total -= sz;
+		}
+
+		if (freeup && this->FWImage != NULL) {
+			sz = this->facts.FWImageSize;
+			pci_free_consistent(this->pcidev, sz,
+					this->FWImage, this->FWImage_dma);
+			this->FWImage = NULL;
+			this->alloc_total -= sz;
+		}
+
+		if (freeup && this->spi_data.nvram != NULL) {
+			kfree(this->spi_data.nvram);
+			this->spi_data.nvram = NULL;
+		}
+
+		if (freeup && this->spi_data.pIocPg3 != NULL) {
+			kfree(this->spi_data.pIocPg3);
+			this->spi_data.pIocPg3 = NULL;
+		}
 	}
 }
 
@@ -1575,23 +1864,30 @@
 /*
  *	MakeIocReady - Get IOC to a READY state, using KickStart if needed.
  *	@ioc: Pointer to MPT_ADAPTER structure
- *	@kick: Force hard KickStart of IOC
+ *	@force: Force hard KickStart of IOC
+ *	@sleepFlag: Specifies whether the process can sleep
  *
- *	Returns 0 for already-READY, 1 for hard reset success,
- *	else negative for failure.
+ *	Returns:
+ *		 1 - DIAG reset and READY
+ *		 0 - READY initially OR soft reset and READY 
+ *		-1 - Any failure on KickStart 
+ *		-2 - Msg Unit Reset Failed
+ *		-3 - IO Unit Reset Failed
+ *		-4 - IOC owned by a PEER
  */
 static int
-MakeIocReady(MPT_ADAPTER *ioc, int force)
+MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 {
 	u32	 ioc_state;
 	int	 statefault = 0;
-	int 	 cntdn;
+	int	 cntdn;
 	int	 hard_reset_done = 0;
 	int	 r;
-	int	 i;
+	int	 ii;
+	int	 whoinit;
 
 	/* Get current [raw] IOC state  */
-	ioc_state = GetIocState(ioc, 0);
+	ioc_state = mpt_GetIocState(ioc, 0);
 	dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
 
 	/*
@@ -1600,7 +1896,7 @@
 	 */
 	if (ioc_state & MPI_DOORBELL_ACTIVE) {
 		statefault = 1;
-		printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+		printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
 				ioc->name);
 	}
 
@@ -1613,7 +1909,7 @@
 	 */
 	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
 		statefault = 2;
-		printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
+		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
 				ioc->name);
 		printk(KERN_WARNING "           FAULT code = %04xh\n",
 				ioc_state & MPI_DOORBELL_DATA_MASK);
@@ -1623,28 +1919,49 @@
 	 *	Hmmm...  Did it get left operational?
 	 */
 	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
-		statefault = 3;
-		dprintk((KERN_WARNING MYNAM ": %s: Hmmm... IOC operational unexpected\n",
+		dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
 				ioc->name));
+
+		/* Check WhoInit.
+		 * If PCI Peer, exit.
+		 * Else, if no fault conditions are present, issue a MessageUnitReset
+		 * Else, fall through to KickStart case
+		 */
+		whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
+		dprintk((KERN_WARNING MYNAM
+			": whoinit 0x%x\n statefault %d force %d\n",
+			whoinit, statefault, force));
+		if (whoinit == MPI_WHOINIT_PCI_PEER)
+			return -4;
+		else {
+			if ((statefault == 0 ) && (force == 0)) {
+				if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+					return 0;
+			}
+			statefault = 3;
+		}
 	}
 
-	hard_reset_done = KickStart(ioc, statefault||force);
+	hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
 	if (hard_reset_done < 0)
 		return -1;
 
 	/*
 	 *  Loop here waiting for IOC to come READY.
 	 */
-	i = 0;
+	ii = 0;
 	cntdn = HZ * 15;
-	while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+	if (sleepFlag != CAN_SLEEP)
+		cntdn *= 10;	/* 1500 iterations @ 1msec per */
+
+	while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
 		if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
 			/*
 			 *  BIOS or previous driver load left IOC in OP state.
 			 *  Reset messaging FIFOs.
 			 */
-			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
-				printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
+				printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
 				return -2;
 			}
 		} else if (ioc_state == MPI_IOC_STATE_RESET) {
@@ -1652,25 +1969,30 @@
 			 *  Something is wrong.  Try to get IOC back
 			 *  to a known state.
 			 */
-			if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
-				printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
+				printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
 				return -3;
 			}
 		}
 
-		i++; cntdn--;
+		ii++; cntdn--;
 		if (!cntdn) {
-			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
-					ioc->name, (i+5)/HZ);
+			printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+					ioc->name, (ii+5)/HZ);
 			return -ETIME;
 		}
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		} else {
+			mdelay (1);	/* 1 msec delay */
+		}
+
 	}
 
 	if (statefault < 3) {
-		printk(KERN_WARNING MYNAM ": %s: Whew!  Recovered from %s\n",
+		printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
 				ioc->name,
 				statefault==1 ? "stuck handshake" : "IOC FAULT");
 	}
@@ -1680,21 +2002,21 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	GetIocState - Get the current state of a MPT adapter.
+ *	mpt_GetIocState - Get the current state of a MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@cooked: Request raw or cooked IOC state
  *
  *	Returns all IOC Doorbell register bits if cooked==0, else just the
  *	Doorbell bits in MPI_IOC_STATE_MASK.
  */
-static u32
-GetIocState(MPT_ADAPTER *ioc, int cooked)
+u32
+mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
 {
 	u32 s, sc;
 
 	/*  Get!  */
 	s = CHIPREG_READ32(&ioc->chip->Doorbell);
-	dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s));
+//	dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
 	sc = s & MPI_IOC_STATE_MASK;
 
 	/*  Save!  */
@@ -1707,11 +2029,13 @@
 /*
  *	GetIocFacts - Send IOCFacts request to MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@sleepFlag: Specifies whether the process can sleep
+ *	@reason: If recovery, only update facts.
  *
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-GetIocFacts(MPT_ADAPTER *ioc)
+GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 {
 	IOCFacts_t		 get_facts;
 	IOCFactsReply_t		*facts;
@@ -1741,14 +2065,13 @@
 	get_facts.Function = MPI_FUNCTION_IOC_FACTS;
 	/* Assert: All other get_facts fields are zero! */
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending get IocFacts request\n", ioc->name));
+	dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name));
 
 	/* No non-zero fields in the get_facts request are greater than
 	 * 1 byte in size, so we can just fire it off as is.
 	 */
-	r = HandShakeReqAndReply(ioc,
-			req_sz, (u32*)&get_facts,
-			reply_sz, (u16*)facts, 3);
+	r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
+			reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag);
 	if (r != 0)
 		return r;
 
@@ -1761,14 +2084,17 @@
 	 */
 	/* Did we get a valid reply? */
 	if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
-		/*
-		 * If not been here, done that, save off first WhoInit value
-		 */
-		if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
-			ioc->FirstWhoInit = facts->WhoInit;
+		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+			/*
+			 * If not been here, done that, save off first WhoInit value
+			 */
+			if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
+				ioc->FirstWhoInit = facts->WhoInit;
+		}
 
 		facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
 		facts->MsgContext = le32_to_cpu(facts->MsgContext);
+		facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
 		facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
 		facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
 		status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
@@ -1776,7 +2102,23 @@
 
 		facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
 		facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
-		facts->FWVersion = le16_to_cpu(facts->FWVersion);
+
+		/*
+		 * FC f/w version changed between 1.1 and 1.2 
+		 *	Old: u16{Major(4),Minor(4),SubMinor(8)}
+		 *	New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
+		 */
+		if (facts->MsgVersion < 0x0102) {
+			/*
+			 *	Handle old FC f/w style, convert to new...
+			 */
+			u16	 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
+			facts->FWVersion.Word =
+					((oldv<<12) & 0xFF000000) |
+					((oldv<<8)  & 0x000FFF00);
+		} else
+			facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
+
 		facts->ProductID = le16_to_cpu(facts->ProductID);
 		facts->CurrentHostMfaHighAddr =
 				le32_to_cpu(facts->CurrentHostMfaHighAddr);
@@ -1791,52 +2133,42 @@
 		 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
 		 * to 14 in MPI-1.01.0x.
 		 */
-		if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) {
+		if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
+		    facts->MsgVersion > 0x0100) {
 			facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
-			facts->DataImageSize = le32_to_cpu(facts->DataImageSize);
 		}
 
-		if (facts->RequestFrameSize) {
-			/*
-			 * Set values for this IOC's REQUEST queue size & depth...
-			 */
-			ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4);
-
-			/*
-			 *  Set values for this IOC's REPLY queue size & depth...
-			 *
-			 * BUG? FIX?  20000516 -nromer & sralston 
-			 *  GRRR...  The following did not translate well from MPI v0.09:
-			 *	ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4);
-			 *  to 0.10:
-			 *	ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4);
-			 *  Was trying to minimally optimize to smallest possible reply size
-			 *  (and greatly reduce kmalloc size).  But LAN may need larger reply?
-			 *
-			 *  So for now, just set reply size to request size.  FIXME?
-			 */
-			ioc->reply_sz = ioc->req_sz;
-		} else {
+		if (!facts->RequestFrameSize) {
 			/*  Something is wrong!  */
-			printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n",
+			printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
 					ioc->name);
-			ioc->req_sz = MPT_REQ_SIZE;
-			ioc->reply_sz = MPT_REPLY_SIZE;
 			return -55;
 		}
-		ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits);
-		ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth);
 
-		dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n",
+		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+			/*
+			 * Set values for this IOC's request & reply frame sizes,
+			 * and request & reply queue depths...
+			 */
+			ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
+			ioc->req_depth = MIN(MPT_DEFAULT_REQ_DEPTH, facts->GlobalCredits);
+			ioc->reply_sz = ioc->req_sz;
+			ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+			/* 1030 - should we use a smaller DEFAULT_REPLY_DEPTH?
+			 * FIX
+			 */
+			dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
 				ioc->name, ioc->reply_sz, ioc->reply_depth));
-		dprintk((KERN_INFO MYNAM ": %s: req_sz  =%3d, req_depth  =%4d\n",
+			dprintk((MYIOC_s_INFO_FMT "req_sz  =%3d, req_depth  =%4d\n",
 				ioc->name, ioc->req_sz, ioc->req_depth));
 
-		/* Get port facts! */
-		if ( (r = GetPortFacts(ioc, 0)) != 0 )
-			return r;
+			/* Get port facts! */
+			if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
+				return r;
+		}
 	} else {
-		printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
+		printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n",
 				ioc->name);
 		return -66;
 	}
@@ -1849,15 +2181,16 @@
  *	GetPortFacts - Send PortFacts request to MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@portnum: Port number
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-GetPortFacts(MPT_ADAPTER *ioc, int portnum)
+GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 {
 	PortFacts_t		 get_pfacts;
 	PortFactsReply_t	*pfacts;
-	int			 i;
+	int			 ii;
 	int			 req_sz;
 	int			 reply_sz;
 
@@ -1883,16 +2216,16 @@
 	get_pfacts.PortNumber = portnum;
 	/* Assert: All other get_pfacts fields are zero! */
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending get PortFacts(%d) request\n",
+	dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
 			ioc->name, portnum));
 
 	/* No non-zero fields in the get_pfacts request are greater than
 	 * 1 byte in size, so we can just fire it off as is.
 	 */
-	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts,
-				reply_sz, (u16*)pfacts, 3);
-	if (i != 0)
-		return i;
+	ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
+				reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag);
+	if (ii != 0)
+		return ii;
 
 	/* Did we get a valid reply? */
 
@@ -1914,13 +2247,14 @@
 /*
  *	SendIocInit - Send IOCInit request to MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
  *
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-SendIocInit(MPT_ADAPTER *ioc)
+SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
 {
 	IOCInit_t		 ioc_init;
 	MPIDefaultReply_t	 init_reply;
@@ -1937,20 +2271,35 @@
 	ioc_init.Function = MPI_FUNCTION_IOC_INIT;
 /*	ioc_init.Flags = 0;				*/
 
-	/*ioc_init.MaxDevices = 16;*/
-	ioc_init.MaxDevices = 255;
-/*	ioc_init.MaxBuses = 16;				*/
-	ioc_init.MaxBuses = 1;
+	if ((int)ioc->chip_type <= (int)FC929) {
+		ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
+	}
+	else {
+		ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
+	}
+	ioc_init.MaxBuses = MPT_MAX_BUS;
 
 /*	ioc_init.MsgFlags = 0;				*/
 /*	ioc_init.MsgContext = cpu_to_le32(0x00000000);	*/
 	ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);	/* in BYTES */
-	ioc_init.HostMfaHighAddr = cpu_to_le32(0);	/* Say we 32-bit! for now */
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init));
+#ifdef __ia64__
+	/* Save the upper 32-bits of the request
+	 * (reply) and sense buffers.
+	 */
+	ioc_init.HostMfaHighAddr = cpu_to_le32((u32)(ioc->req_frames_dma >> 32));
+	ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)(ioc->sense_buf_pool_dma >> 32));
+#else
+	/* Force 32-bit addressing */
+	ioc_init.HostMfaHighAddr = cpu_to_le32(0);
+	ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
+#endif
 
-	r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
-			sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10);
+	dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
+			ioc->name, &ioc_init));
+
+	r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+				sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
 	if (r != 0)
 		return r;
 
@@ -1958,7 +2307,7 @@
 	 * since we don't even look at it's contents.
 	 */
 
-	if ((r = SendPortEnable(ioc, 0)) != 0)
+	if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
 		return r;
 
 	/* YIKES!  SUPER IMPORTANT!!!
@@ -1967,21 +2316,27 @@
 	 */
 	count = 0;
 	cntdn = HZ * 60;					/* chg'd from 30 to 60 seconds */
-	state = GetIocState(ioc, 1);
+	if (sleepFlag != CAN_SLEEP)
+		cntdn *= 10;					/* scale for 1msec delays */
+	state = mpt_GetIocState(ioc, 1);
 	while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		} else {
+			mdelay(1);
+		}
 
 		if (!cntdn) {
-			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n",
+			printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
 					ioc->name, (count+5)/HZ);
 			return -9;
 		}
 
-		state = GetIocState(ioc, 1);
+		state = mpt_GetIocState(ioc, 1);
 		count++;
 	}
-	dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+	dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
 			ioc->name, count));
 
 	return r;
@@ -1992,17 +2347,18 @@
  *	SendPortEnable - Send PortEnable request to MPT adapter port.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@portnum: Port number to enable
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	Send PortEnable to bring IOC to OPERATIONAL state.
  *
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-SendPortEnable(MPT_ADAPTER *ioc, int portnum)
+SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 {
 	PortEnable_t		 port_enable;
 	MPIDefaultReply_t	 reply_buf;
-	int	 i;
+	int	 ii;
 	int	 req_sz;
 	int	 reply_sz;
 
@@ -2019,13 +2375,21 @@
 /*	port_enable.MsgFlags = 0;		*/
 /*	port_enable.MsgContext = 0;		*/
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n",
+	dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
 			ioc->name, portnum, &port_enable));
 
-	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable,
-			reply_sz, (u16*)&reply_buf, 65);
-	if (i != 0)
-		return i;
+	/* RAID FW may take a long time to enable
+	 */
+	if ((int)ioc->chip_type <= (int)FC929) {
+		ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+				reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
+	} else {
+		ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+				reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
+	}
+
+	if (ii != 0)
+		return ii;
 
 	/* We do not even look at the reply, so we need not
 	 * swap the multi-byte fields.
@@ -2036,19 +2400,341 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *	mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@sleepFlag: Specifies whether the process can sleep
+ *
+ *	Returns 0 for success, >0 for handshake failure
+ *		<0 for fw upload failure.
+ *
+ *	Remark: If bound IOC and a successful FWUpload was performed
+ *	on the bound IOC, the second image is discarded
+ *	and memory is free'd. Both channels must upload to prevent
+ *	IOC from running in degraded mode.
+ */
+static int
+mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
+{
+	u8			 request[sizeof(FWUpload_t) +  24];
+	u8			 reply[sizeof(FWUploadReply_t)];
+	FWUpload_t		*prequest;
+	FWUploadReply_t		*preply;
+	FWUploadTCSGE_t		*ptcsge = NULL;
+	MptSge_t		*psge;
+	u8			*mem;
+	dma_addr_t		 dma_addr;
+	int			 sgeoffset;
+	int			 i, sz, req_sz, reply_sz;
+	int			 cmdStatus, freeMem = 0;
+
+	/* If the image size is 0 or if the pointer is
+	 * not NULL (error), we are done.
+	 */
+	if (((sz = ioc->facts.FWImageSize) == 0) || ioc->FWImage)
+		return 0;
+
+	/* Allocate memory
+	 */
+	mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->FWImage_dma);
+	if (mem == NULL)
+		return -1;
+
+	memset(mem, 0, sz);
+	ioc->alloc_total += sz;
+	ioc->FWImage = mem;
+	dprintk((KERN_INFO MYNAM ": FW Image  @ %p[%p], sz=%d bytes\n",
+			mem, (void *)(ulong)ioc->FWImage_dma, sz));
+
+	dma_addr = ioc->FWImage_dma;
+
+	prequest = (FWUpload_t *)&request;
+	preply = (FWUploadReply_t *)&reply;
+
+	/*  Destination...  */
+	req_sz = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION)
+			+ sizeof(FWUploadTCSGE_t) + sizeof(MptSge_t);
+	memset(prequest, 0, req_sz);
+
+	reply_sz = sizeof(reply);
+	memset(preply, 0, reply_sz);
+
+	prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
+	prequest->Function = MPI_FUNCTION_FW_UPLOAD;
+	prequest->MsgContext = 0;		/* anything */
+
+	ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
+	ptcsge->Reserved = 0;
+	ptcsge->ContextSize = 0;
+	ptcsge->DetailsLength = 12;
+	ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+	ptcsge->Reserved1 = 0;
+	ptcsge->ImageOffset = 0;
+	ptcsge->ImageSize = cpu_to_le32(sz);
+
+	sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
+	psge = (MptSge_t *) &request[sgeoffset];
+	psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | (u32) sz);
+
+	cpu_to_leXX(dma_addr, psge->Address);
+
+	dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p)\n",
+			ioc->name, prequest));
+
+	i = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)prequest,
+				reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+
+	cmdStatus = -EFAULT;
+	if (i == 0) {
+		/* Handshake transfer was complete and successful.
+		 * Check the Reply Frame.
+		 */
+		int status, transfer_sz;
+		status = le16_to_cpu(preply->IOCStatus);
+		if (status == MPI_IOCSTATUS_SUCCESS) {
+			transfer_sz = le32_to_cpu(preply->ActualImageSize);
+			if (transfer_sz == sz)
+				cmdStatus = 0;
+		}
+	}
+	dprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
+			ioc->name, cmdStatus));
+
+	/* Check to see if we have a copy of this image in
+	 * host memory already.
+	 */
+	if (cmdStatus == 0) {
+		if (ioc->alt_ioc && ioc->alt_ioc->FWImage)
+			freeMem = 1;
+	}
+
+	/* We already have a copy of this image or
+	 * we had some type of an error  - either the handshake
+	 * failed (i != 0) or the command did not complete successfully.
+	 */
+	if (cmdStatus || freeMem) {
+		dprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
+			ioc->name, cmdStatus ? "incomplete" : "duplicate"));
+
+		pci_free_consistent(ioc->pcidev, sz,
+					ioc->FWImage, ioc->FWImage_dma);
+		ioc->FWImage = NULL;
+		ioc->alloc_total -= sz;
+	}
+
+	return cmdStatus;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_downloadboot - DownloadBoot code
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@flag: Specify which part of IOC memory is to be uploaded.
+ *	@sleepFlag: Specifies whether the process can sleep
+ *
+ *	FwDownloadBoot requires Programmed IO access.
+ *
+ *	Returns 0 for success
+ *		-1 FW Image size is 0
+ *		-2 No valid FWImage Pointer
+ *		<0 for fw upload failure.
+ */
+static int
+mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
+{
+	MpiFwHeader_t		*FwHdr = NULL;
+	MpiExtImageHeader_t 	*ExtHdr;
+	int			 fw_sz;
+	u32			 diag0val;
+#ifdef MPT_DEBUG
+	u32			 diag1val = 0;
+#endif
+	int			 count = 0;
+	u32			*ptru32 = NULL;
+	u32			 diagRwData;
+	u32			 nextImage;
+
+	dprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
+				ioc->name));
+#ifdef MPT_DEBUG
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
+				ioc->name, diag0val, diag1val));
+#endif
+
+	dprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
+				ioc->name, ioc->facts.FWImageSize, ioc->FWImage));
+	if (ioc->alt_ioc)
+		dprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
+				ioc->name, ioc->alt_ioc->FWImage));
+
+	/* Get dma_addr and data transfer size.
+	 */
+	if ((fw_sz = ioc->facts.FWImageSize) == 0)
+		return -1;
+
+	/* Get the DMA from ioc or ioc->alt_ioc */
+	if (ioc->FWImage)
+		FwHdr = (MpiFwHeader_t *)ioc->FWImage;
+	else if (ioc->alt_ioc && ioc->alt_ioc->FWImage)
+		FwHdr = (MpiFwHeader_t *)ioc->alt_ioc->FWImage;
+
+	dprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
+			ioc->name, FwHdr));
+
+	if (!FwHdr)
+		return -2;
+
+	/* Write magic sequence to WriteSequence register
+	 * until enter diagnostic mode
+	 */
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	while ((diag0val & MPI_DIAG_DRWE) == 0) {
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+		/* wait 100 msec */
+		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(100 * HZ / 1000);
+		} else {
+			mdelay (100);
+		}
+
+		count++;
+		if (count > 20) {
+			printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+					ioc->name, diag0val);
+			return -EFAULT;
+
+		}
+
+		diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+		if (ioc->alt_ioc)
+			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+		dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+				ioc->name, diag0val, diag1val));
+#endif
+		dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+				ioc->name, diag0val));
+	}
+
+	/* Set the DiagRwEn and Disable ARM bits */
+	diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM);
+	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+#ifdef MPT_DEBUG
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+			ioc->name, diag0val, diag1val));
+#endif
+
+	/* Write the LoadStartAddress to the DiagRw Address Register
+	 * using Programmed IO
+	 */
+
+	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress);
+	dprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+		ioc->name, FwHdr->LoadStartAddress));
+
+	nextImage = FwHdr->NextImageHeaderOffset;
+
+	/* round up count to a 32bit alignment */
+	ptru32 = (u32 *) FwHdr;
+	count = (FwHdr->ImageSize + 3)/4;
+
+	dprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
+				ioc->name, count, ptru32));
+	while (count-- ) {
+		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+		ptru32++;
+	}
+
+	dprintk((MYIOC_s_INFO_FMT "FW Image done! \n", ioc->name));
+		
+	while (nextImage) {
+
+		/* Set the pointer to the extended image
+		 */
+		ExtHdr = (MpiExtImageHeader_t *) ((char *) FwHdr + nextImage);
+
+		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, ExtHdr->LoadStartAddress);
+
+		count = (ExtHdr->ImageSize + 3 )/4;
+
+		ptru32 = (u32 *) ExtHdr;
+		dprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
+				ioc->name, count, ptru32));
+		while (count-- ) {
+			CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+			ptru32++;
+		}
+		nextImage = ExtHdr->NextImageHeaderOffset;
+	}
+
+
+	/* Write the IopResetVectorRegAddr */
+	dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
+	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr);
+
+	/* Write the IopResetVectorValue */
+	dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
+	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue);
+
+	/* Clear the internal flash bad bit - autoincrementing register,
+	 * so must do two writes.
+	 */
+	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+	diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
+	diagRwData |= 0x4000000;
+	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
+
+	/* clear the RW enable and DISARM bits */
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG);
+	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+	/* Write 0xFF to reset the sequencer */
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
  *	KickStart - Perform hard reset of MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@force: Force hard reset
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	This routine places MPT adapter in diagnostic mode via the
  *	WriteSequence register, and then performs a hard reset of adapter
  *	via the Diagnostic register.
  *
- *	Returns 0 for soft reset success, 1 for hard reset success,
- *	else a negative value for failure.
+ *	Inputs:   sleepflag - CAN_SLEEP (non-interrupt thread)
+ *			or NO_SLEEP (interrupt thread, use mdelay)
+ *		  force - 1 if doorbell active, board fault state
+ *				board operational, IOC_RECOVERY or
+ *				IOC_BRINGUP and there is an alt_ioc.
+ *			  0 else
+ *
+ *	Returns:
+ *		 1 - hard reset, READY	
+ *		 0 - no reset due to History bit, READY	
+ *		-1 - no reset due to History bit but not READY	
+ *		     OR reset but failed to come READY
+ *		-2 - no reset, could not enter DIAG mode 
+ *		-3 - reset but bad FW bit 
  */
 static int
-KickStart(MPT_ADAPTER *ioc, int force)
+KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
 {
 	int hard_reset_done = 0;
 	u32 ioc_state;
@@ -2056,183 +2742,295 @@
 
 	dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
 
-	hard_reset_done = mpt_fc9x9_reset(ioc, force);
-#if 0
-	if (ioc->chip_type == FC909 || ioc->chip-type == FC919) {
-		hard_reset_done = mpt_fc9x9_reset(ioc, force);
-	} else if (ioc->chip_type == FC929) {
-		unsigned long delta;
-
-		delta = jiffies - ioc->last_kickstart;
-		dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n",
-				ioc->name, ioc->last_kickstart, delta));
-		if ((ioc->sod_reset == 0) || (delta >= 10*HZ))
-			hard_reset_done = mpt_fc9x9_reset(ioc, ignore);
-		else {
-			dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
-					ioc->name, delta));
-			return 0;
-		}
-	/* TODO! Add C1030!
-	} else if (ioc->chip_type == C1030) {
-	 */
-	} else {
-		printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n",
-				ioc->name, ioc->chip_type);
-		return -5;
-	}
-#endif
-
+	hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
 	if (hard_reset_done < 0)
 		return hard_reset_done;
 
-	dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
+	dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
 			ioc->name));
 
 	for (cnt=0; cnt<HZ*20; cnt++) {
-		if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
-			dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n",
+		if ((ioc_state = mpt_GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+			dprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
 					ioc->name, cnt));
 			return hard_reset_done;
 		}
-		/* udelay(10000) ? */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		} else {
+			mdelay (10);
+		}
 	}
 
-	printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n",
+	printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n",
 			ioc->name);
 	return -1;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter.
+ *	mpt_diag_reset - Perform hard reset of the adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
- *
- *	This routine places FC9x9 adapter in diagnostic mode via the
- *	WriteSequence register, and then performs a hard reset of adapter
- *	via the Diagnostic register.
- *
- *	Returns 0 for success, non-zero for failure.
+ *	@ignore: Set if to honor and clear to ignore
+ *		the reset history bit
+ *	@sleepflag: CAN_SLEEP if called in a non-interrupt thread,
+ *		else set to NO_SLEEP (use mdelay instead)
+ *
+ *	This routine places the adapter in diagnostic mode via the
+ *	WriteSequence register and then performs a hard reset of adapter
+ *	via the Diagnostic register. Adapter should be in ready state
+ *	upon successful completion.
+ *
+ *	Returns:  1  hard reset successful
+ *		  0  no reset performed because reset history bit set
+ *		 -2  enabling diagnostic mode failed
+ *		 -3  diagnostic reset failed
  */
 static int
-mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore)
+mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 {
 	u32 diag0val;
+	u32 doorbell;
 	int hard_reset_done = 0;
+	int count = 0;
+#ifdef MPT_DEBUG
+	u32 diag1val = 0;
+#endif
 
-	/* Use "Diagnostic reset" method! (only thing available!) */
+	/* Clear any existing interrupts */
+	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
+	/* Use "Diagnostic reset" method! (only thing available!) */
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
 #ifdef MPT_DEBUG
-{
-	u32 diag1val = 0;
 	if (ioc->alt_ioc)
 		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((KERN_INFO MYNAM ": %s: DBG1: diag0=%08x, diag1=%08x\n",
+	dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
 			ioc->name, diag0val, diag1val));
-}
 #endif
-	if (diag0val & MPI_DIAG_DRWE) {
-		dprintk((KERN_INFO MYNAM ": %s: DiagWriteEn bit already set\n",
-				ioc->name));
-	} else {
-		/* Write magic sequence to WriteSequence register */
-		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
-		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
-		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
-		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
-		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
-		dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#1]\n",
-				ioc->name));
-	}
 
-	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	/* Do the reset if we are told to ignore the reset history
+	 * or if the reset history is 0
+	 */
+	if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
+		while ((diag0val & MPI_DIAG_DRWE) == 0) {
+			/* Write magic sequence to WriteSequence register
+			 * Loop until in diagnostic mode
+			 */
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+			/* wait 100 msec */
+			if (sleepFlag == CAN_SLEEP) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				schedule_timeout(100 * HZ / 1000);
+			} else {
+				mdelay (100);
+			}
+
+			count++;
+			if (count > 20) {
+				printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+						ioc->name, diag0val);
+				return -2;
+
+			}
+
+			diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+			dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+					ioc->name, diag0val));
+		}
+
 #ifdef MPT_DEBUG
-{
-	u32 diag1val = 0;
-	if (ioc->alt_ioc)
-		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((KERN_INFO MYNAM ": %s: DbG2: diag0=%08x, diag1=%08x\n",
-			ioc->name, diag0val, diag1val));
-}
+		if (ioc->alt_ioc)
+			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+		dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+				ioc->name, diag0val, diag1val));
 #endif
-	if (!ignore && (diag0val & MPI_DIAG_RESET_HISTORY)) {
-		dprintk((KERN_INFO MYNAM ": %s: Skipping due to ResetHistory bit set!\n",
-				ioc->name));
-	} else {
+		/* Write the PreventIocBoot bit */
+		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+			diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
+			CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+		}
+
+		/*
+		 * Disable the ARM (Bug fix)
+		 * 
+		 */
+		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
+		mdelay (1);
+
 		/*
 		 * Now hit the reset bit in the Diagnostic register
-		 * (THE BIG HAMMER!)
+		 * (THE BIG HAMMER!) (Clears DRWE bit).
 		 */
-		CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
 		hard_reset_done = 1;
-		dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset performed\n",
+		dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
 				ioc->name));
 
-		/* want udelay(100) */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		/*
+		 * Call each currently registered protocol IOC reset handler
+		 * with pre-reset indication.
+		 * NOTE: If we're doing _IOC_BRINGUP, there can be no
+		 * MptResetHandlers[] registered yet.
+		 */
+		{
+			int	 ii;
+			int	 r = 0;
+
+			for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+				if (MptResetHandlers[ii]) {
+					dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
+							ioc->name, ii));
+					r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
+					if (ioc->alt_ioc) {
+						dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
+								ioc->name, ioc->alt_ioc->name, ii));
+						r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
+					}
+				}
+			}
+			/* FIXME?  Examine results here? */
+		}
+
+		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+			/* If the DownloadBoot operation fails, the
+			 * IOC will be left unusable. This is a fatal error
+			 * case.  _diag_reset will return < 0
+			 */
+			for (count = 0; count < 30; count ++) {
+				diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+				if (ioc->alt_ioc)
+					diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+				dprintk((MYIOC_s_INFO_FMT 
+					"DbG2b: diag0=%08x, diag1=%08x\n",
+					ioc->name, diag0val, diag1val));
+#endif
+				if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
+					break;
+				}
+
+				/* wait 1 sec */
+				if (sleepFlag == CAN_SLEEP) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					schedule_timeout(HZ);
+				} else {
+					mdelay (1000);
+				}
+			}
+			if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
+				printk(KERN_WARNING MYNAM 
+					": firmware downloadboot failure (%d)!\n", count);
+			}
+
+		} else {
+			/* Wait for FW to reload and for board
+			 * to go to the READY state.
+			 * Maximum wait is 30 seconds.
+			 * If fail, no error will check again
+			 * with calling program.
+			 */
+			for (count = 0; count < 30; count ++) {
+				doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+				doorbell &= MPI_IOC_STATE_MASK;
+
+				if (doorbell == MPI_IOC_STATE_READY) {
+					break;
+				}
+
+				/* wait 1 sec */
+				if (sleepFlag == CAN_SLEEP) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					schedule_timeout(HZ);
+				} else {
+					mdelay (1000);
+				}
+			}
+		}
+	}
 
-		/* Write magic sequence to WriteSequence register */
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+		ioc->name, diag0val, diag1val));
+#endif
+
+	/* Clear RESET_HISTORY bit!  Place board in the
+	 * diagnostic mode to update the diag register.
+	 */
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	count = 0;
+	while ((diag0val & MPI_DIAG_DRWE) == 0) {
+		/* Write magic sequence to WriteSequence register
+		 * Loop until in diagnostic mode
+		 */
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
 		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
-		dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#2]\n",
-				ioc->name));
-	}
 
-	/* Clear RESET_HISTORY bit! */
-	CHIPREG_WRITE32(&ioc->chip->Diagnostic, 0x0);
+		/* wait 100 msec */
+		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(100 * HZ / 1000);
+		} else {
+			mdelay (100);
+		}
 
+		count++;
+		if (count > 20) {
+			printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+					ioc->name, diag0val);
+			break;
+		}
+		diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	}
+	diag0val &= ~MPI_DIAG_RESET_HISTORY;
+	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-#ifdef MPT_DEBUG
-{
-	u32 diag1val = 0;
-	if (ioc->alt_ioc)
-		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((KERN_INFO MYNAM ": %s: DbG3: diag0=%08x, diag1=%08x\n",
-			ioc->name, diag0val, diag1val));
-}
-#endif
 	if (diag0val & MPI_DIAG_RESET_HISTORY) {
-		printk(KERN_WARNING MYNAM ": %s: WARNING - ResetHistory bit failed to clear!\n",
+		printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
 				ioc->name);
 	}
 
+	/* Disable Diagnostic Mode
+	 */
+	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
+
+	/* Check FW reload status flags.
+	 */
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+	if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
+		printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
+				ioc->name, diag0val);
+		return -3;
+	}
+
 #ifdef MPT_DEBUG
-{
-	u32 diag1val = 0;
 	if (ioc->alt_ioc)
 		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((KERN_INFO MYNAM ": %s: DbG4: diag0=%08x, diag1=%08x\n",
+	dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
 			ioc->name, diag0val, diag1val));
-}
 #endif
-	if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
-		printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED! (%02xh)\n",
-				ioc->name, diag0val);
-		return -3;
-	}
 
 	/*
 	 * Reset flag that says we've enabled event notification
 	 */
 	ioc->facts.EventState = 0;
 
-	/* NEW!  20010220 -sralston
-	 * Try to avoid redundant resets of the 929.
-	 */
-	ioc->sod_reset++;
-	ioc->last_kickstart = jiffies;
-	if (ioc->alt_ioc) {
-		ioc->alt_ioc->sod_reset = ioc->sod_reset;
-		ioc->alt_ioc->last_kickstart = ioc->last_kickstart;
-	}
+	if (ioc->alt_ioc)
+		ioc->alt_ioc->facts.EventState = 0;
 
 	return hard_reset_done;
 }
@@ -2249,16 +3047,45 @@
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
 {
 	int r;
+	u32 state;
+	int cntdn, count;
 
 	dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
 			ioc->name, reset_type));
 	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
-	if ((r = WaitForDoorbellAck(ioc, 2)) < 0)
+	if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
 		return r;
 
+	/* FW ACK'd request, wait for READY state 
+	 */
+	cntdn = HZ * 15;
+	count = 0;
+	if (sleepFlag != CAN_SLEEP)
+		cntdn *= 10;	/* 1500 iterations @ 1msec per */
+
+	while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+		cntdn--;
+		count++;
+		if (!cntdn) {
+			if (sleepFlag != CAN_SLEEP)
+				count *= 10;
+
+			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+					ioc->name, (count+5)/HZ);
+			return -ETIME;
+		}
+
+		if (sleepFlag == CAN_SLEEP) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		} else {
+			mdelay (1);	/* 1 msec delay */
+		}
+	}
+
 	/* TODO!
 	 *  Cleanup all event stuff for this IOC; re-issue EventNotification
 	 *  request if needed.
@@ -2275,7 +3102,8 @@
  *	@ioc: Pointer to MPT_ADAPTER structure
  *
  *	This routine allocates memory for the MPT reply and request frame
- *	pools, and primes the IOC reply FIFO with reply frames.
+ *	pools (if necessary), and primes the IOC reply FIFO with
+ *	reply frames.
  *
  *	Returns 0 for success, non-zero for failure.
  */
@@ -2284,6 +3112,7 @@
 {
 	MPT_FRAME_HDR *mf;
 	unsigned long b;
+	unsigned long flags;
 	dma_addr_t aligned_mem_dma;
 	u8 *mem, *aligned_mem;
 	int i, sz;
@@ -2299,8 +3128,8 @@
 		memset(mem, 0, sz);
 		ioc->alloc_total += sz;
 		ioc->reply_alloc = mem;
-		dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%08x], sz=%d bytes\n",
-			 ioc->name, mem, ioc->reply_alloc_dma, sz));
+		dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%p], sz=%d bytes\n",
+			 	ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, sz));
 
 		b = (unsigned long) mem;
 		b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -2308,15 +3137,20 @@
 		ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
 		ioc->reply_frames_dma =
 			(ioc->reply_alloc_dma + (aligned_mem - mem));
-		aligned_mem_dma = ioc->reply_frames_dma;
-		dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n",
-			 ioc->name, aligned_mem, aligned_mem_dma));
-
-		for (i = 0; i < ioc->reply_depth; i++) {
-			/*  Write each address to the IOC!  */
-			CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
-			aligned_mem_dma += ioc->reply_sz;
-		}
+
+		ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF);
+	}
+
+	/* Post Reply frames to FIFO
+	 */
+	aligned_mem_dma = ioc->reply_frames_dma;
+	dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n",
+		 	ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma));
+
+	for (i = 0; i < ioc->reply_depth; i++) {
+		/*  Write each address to the IOC!  */
+		CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
+		aligned_mem_dma += ioc->reply_sz;
 	}
 
 
@@ -2336,8 +3170,8 @@
 		memset(mem, 0, sz);
 		ioc->alloc_total += sz;
 		ioc->req_alloc = mem;
-		dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%08x], sz=%d bytes\n",
-			 ioc->name, mem, ioc->req_alloc_dma, sz));
+		dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%p], sz=%d bytes\n",
+			 	ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, sz));
 
 		b = (unsigned long) mem;
 		b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -2345,18 +3179,18 @@
 		ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
 		ioc->req_frames_dma =
 			(ioc->req_alloc_dma + (aligned_mem - mem));
-		aligned_mem_dma = ioc->req_frames_dma;
 
-		dprintk((KERN_INFO MYNAM ": %s.req_frames   @ %p[%08x]\n",
-			 ioc->name, aligned_mem, aligned_mem_dma));
+		ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF);
 
-		for (i = 0; i < ioc->req_depth; i++) {
-			mf = (MPT_FRAME_HDR *) aligned_mem;
-
-			/*  Queue REQUESTs *internally*!  */
-			Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
-			aligned_mem += ioc->req_sz;
+#ifdef __ia64__
+		/* Check: upper 32-bits of the request and reply frame
+		 * physical addresses must be the same.
+		 * ia64 check only
+		 */
+		if ((ioc->req_frames_dma >> 32) != (ioc->reply_frames_dma >> 32)){
+			goto out_fail;
 		}
+#endif
 
 #if defined(CONFIG_MTRR) && 0
 		/*
@@ -2367,20 +3201,38 @@
 		ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
 					 sz,
 					 MTRR_TYPE_WRCOMB, 1);
-		dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n",
-				ioc->name, ioc->req_alloc_dma,
-				sz ));
+		dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
+				ioc->name, ioc->req_alloc_dma, sz));
 #endif
+	}
+
+	/* Initialize Request frames linked list
+	 */
+	aligned_mem_dma = ioc->req_frames_dma;
+	aligned_mem = (u8 *) ioc->req_frames;
+	dprintk((KERN_INFO MYNAM ": %s.req_frames   @ %p[%p]\n",
+		 	ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma));
 
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+	Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+	for (i = 0; i < ioc->req_depth; i++) {
+		mf = (MPT_FRAME_HDR *) aligned_mem;
+
+		/*  Queue REQUESTs *internally*!  */
+		Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
+		aligned_mem += ioc->req_sz;
 	}
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
 
 	if (ioc->sense_buf_pool == NULL) {
-		sz = (ioc->req_depth * 256);
+		sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
 		ioc->sense_buf_pool =
 				pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
 		if (ioc->sense_buf_pool == NULL)
 			goto out_fail;
 
+		ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
 		ioc->alloc_total += sz;
 	}
 
@@ -2408,7 +3260,7 @@
 #if defined(CONFIG_MTRR) && 0
 		if (ioc->mtrr_reg > 0) {
 			mtrr_del(ioc->mtrr_reg, 0, 0);
-			dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n",
+			dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n",
 					ioc->name));
 		}
 #endif
@@ -2417,7 +3269,7 @@
 		ioc->alloc_total -= sz;
 	}
 	if (ioc->sense_buf_pool != NULL) {
-		sz = (ioc->req_depth * 256);
+		sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
 		pci_free_consistent(ioc->pcidev,
 				sz,
 				ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
@@ -2427,8 +3279,8 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	HandShakeReqAndReply - Send MPT request to and receive reply from
+/**
+ *	mpt_handshake_req_reply_wait - Send MPT request to and receive reply from
  *	IOC via doorbell handshake method.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@reqBytes: Size of the request in bytes
@@ -2436,6 +3288,7 @@
  *	@replyBytes: Expected size of the reply in bytes
  *	@u16reply: Pointer to area where reply should be written
  *	@maxwait: Max wait time for a reply (in seconds)
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	NOTES: It is the callers responsibility to byte-swap fields in the
  *	request which are greater than 1 byte in size.  It is also the
@@ -2444,8 +3297,9 @@
  *
  *	Returns 0 for success, non-zero for failure.
  */
-static int
-HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait)
+int
+mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
+				int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
 {
 	MPIDefaultReply_t *mptReply;
 	int failcnt = 0;
@@ -2471,57 +3325,61 @@
 	/*
 	 * Wait for IOC's doorbell handshake int
 	 */
-	if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+	if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
 		failcnt++;
 
-	dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
+	dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n",
 			ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
 
+	/* Read doorbell and check for active bit */
+	if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+			return -1;
+
 	/*
 	 * Clear doorbell int (WRITE 0 to IntStatus reg),
 	 * then wait for IOC to ACKnowledge that it's ready for
 	 * our handshake request.
 	 */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-	if (!failcnt && (t = WaitForDoorbellAck(ioc, 2)) < 0)
+	if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
 		failcnt++;
 
 	if (!failcnt) {
-		int	 i;
+		int	 ii;
 		u8	*req_as_bytes = (u8 *) req;
 
 		/*
 		 * Stuff request words via doorbell handshake,
 		 * with ACK from IOC for each.
 		 */
-		for (i = 0; !failcnt && i < reqBytes/4; i++) {
-			u32 word = ((req_as_bytes[(i*4) + 0] <<  0) |
-				    (req_as_bytes[(i*4) + 1] <<  8) |
-				    (req_as_bytes[(i*4) + 2] << 16) |
-				    (req_as_bytes[(i*4) + 3] << 24));
+		for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
+			u32 word = ((req_as_bytes[(ii*4) + 0] <<  0) |
+				    (req_as_bytes[(ii*4) + 1] <<  8) |
+				    (req_as_bytes[(ii*4) + 2] << 16) |
+				    (req_as_bytes[(ii*4) + 3] << 24));
 
 			CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
-			if ((t = WaitForDoorbellAck(ioc, 2)) < 0)
+			if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
 				failcnt++;
 		}
 
 		dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
 		DBG_DUMP_REQUEST_FRAME_HDR(req)
 
-		dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n",
+		dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
 				ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
 
 		/*
 		 * Wait for completion of doorbell handshake reply from the IOC
 		 */
-		if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait)) < 0)
+		if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
 			failcnt++;
 
 		/*
 		 * Copy out the cached reply...
 		 */
-		for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++)
-			u16reply[i] = ioc->hs_reply[i];
+		for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++)
+			u16reply[ii] = ioc->hs_reply[ii];
 	} else {
 		return -99;
 	}
@@ -2535,6 +3393,7 @@
  *	in it's IntStatus register.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@howlong: How long to wait (in seconds)
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	This routine waits (up to ~2 seconds max) for IOC doorbell
  *	handshake ACKnowledge.
@@ -2542,28 +3401,40 @@
  *	Returns a negative value on failure, else wait loop count.
  */
 static int
-WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
 	int cntdn = HZ * howlong;
 	int count = 0;
 	u32 intstat;
 
-	while (--cntdn) {
-		intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
-		if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
-			break;
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
-		count++;
+	if (sleepFlag == CAN_SLEEP) {
+		while (--cntdn) {
+			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+			if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+				break;
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+			count++;
+		}
+	} else {
+		cntdn *= 10; /* convert to msec */
+		while (--cntdn) {
+			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+			if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+				break;
+			mdelay (1);
+			count++;
+		}
+		count /= 10;
 	}
 
 	if (cntdn) {
-		dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n",
+		dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n",
 				ioc->name, count));
 		return count;
 	}
 
-	printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n",
+	printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n",
 			ioc->name, (count+5)/HZ);
 	return -1;
 }
@@ -2574,34 +3445,47 @@
  *	in it's IntStatus register.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@howlong: How long to wait (in seconds)
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
  *
  *	Returns a negative value on failure, else wait loop count.
  */
 static int
-WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
 	int cntdn = HZ * howlong;
 	int count = 0;
 	u32 intstat;
 
-	while (--cntdn) {
-		intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
-		if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
-			break;
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
-		count++;
+	if (sleepFlag == CAN_SLEEP) {
+		while (--cntdn) {
+			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+			if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+				break;
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+			count++;
+		}
+	} else {
+		cntdn *= 10; /* convert to msec */
+		while (--cntdn) {
+			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+			if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+				break;
+			mdelay(1);
+			count++;
+		}
+		count /= 10;
 	}
 
 	if (cntdn) {
-		dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n",
+		dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n",
 				ioc->name, count));
 		return count;
 	}
 
-	printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n",
+	printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n",
 			ioc->name, (count+5)/HZ);
 	return -1;
 }
@@ -2611,6 +3495,7 @@
  *	WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@howlong: How long to wait (in seconds)
+ *	@sleepFlag: Specifies whether the process can sleep
  *
  *	This routine polls the IOC for a handshake reply, 16 bits at a time.
  *	Reply is cached to IOC private area large enough to hold a maximum
@@ -2619,13 +3504,13 @@
  *	Returns a negative value on failure, else size of reply in WORDS.
  */
 static int
-WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
 	int u16cnt = 0;
 	int failcnt = 0;
 	int t;
 	u16 *hs_reply = ioc->hs_reply;
- 	volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+	volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
 	u16 hword;
 
 	hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
@@ -2634,12 +3519,12 @@
 	 * Get first two u16's so we can look at IOC's intended reply MsgLength
 	 */
 	u16cnt=0;
-	if ((t = WaitForDoorbellInt(ioc, howlong)) < 0) {
+	if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
 		failcnt++;
 	} else {
 		hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
 		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-		if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+		if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
 			failcnt++;
 		else {
 			hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
@@ -2647,7 +3532,7 @@
 		}
 	}
 
-	dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
+	dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n",
 			ioc->name, le32_to_cpu(*(u32 *)hs_reply),
 			failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
 
@@ -2656,7 +3541,7 @@
 	 * reply 16 bits at a time.
 	 */
 	for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
-		if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+		if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
 			failcnt++;
 		hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
 		/* don't overflow our IOC hs_reply[] buffer! */
@@ -2665,12 +3550,12 @@
 		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 	}
 
-	if (!failcnt && (t = WaitForDoorbellInt(ioc, 2)) < 0)
+	if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
 		failcnt++;
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
 	if (failcnt) {
-		printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n",
+		printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
 				ioc->name);
 		return -failcnt;
 	}
@@ -2681,130 +3566,631 @@
 	else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
 		return -102;
 	}
-#endif
+#endif
+
+	dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
+	DBG_DUMP_REPLY_FRAME(mptReply)
+
+	dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n",
+			ioc->name, u16cnt/2));
+	return u16cnt/2;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetLanConfigPages - Fetch LANConfig pages.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Return: 0 for success
+ *	-ENOMEM if no memory available
+ *		-EPERM if not allowed due to ISR context
+ *		-EAGAIN if no msg frames currently available
+ *		-EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+	ConfigPageHeader_t	 hdr;
+	CONFIGPARMS		 cfg;
+	LANPage0_t		*ppage0_alloc;
+	dma_addr_t		 page0_dma;
+	LANPage1_t		*ppage1_alloc;
+	dma_addr_t		 page1_dma;
+	int			 rc = 0;
+	int			 data_sz;
+	int			 copy_sz;
+
+	/* Get LAN Page 0 header */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.pageAddr = 0;
+	cfg.timeout = 0;
+
+	if ((rc = mpt_config(ioc, &cfg)) != 0)
+		return rc;
+
+	if (hdr.PageLength > 0) {
+		data_sz = hdr.PageLength * 4;
+		ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+		rc = -ENOMEM;
+		if (ppage0_alloc) {
+			memset((u8 *)ppage0_alloc, 0, data_sz);
+			cfg.physAddr = page0_dma;
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+			if ((rc = mpt_config(ioc, &cfg)) == 0) {
+				/* save the data */
+				copy_sz = MIN(sizeof(LANPage0_t), data_sz);
+				memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
+
+			}
+
+			pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+
+			/* FIXME!
+			 *	Normalize endianness of structure data,
+			 *	by byte-swapping all > 1 byte fields!
+			 */
+
+		}
+
+		if (rc)
+			return rc;
+	}
+
+	/* Get LAN Page 1 header */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 1;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.pageAddr = 0;
+
+	if ((rc = mpt_config(ioc, &cfg)) != 0)
+		return rc;
+
+	if (hdr.PageLength == 0)
+		return 0;
+
+	data_sz = hdr.PageLength * 4;
+	rc = -ENOMEM;
+	ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
+	if (ppage1_alloc) {
+		memset((u8 *)ppage1_alloc, 0, data_sz);
+		cfg.physAddr = page1_dma;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+		if ((rc = mpt_config(ioc, &cfg)) == 0) {
+			/* save the data */
+			copy_sz = MIN(sizeof(LANPage1_t), data_sz);
+			memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
+		}
+
+		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
+
+		/* FIXME!
+		 *	Normalize endianness of structure data,
+		 *	by byte-swapping all > 1 byte fields!
+		 */
+
+	}
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetFcPortPage0 - Fetch FCPort config Page0.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@portnum: IOC Port number
+ *
+ *	Return: 0 for success
+ *	-ENOMEM if no memory available
+ *		-EPERM if not allowed due to ISR context
+ *		-EAGAIN if no msg frames currently available
+ *		-EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+{
+	ConfigPageHeader_t	 hdr;
+	CONFIGPARMS		 cfg;
+	FCPortPage0_t		*ppage0_alloc;
+	FCPortPage0_t		*pp0dest;
+	dma_addr_t		 page0_dma;
+	int			 data_sz;
+	int			 copy_sz;
+	int			 rc;
+
+	/* Get FCPort Page 0 header */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.pageAddr = portnum;
+	cfg.timeout = 0;
+
+	if ((rc = mpt_config(ioc, &cfg)) != 0)
+		return rc;
+
+	if (hdr.PageLength == 0)
+		return 0;
+
+	data_sz = hdr.PageLength * 4;
+	rc = -ENOMEM;
+	ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+	if (ppage0_alloc) {
+		memset((u8 *)ppage0_alloc, 0, data_sz);
+		cfg.physAddr = page0_dma;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+		if ((rc = mpt_config(ioc, &cfg)) == 0) {
+			/* save the data */
+			pp0dest = &ioc->fc_port_page0[portnum];
+			copy_sz = MIN(sizeof(FCPortPage0_t), data_sz);
+			memcpy(pp0dest, ppage0_alloc, copy_sz);
+
+			/*
+			 *	Normalize endianness of structure data,
+			 *	by byte-swapping all > 1 byte fields!
+			 */
+			pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
+			pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
+			pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
+			pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
+			pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
+			pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
+			pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
+			pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
+			pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
+			pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
+			pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
+			pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
+			pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
+			pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
+			pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
+			pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
+
+		}
+
+		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+	}
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	GetIoUnitPage2 - Retrieve BIOS version and boot order information.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *
+ *	Returns: 0 for success
+ *	-ENOMEM if no memory available
+ *		-EPERM if not allowed due to ISR context
+ *		-EAGAIN if no msg frames currently available
+ *		-EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetIoUnitPage2(MPT_ADAPTER *ioc)
+{
+	ConfigPageHeader_t	 hdr;
+	CONFIGPARMS		 cfg;
+	IOUnitPage2_t		*ppage_alloc;
+	dma_addr_t		 page_dma;
+	int			 data_sz;
+	int			 rc;
+
+	/* Get the page header */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 2;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.pageAddr = 0;
+	cfg.timeout = 0;
+
+	if ((rc = mpt_config(ioc, &cfg)) != 0)
+		return rc;
+
+	if (hdr.PageLength == 0)
+		return 0;
+
+	/* Read the config page */
+	data_sz = hdr.PageLength * 4;
+	rc = -ENOMEM;
+	ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
+	if (ppage_alloc) {
+		memset((u8 *)ppage_alloc, 0, data_sz);
+		cfg.physAddr = page_dma;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+		/* If Good, save data */
+		if ((rc = mpt_config(ioc, &cfg)) == 0)
+			ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
+
+		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
+	}
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
+ *	@ioc: Pointer to a Adapter Strucutre
+ *	@portnum: IOC port number
+ *
+ *	Return: -EFAULT if read of config page header fails
+ *			or if no nvram
+ *	If read of SCSI Port Page 0 fails,
+ *		NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
+ *		Adapter settings: async, narrow
+ *		Return 1
+ *	If read of SCSI Port Page 2 fails,
+ *		Adapter settings valid
+ *		NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
+ *		Return 1
+ *	Else
+ *		Both valid
+ *		Return 0
+ *	CHECK - what type of locking mechanisms should be used????
+ */
+static int
+mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
+{
+	u8			*pbuf = NULL;
+	dma_addr_t		 buf_dma;
+	CONFIGPARMS		 cfg;
+	ConfigPageHeader_t	 header;
+	int			 ii;
+	int			 data, rc = 0;
+
+	/* Allocate memory 
+	 */
+	if (!ioc->spi_data.nvram) {
+		int	 sz;
+		u8	*mem;
+		sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
+		mem = kmalloc(sz, GFP_KERNEL);
+		if (mem == NULL)
+			return -EFAULT;
+
+		ioc->spi_data.nvram = (int *) mem;
+
+		dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
+			ioc->name, ioc->spi_data.nvram, sz));
+	}
+
+	/* Invalidate NVRAM information
+	 */
+	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+		ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
+	}
+
+	/* Read SPP0 header, allocate memory, then read page.
+	 */
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 0;
+	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+	cfg.hdr = &header;
+	cfg.physAddr = -1;
+	cfg.pageAddr = portnum;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;	/* use default */
+	if (mpt_config(ioc, &cfg) != 0)
+		 return -EFAULT;
+
+	if (header.PageLength > 0) {
+		pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+		if (pbuf) {
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+			cfg.physAddr = buf_dma;
+			if (mpt_config(ioc, &cfg) != 0) {
+				ioc->spi_data.maxBusWidth = MPT_NARROW;
+				ioc->spi_data.maxSyncOffset = 0;
+				ioc->spi_data.minSyncFactor = MPT_ASYNC;
+				ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
+				rc = 1;
+			} else {
+				/* Save the Port Page 0 data
+				 */
+				SCSIPortPage0_t  *pPP0 = (SCSIPortPage0_t  *) pbuf;
+				pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
+				pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
+
+				ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
+				data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
+				if (data) {
+					ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
+					data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
+					ioc->spi_data.minSyncFactor = (u8) (data >> 8);
+				} else {
+					ioc->spi_data.maxSyncOffset = 0;
+					ioc->spi_data.minSyncFactor = MPT_ASYNC;
+				}
+
+				ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
+
+				/* Update the minSyncFactor based on bus type.
+				 */
+				if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
+					(ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE))  {
+
+					if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
+						ioc->spi_data.minSyncFactor = MPT_ULTRA;
+				}
+			}
+			if (pbuf) {
+				pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+				pbuf = NULL;
+			}
+		}
+	}
+
+	/* SCSI Port Page 2 - Read the header then the page.
+	 */
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 2;
+	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+	cfg.hdr = &header;
+	cfg.physAddr = -1;
+	cfg.pageAddr = portnum;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	if (mpt_config(ioc, &cfg) != 0)
+		return -EFAULT;
+
+	if (header.PageLength > 0) {
+		/* Allocate memory and read SCSI Port Page 2
+		 */
+		pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+		if (pbuf) {
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
+			cfg.physAddr = buf_dma;
+			if (mpt_config(ioc, &cfg) != 0) {
+				/* Nvram data is left with INVALID mark
+				 */
+				rc = 1;
+			} else {
+				SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
+				MpiDeviceInfo_t	*pdevice = NULL;
+
+				/* Save the Port Page 2 data
+				 * (reformat into a 32bit quantity)
+				 */
+				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+					pdevice = &pPP2->DeviceSettings[ii];
+					data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
+						(pdevice->SyncFactor << 8) | pdevice->Timeout;
+					ioc->spi_data.nvram[ii] = data;
+				}
+			}
+
+			pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+			pbuf = NULL;
+		}
+	}
 
-	dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name));
-	DBG_DUMP_REPLY_FRAME(mptReply)
+	/* Update Adapter limits with those from NVRAM
+	 * Comment: Don't need to do this. Target performance
+	 * parameters will never exceed the adapters limits.
+	 */
 
-	dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n",
-			ioc->name, u16cnt/2));
-	return u16cnt/2;
+	return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	GetLanConfigPages - Fetch LANConfig pages.
- *	@ioc: Pointer to MPT_ADAPTER structure
+/*	mpt_readScsiDevicePageHeaders - save version and length of SDP1
+ *	@ioc: Pointer to a Adapter Strucutre
+ *	@portnum: IOC port number
  *
- *	Returns 0 for success, non-zero for failure.
+ *	Return: -EFAULT if read of config page header fails
+ *		or 0 if success.
  */
 static int
-GetLanConfigPages(MPT_ADAPTER *ioc)
+mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
 {
-	Config_t		 config_req;
-	ConfigReply_t		 config_reply;
-	LANPage0_t		*page0;
-	dma_addr_t		 page0_dma;
-	LANPage1_t		*page1;
-	dma_addr_t		 page1_dma;
-	int			 i;
-	int			 req_sz;
-	int			 reply_sz;
-	int			 data_sz;
+	CONFIGPARMS		 cfg;
+	ConfigPageHeader_t	 header;
 
-/* LANPage0 */
-	/*  Immediate destination (reply area)...  */
-	reply_sz = sizeof(config_reply);
-	memset(&config_reply, 0, reply_sz);
-
-	/*  Ultimate destination...  */
-	page0 = &ioc->lan_cnfg_page0;
-	data_sz = sizeof(*page0);
-	memset(page0, 0, data_sz);
-
-	/*  Request area (config_req on the stack right now!)  */
-	req_sz = sizeof(config_req);
-	memset(&config_req, 0, req_sz);
-	config_req.Function = MPI_FUNCTION_CONFIG;
-	config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
-	/*	config_req.Header.PageVersion = 0;	*/
-	/*	config_req.Header.PageLength = 0;	*/
-	config_req.Header.PageNumber = 0;
-	config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
-	/*	config_req.PageAddress = 0;		*/
-	config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
-			((MPI_SGE_FLAGS_LAST_ELEMENT |
-			  MPI_SGE_FLAGS_END_OF_BUFFER |
-			  MPI_SGE_FLAGS_END_OF_LIST |
-			  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
-			  MPI_SGE_FLAGS_SYSTEM_ADDRESS |
-			  MPI_SGE_FLAGS_32_BIT_ADDRESSING |
-			  MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
-			(u32)data_sz
-	);
-	page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE);
-	config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma);
+	/* Read the SCSI Device Page 1 header
+	 */
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 1;
+	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+	cfg.hdr = &header;
+	cfg.physAddr = -1;
+	cfg.pageAddr = portnum;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;
+	if (mpt_config(ioc, &cfg) != 0)
+		 return -EFAULT;
+
+	ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
+	ioc->spi_data.sdp1length = cfg.hdr->PageLength;
+
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 0;
+	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+	if (mpt_config(ioc, &cfg) != 0)
+		 return -EFAULT;
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n",
-			ioc->name));
+	ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
+	ioc->spi_data.sdp0length = cfg.hdr->PageLength;
 
-	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
-				reply_sz, (u16*)&config_reply, 3);
-	pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
-	if (i != 0)
-		return i;
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes 
+ *	@ioc: Pointer to a Adapter Strucutre
+ *	@portnum: IOC port number
+ *
+ *	Return:
+ *	0 on success
+ *	-EFAULT if read of config page header fails or data pointer not NULL
+ *	-ENOMEM if pci_alloc failed
+ */
+static int
+mpt_findImVolumes(MPT_ADAPTER *ioc)
+{
+	IOCPage2_t		*pIoc2 = NULL;
+	IOCPage3_t		*pIoc3 = NULL;
+	ConfigPageIoc2RaidVol_t	*pIocRv = NULL;
+	u8			*mem;
+	dma_addr_t		 ioc2_dma;
+	dma_addr_t		 ioc3_dma;
+	CONFIGPARMS		 cfg;
+	ConfigPageHeader_t	 header;
+	int			 jj;
+	int			 rc = 0;
+	int			 iocpage2sz;
+	int			 iocpage3sz = 0;
+	u8			 nVols, nPhys;
+	u8			 vid, vbus, vioc;
+
+	if (ioc->spi_data.pIocPg3)
+		return -EFAULT;	
+
+	/* Read IOCP2 header then the page.
+	 */
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 2;
+	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+	cfg.hdr = &header;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;
+	if (mpt_config(ioc, &cfg) != 0)
+		 return -EFAULT;
+
+	if (header.PageLength == 0)
+		return -EFAULT;
+
+	iocpage2sz = header.PageLength * 4;
+	pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
+	if (!pIoc2)
+		return -ENOMEM;
+
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	cfg.physAddr = ioc2_dma;
+	if (mpt_config(ioc, &cfg) != 0)
+		goto done_and_free;
+
+	/* Identify RAID Volume Id's */
+	nVols = pIoc2->NumActiveVolumes;
+	if ( nVols == 0) {
+		/* No RAID Volumes.  Done.
+		 */
+	} else {
+		/* At least 1 RAID Volume
+		 */
+		pIocRv = pIoc2->RaidVolume;
+		ioc->spi_data.isRaid = 0;
+		for (jj = 0; jj < nVols; jj++, pIocRv++) {
+			vid = pIocRv->VolumeID;
+			vbus = pIocRv->VolumeBus;
+			vioc = pIocRv->VolumeIOC;
+
+			/* find the match
+			 */
+			if (vbus == 0) {
+				ioc->spi_data.isRaid |= (1 << vid);
+			} else {
+				/* Error! Always bus 0
+				 */
+			}
+		}
+	}
 
-	/*  Now byte swap the necessary LANPage0 fields  */
+	/* Identify Hidden Physical Disk Id's */
+	nPhys = pIoc2->NumActivePhysDisks;
+	if (nPhys == 0) {
+		/* No physical disks. Done.
+		 */
+	} else {
+		/* There is at least one physical disk.
+		 * Read and save IOC Page 3
+		 */
+		header.PageVersion = 0;
+		header.PageLength = 0;
+		header.PageNumber = 3;
+		header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+		cfg.hdr = &header;
+		cfg.physAddr = -1;
+		cfg.pageAddr = 0;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+		cfg.dir = 0;
+		cfg.timeout = 0;
+		if (mpt_config(ioc, &cfg) != 0)
+			goto done_and_free;
 
-/* LANPage1 */
-	/*  Immediate destination (reply area)...  */
-	reply_sz = sizeof(config_reply);
-	memset(&config_reply, 0, reply_sz);
-
-	/*  Ultimate destination...  */
-	page1 = &ioc->lan_cnfg_page1;
-	data_sz = sizeof(*page1);
-	memset(page1, 0, data_sz);
-
-	/*  Request area (config_req on the stack right now!)  */
-	req_sz = sizeof(config_req);
-	memset(&config_req, 0, req_sz);
-	config_req.Function = MPI_FUNCTION_CONFIG;
-	config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
-	/*	config_req.Header.PageVersion = 0;	*/
-	/*	config_req.Header.PageLength = 0;	*/
-	config_req.Header.PageNumber = 1;
-	config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
-	/*	config_req.PageAddress = 0;		*/
-	config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
-			((MPI_SGE_FLAGS_LAST_ELEMENT |
-			  MPI_SGE_FLAGS_END_OF_BUFFER |
-			  MPI_SGE_FLAGS_END_OF_LIST |
-			  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
-			  MPI_SGE_FLAGS_SYSTEM_ADDRESS |
-			  MPI_SGE_FLAGS_32_BIT_ADDRESSING |
-			  MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
-			(u32)data_sz
-	);
-	page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE);
-	config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma);
+		if (header.PageLength == 0)
+			goto done_and_free;
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n",
-			ioc->name));
+		/* Read Header good, alloc memory
+		 */
+		iocpage3sz = header.PageLength * 4;
+		pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
+		if (!pIoc3)
+			goto done_and_free;
 
-	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
-				reply_sz, (u16*)&config_reply, 3);
-	pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
-	if (i != 0)
-		return i;
+		/* Read the Page and save the data
+		 * into malloc'd memory.
+		 */
+		cfg.physAddr = ioc3_dma;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+		if (mpt_config(ioc, &cfg) == 0) {
+			mem = kmalloc(iocpage3sz, GFP_KERNEL);
+			if (mem) {
+				memcpy(mem, (u8 *)pIoc3, iocpage3sz);
+				ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
+			}
+		}
+	}
 
-	/*  Now byte swap the necessary LANPage1 fields  */
+done_and_free:
+	if (pIoc2) {
+		pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
+		pIoc2 = NULL;
+	}
 
-	return 0;
+	if (pIoc3) {
+		pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
+		pIoc3 = NULL;
+	}
+
+	return rc;
 }
 
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	SendEventNotification - Send EventNotification (on or off) request
  *	to MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
@@ -2817,13 +4203,13 @@
 
 	evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
 	if (evnp == NULL) {
-		dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n",
+		dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
 				ioc->name));
 		return 0;
 	}
 	memset(evnp, 0, sizeof(*evnp));
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+	dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
 
 	evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
 	evnp->ChainOffset = 0;
@@ -2847,13 +4233,13 @@
 	EventAck_t	*pAck;
 
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
-		printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n",
+		printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
 				ioc->name);
 		return -1;
 	}
 	memset(pAck, 0, sizeof(*pAck));
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name));
+	dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
 
 	pAck->Function     = MPI_FUNCTION_EVENT_ACK;
 	pAck->ChainOffset  = 0;
@@ -2866,25 +4252,212 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS		/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_config - Generic function to issue config message
+ *	@ioc - Pointer to an adapter structure
+ *	@cfg - Pointer to a configuration structure. Struct contains
+ *		action, page address, direction, physical address
+ *		and pointer to a configuration page header
+ *		Page header is updated.
+ *
+ *	Returns 0 for success
+ *	-EPERM if not allowed due to ISR context
+ *	-EAGAIN if no msg frames currently available
+ *	-EFAULT for non-successful reply or no reply (timeout)
+ */
+int
+mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
+{
+	Config_t	*pReq;
+	MPT_FRAME_HDR	*mf;
+	MptSge_t	*psge;
+	unsigned long	 flags;
+	int		 ii, rc;
+	int		 flagsLength;
+	int		 in_isr;
+
+	/* (Bugzilla:fibrebugs, #513)
+	 * Bug fix (part 1)!  20010905 -sralston
+	 *	Prevent calling wait_event() (below), if caller happens
+	 *	to be in ISR context, because that is fatal!
+	 */
+	in_isr = in_interrupt();
+	if (in_isr) {
+		dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+				ioc->name));
+		return -EPERM;
+	}
+
+	/* Get and Populate a free Frame
+	 */
+	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+		dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+				ioc->name));
+		return -EAGAIN;
+	}
+	pReq = (Config_t *)mf;
+	pReq->Action = pCfg->action;
+	pReq->Reserved = 0;
+	pReq->ChainOffset = 0;
+	pReq->Function = MPI_FUNCTION_CONFIG;
+	pReq->Reserved1[0] = 0;
+	pReq->Reserved1[1] = 0;
+	pReq->Reserved1[2] = 0;
+	pReq->MsgFlags = 0;
+	for (ii=0; ii < 8; ii++)
+		pReq->Reserved2[ii] = 0;
+
+	pReq->Header.PageVersion = pCfg->hdr->PageVersion;
+	pReq->Header.PageLength = pCfg->hdr->PageLength;
+	pReq->Header.PageNumber = pCfg->hdr->PageNumber;
+	pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
+	pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
+
+	/* Add a SGE to the config request.
+	 */
+	flagsLength = ((MPI_SGE_FLAGS_LAST_ELEMENT |
+			MPI_SGE_FLAGS_END_OF_BUFFER |
+			MPI_SGE_FLAGS_END_OF_LIST |
+			MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+			MPT_SGE_ADDRESS_SIZE ) << MPI_SGE_FLAGS_SHIFT) |
+			pCfg->hdr->PageLength * 4;
+
+	if (pCfg->dir)
+		flagsLength |= (MPI_SGE_FLAGS_DIRECTION << MPI_SGE_FLAGS_SHIFT);
+
+	psge = (MptSge_t *) &pReq->PageBufferSGE;
+	psge->FlagsLength = cpu_to_le32(flagsLength);
+	cpu_to_leXX(pCfg->physAddr, psge->Address);
+
+	dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+		ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+
+	/* Append pCfg pointer to end of mf
+	 */
+	*((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) =  (void *) pCfg;
+
+	/* Initalize the timer
+	 */
+	init_timer(&pCfg->timer);
+	pCfg->timer.data = (unsigned long) ioc;
+	pCfg->timer.function = mpt_timer_expired;
+	pCfg->wait_done = 0;
+
+	/* Set the timer; ensure 10 second minimum */
+	if (pCfg->timeout < 10)
+		pCfg->timer.expires = jiffies + HZ*10;
+	else
+		pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
+
+	/* Add to end of Q, set timer and then issue this command */
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+	Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM);
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+	add_timer(&pCfg->timer);
+	mpt_put_msg_frame(mpt_base_index, ioc->id, mf);
+	wait_event(mpt_waitq, pCfg->wait_done);
+
+	/* mf has been freed - do not access */
+
+	rc = pCfg->status;
+
+	return rc;
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ *	mpt_timer_expired - Call back for timer process.
+ *	Used only internal config functionality.
+ *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ */
+static void
+mpt_timer_expired(unsigned long data)
+{
+	MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+
+	dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+
+	/* Perform a FW reload */
+	if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+		printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+
+	/* No more processing.
+	 * Hard reset clean-up will wake up
+	 * process and free all resources.
+	 */
+	dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mpt_ioc_reset - Base cleanup for hard reset
+ *	@ioc: Pointer to the adapter structure
+ *	@reset_phase: Indicates pre- or post-reset functionality
+ *
+ *	Remark: Free's resources with internally generated commands.
  */
+static int
+mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+	CONFIGPARMS *pCfg;
+	unsigned long flags;
+
+	dprintk((KERN_WARNING MYNAM
+			": IOC %s_reset routed to MPT base driver!\n",
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+	if (reset_phase == MPT_IOC_PRE_RESET) {
+		/* If the internal config Q is not empty -
+		 * delete timer. MF resources will be freed when
+		 * the FIFO's are primed.
+		 */
+		spin_lock_irqsave(&ioc->FreeQlock, flags);
+		if (! Q_IS_EMPTY(&ioc->configQ)){
+			pCfg = (CONFIGPARMS *)ioc->configQ.head;
+			do {
+				del_timer(&pCfg->timer);
+				pCfg = (CONFIGPARMS *) (pCfg->linkage.forw);
+			} while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+		}
+		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+	} else {
+		CONFIGPARMS *pNext;
+
+		/* Search the configQ for internal commands. 
+		 * Flush the Q, and wake up all suspended threads.
+		 */
+		spin_lock_irqsave(&ioc->FreeQlock, flags);
+		if (! Q_IS_EMPTY(&ioc->configQ)){
+			pCfg = (CONFIGPARMS *)ioc->configQ.head;
+			do {
+				pNext = (CONFIGPARMS *) pCfg->linkage.forw;
 
-#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \
-{ \
-	len -= off;			\
-	if (len < count) {		\
-		*eof = 1;		\
-		if (len <= 0)		\
-			return 0;	\
-	} else				\
-		len = count;		\
-	*start = page + off;		\
-	return len;			\
+				Q_DEL_ITEM(&pCfg->linkage);
+
+				pCfg->status = MPT_CONFIG_ERROR;
+				pCfg->wait_done = 1;
+				wake_up(&mpt_waitq);
+
+				pCfg = pNext;
+			} while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+		}
+		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+	}
+
+	return 1;		/* currently means nothing really */
 }
 
+
+#ifdef CONFIG_PROC_FS		/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
@@ -2894,71 +4467,62 @@
 static int
 procmpt_create(void)
 {
-	MPT_ADAPTER *ioc;
-	struct proc_dir_entry *ent;
-	int errcnt = 0;
+	MPT_ADAPTER		*ioc;
+	struct proc_dir_entry	*ent;
+	int	 ii;
 
 	/*
-	 * 	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
-	 * 	(single level) to multi level (e.g. "driver/message/fusion")
-	 * 	something here needs to change.  -sralston
+	 *	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+	 *	(single level) to multi level (e.g. "driver/message/fusion")
+	 *	something here needs to change.  -sralston
 	 */
-	procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL);
-	if (procmpt_root_dir == NULL)
+	mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
+	if (mpt_proc_root_dir == NULL)
 		return -ENOTDIR;
 
-	if ((ioc = mpt_adapter_find_first()) != NULL) {
-		ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL);
-		if (ent == NULL) {
-			printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n",
-					MPT_PROCFS_SUMMARY_PATHNAME);
-			errcnt++;
+	for (ii=0; ii < MPT_PROC_ENTRIES; ii++) {
+		ent = create_proc_entry(mpt_proc_list[ii].name,
+				S_IFREG|S_IRUGO, mpt_proc_root_dir);
+		if (!ent) {
+			printk(KERN_WARNING MYNAM
+					": WARNING - Could not create /proc/mpt/%s entry\n",
+					mpt_proc_list[ii].name);
+			continue;
 		}
+		ent->read_proc = mpt_proc_list[ii].f;
+		ent->data      = NULL;
 	}
 
+	ioc = mpt_adapter_find_first();
 	while (ioc != NULL) {
-		char pname[32];
-		int namelen;
+		struct proc_dir_entry	*dent;
 		/*
 		 *  Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
 		 */
-		namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
-		if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) {
+		if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) {
 			/*
-			 *  And populate it with: "summary" and "dbg" file entries.
+			 *  And populate it with mpt_ioc_proc_list[] entries.
 			 */
-			(void) sprintf(pname+namelen, "/summary");
-			ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc);
-			if (ent == NULL) {
-				errcnt++;
-				printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
-						ioc->name, pname);
-			}
-//#ifdef MPT_DEBUG
-			/* DEBUG aid! */
-			(void) sprintf(pname+namelen, "/dbg");
-			ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc);
-			if (ent == NULL) {
-				errcnt++;
-				printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
-						ioc->name, pname);
+			for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+				ent = create_proc_entry(mpt_ioc_proc_list[ii].name,
+						S_IFREG|S_IRUGO, dent);
+				if (!ent) {
+					printk(KERN_WARNING MYNAM
+							": WARNING - Could not create /proc/mpt/%s/%s entry!\n",
+							ioc->name,
+							mpt_ioc_proc_list[ii].name);
+					continue;
+				}
+				ent->read_proc = mpt_ioc_proc_list[ii].f;
+				ent->data      = ioc;
 			}
-//#endif
 		} else {
-			errcnt++;
-			printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
-					ioc->name, pname);
-
+			printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n",
+					ioc->name, mpt_ioc_proc_list[ii].name);
 		}
-
 		ioc = mpt_adapter_find_next(ioc);
 	}
 
-	if (errcnt) {
-//		remove_proc_entry("mpt", 0);
-		return -ENOTDIR;
-	}
-
 	return 0;
 }
 
@@ -2971,44 +4535,44 @@
 static int
 procmpt_destroy(void)
 {
-	MPT_ADAPTER *ioc;
+	MPT_ADAPTER	*ioc;
+	int		 ii;
 
-	if (!procmpt_root_dir)
+	if (!mpt_proc_root_dir)
 		return 0;
 
 	/*
-	 * 	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
-	 * 	(single level) to multi level (e.g. "driver/message/fusion")
-	 * 	something here needs to change.  -sralston
+	 *	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+	 *	(single level) to multi level (e.g. "driver/message/fusion")
+	 *	something here needs to change.  -sralston
 	 */
 
 	ioc = mpt_adapter_find_first();
-	if (ioc != NULL) {
-		remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0);
-	}
-
 	while (ioc != NULL) {
 		char pname[32];
 		int namelen;
+
+		namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+
 		/*
 		 *  Tear down each "/proc/mpt/iocN" subdirectory.
 		 */
-		namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
-		(void) sprintf(pname+namelen, "/summary");
-		remove_proc_entry(pname, 0);
-//#ifdef MPT_DEBUG
-		(void) sprintf(pname+namelen, "/dbg");
-		remove_proc_entry(pname, 0);
-//#endif
-		(void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
-		remove_proc_entry(pname, 0);
+		for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+			(void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name);
+			remove_proc_entry(pname, NULL);
+		}
+
+		remove_proc_entry(ioc->name, mpt_proc_root_dir);
 
 		ioc = mpt_adapter_find_next(ioc);
 	}
 
-	if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
-		remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
-		procmpt_root_dir = NULL;
+	for (ii=0; ii < MPT_PROC_ENTRIES; ii++)
+		remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir);
+
+	if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) {
+		remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
+		mpt_proc_root_dir = NULL;
 		return 0;
 	}
 
@@ -3016,23 +4580,23 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	procmpt_read_summary - Handle read request from /proc/mpt/summary
+/*
+ *	procmpt_summary_read - Handle read request from /proc/mpt/summary
  *	or from /proc/mpt/iocN/summary.
- *	@page: Pointer to area to write information
+ *	@buf: Pointer to area to write information
  *	@start: Pointer to start pointer
- *	@off: Offset to start writing
- *	@count: 
+ *	@offset: Offset to start writing
+ *	@request:
  *	@eof: Pointer to EOF integer
- *	@data: Pointer 
+ *	@data: Pointer
  *
- *	Returns numbers of characters written to process performing the read.
+ *	Returns number of characters written to process performing the read.
  */
 static int
-procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data)
+procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
 	MPT_ADAPTER *ioc;
-	char *out = page;
+	char *out = buf;
 	int len;
 
 	if (data == NULL)
@@ -3040,84 +4604,196 @@
 	else
 		ioc = data;
 
-// Too verbose!
-//	out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none");
-
 	while (ioc) {
 		int	more = 0;
 
-// Too verbose!
-//		mpt_print_ioc_facts(ioc, out, &more, 0);
 		mpt_print_ioc_summary(ioc, out, &more, 0, 1);
 
 		out += more;
-		if ((out-page) >= count) {
+		if ((out-buf) >= request) {
 			break;
 		}
 
 		if (data == NULL)
 			ioc = mpt_adapter_find_next(ioc);
 		else
-			ioc = NULL;				/* force exit for iocN */
+			ioc = NULL;		/* force exit for iocN */
 	}
-	len = out - page;
+	len = out - buf;
 
-	PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+	MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
 }
 
-// debug aid!
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg.
- *	@page: Pointer to area to write information
+/*
+ *	procmpt_version_read - Handle read request from /proc/mpt/version.
+ *	@buf: Pointer to area to write information
  *	@start: Pointer to start pointer
- *	@off: Offset to start writing
- *	@count: 
+ *	@offset: Offset to start writing
+ *	@request:
  *	@eof: Pointer to EOF integer
- *	@data: Pointer 
+ *	@data: Pointer
  *
- *	Returns numbers of characters written to process performing the read.
+ *	Returns number of characters written to process performing the read.
  */
 static int
-procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data)
+procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
-	MPT_ADAPTER *ioc;
-	char *out = page;
-	int len;
+	int	 ii;
+	int	 scsi, lan, ctl, targ, dmp;
+	char	*drvname;
+	int	 len;
+
+	len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
+	len += sprintf(buf+len, "  Fusion MPT base driver\n");
+
+	scsi = lan = ctl = targ = dmp = 0;
+	for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+		drvname = NULL;
+		if (MptCallbacks[ii]) {
+			switch (MptDriverClass[ii]) {
+			case MPTSCSIH_DRIVER:
+				if (!scsi++) drvname = "SCSI host";
+				break;
+			case MPTLAN_DRIVER:
+				if (!lan++) drvname = "LAN";
+				break;
+			case MPTSTM_DRIVER:
+				if (!targ++) drvname = "SCSI target";
+				break;
+			case MPTCTL_DRIVER:
+				if (!ctl++) drvname = "ioctl";
+				break;
+			case MPTDMP_DRIVER:
+				if (!dmp++) drvname = "DMP";
+				break;
+			}
+
+			if (drvname)
+				len += sprintf(buf+len, "  Fusion MPT %s driver\n", drvname);
+			/*
+			 *	Handle isense special case, because it
+			 *	doesn't do a formal mpt_register call.
+			 */
+			if (isense_idx == ii)
+				len += sprintf(buf+len, "  Fusion MPT isense driver\n");
+		} else
+			break;
+	}
 
-	ioc = data;
+	MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+}
 
-	while (ioc) {
-		int	more = 0;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
+ *	@buf: Pointer to area to write information
+ *	@start: Pointer to start pointer
+ *	@offset: Offset to start writing
+ *	@request:
+ *	@eof: Pointer to EOF integer
+ *	@data: Pointer
+ *
+ *	Returns number of characters written to process performing the read.
+ */
+static int
+procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+{
+	MPT_ADAPTER	*ioc = data;
+	int		 len;
+	char		 expVer[32];
+	int		 sz;
+	int		 p;
 
-		mpt_print_ioc_facts(ioc, out, &more, 0);
+	mpt_get_fw_exp_ver(expVer, ioc);
 
-		out += more;
-		if ((out-page) >= count) {
-			break;
+	len = sprintf(buf, "%s:", ioc->name);
+	if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
+		len += sprintf(buf+len, "  (f/w download boot flag set)");
+//	if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
+//		len += sprintf(buf+len, "  CONFIG_CHECKSUM_FAIL!");
+
+	len += sprintf(buf+len, "\n  ProductID = 0x%04x (%s)\n",
+			ioc->facts.ProductID,
+			ioc->prod_name);
+	len += sprintf(buf+len, "  FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
+	if (ioc->facts.FWImageSize)
+		len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
+	len += sprintf(buf+len, "\n  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
+	len += sprintf(buf+len, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
+	len += sprintf(buf+len, "  EventState = 0x%02x\n", ioc->facts.EventState);
+
+	len += sprintf(buf+len, "  CurrentHostMfaHighAddr = 0x%08x\n",
+			ioc->facts.CurrentHostMfaHighAddr);
+	len += sprintf(buf+len, "  CurrentSenseBufferHighAddr = 0x%08x\n",
+			ioc->facts.CurrentSenseBufferHighAddr);
+
+	len += sprintf(buf+len, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
+	len += sprintf(buf+len, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+
+	len += sprintf(buf+len, "  RequestFrames @ 0x%p (Dma @ 0x%p)\n",
+					ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma);
+	/*
+	 *  Rounding UP to nearest 4-kB boundary here...
+	 */
+	sz = (ioc->req_sz * ioc->req_depth) + 128;
+	sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+	len += sprintf(buf+len, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+					ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+	len += sprintf(buf+len, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
+					4*ioc->facts.RequestFrameSize,
+					ioc->facts.GlobalCredits);
+
+	len += sprintf(buf+len, "  ReplyFrames   @ 0x%p (Dma @ 0x%p)\n",
+					ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
+	sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+	len += sprintf(buf+len, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+					ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+	len += sprintf(buf+len, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
+					ioc->facts.CurReplyFrameSize,
+					ioc->facts.ReplyQueueDepth);
+
+	len += sprintf(buf+len, "  MaxDevices = %d\n",
+			(ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
+	len += sprintf(buf+len, "  MaxBuses = %d\n", ioc->facts.MaxBuses);
+
+	/* per-port info */
+	for (p=0; p < ioc->facts.NumberOfPorts; p++) {
+		len += sprintf(buf+len, "  PortNumber = %d (of %d)\n",
+				p+1,
+				ioc->facts.NumberOfPorts);
+		if ((int)ioc->chip_type <= (int)FC929) {
+			if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+				u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+				len += sprintf(buf+len, "    LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+						a[5], a[4], a[3], a[2], a[1], a[0]);
+			}
+			len += sprintf(buf+len, "    WWN = %08X%08X:%08X%08X\n",
+					ioc->fc_port_page0[p].WWNN.High,
+					ioc->fc_port_page0[p].WWNN.Low,
+					ioc->fc_port_page0[p].WWPN.High,
+					ioc->fc_port_page0[p].WWPN.Low);
 		}
-		ioc = NULL;
 	}
-	len = out - page;
 
-	PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+	MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
 }
+
 #endif		/* CONFIG_PROC_FS } */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static void
 mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
 {
-	if ((ioc->facts.FWVersion & 0xF000) == 0xE000)
+	buf[0] ='\0';
+	if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
 		sprintf(buf, " (Exp %02d%02d)",
-			(ioc->facts.FWVersion & 0x0F00) >> 8,	/* Month */
-			ioc->facts.FWVersion & 0x001F);		/* Day */
-	else
-		buf[0] ='\0';
+			(ioc->facts.FWVersion.Word >> 16) & 0x00FF,	/* Month */
+			(ioc->facts.FWVersion.Word >> 8) & 0x1F);	/* Day */
 
-	/* insider hack! */
-	if (ioc->facts.FWVersion & 0x0080) {
-		strcat(buf, " [MDBG]");
+		/* insider hack! */
+		if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
+			strcat(buf, " [MDBG]");
 	}
 }
 
@@ -3130,8 +4806,8 @@
  *	@len: Offset at which to start writing in buffer
  *	@showlan: Display LAN stuff?
  *
- * 	This routine writes (english readable) ASCII text, which represents
- * 	a summary of IOC information, to a buffer.
+ *	This routine writes (english readable) ASCII text, which represents
+ *	a summary of IOC information, to a buffer.
  */
 void
 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
@@ -3144,11 +4820,11 @@
 	/*
 	 *  Shorter summary of attached ioc's...
 	 */
-	y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d",
+	y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
 			ioc->name,
 			ioc->prod_name,
 			MPT_FW_REV_MAGIC_ID_STRING,	/* "FwRev=" or somesuch */
-			ioc->facts.FWVersion,
+			ioc->facts.FWVersion.Word,
 			expVer,
 			ioc->facts.NumberOfPorts,
 			ioc->req_depth);
@@ -3159,8 +4835,11 @@
 			a[5], a[4], a[3], a[2], a[1], a[0]);
 	}
 
-	if (ioc->pci_irq < 100)
-		y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#ifndef __sparc__
+	y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#else
+	y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
+#endif
 
 	if (!ioc->active)
 		y += sprintf(buffer+len+y, " (disabled)");
@@ -3171,75 +4850,66 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	Reset Handling
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer.
+ *	mpt_HardResetHandler - Generic reset handler, issue SCSI Task
+ *	Management call based on input arg values.  If TaskMgmt fails,
+ *	return associated SCSI request.
  *	@ioc: Pointer to MPT_ADAPTER structure
- *	@buffer: Pointer to buffer where IOC facts should be written
- *	@size: Pointer to number of bytes we wrote (set by this routine)
- *	@len: Offset at which to start writing in buffer
+ *	@sleepFlag: Indicates if sleep or schedule must be called.
+ *
+ *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *	or a non-interrupt thread.  In the former, must not call schedule().
  *
- * 	This routine writes (english readable) ASCII text, which represents
- * 	a summary of the IOC facts, to a buffer.
+ *	Remark: A return of -1 is a FATAL error case, as it means a
+ *	FW reload/initialization failed.
+ *
+ *	Returns 0 for SUCCESS or -1 if FAILED.
  */
-void
-mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+int
+mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
 {
-	char expVer[32];
-	char iocName[16];
-	int sz;
-	int y;
-	int p;
-
-	mpt_get_fw_exp_ver(expVer, ioc);
+	int		 rc;
+	unsigned long	 flags;
 
-	strcpy(iocName, ioc->name);
-	y = sprintf(buffer+len, "%s:\n", iocName);
+	dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+#ifdef MFCNT
+	printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
+	printk("MF count 0x%x !\n", ioc->mfcnt);
+#endif
 
-	y += sprintf(buffer+len+y, "  ProductID = 0x%04x\n", ioc->facts.ProductID);
-	for (p=0; p < ioc->facts.NumberOfPorts; p++) {
-		y += sprintf(buffer+len+y, "  PortNumber = %d (of %d)\n",
-			p+1,
-			ioc->facts.NumberOfPorts);
-		if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
-			u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
-			y += sprintf(buffer+len+y, "  LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
-				a[5], a[4], a[3], a[2], a[1], a[0]);
-		}
-	}
-	y += sprintf(buffer+len+y, "  FWVersion = 0x%04x%s\n", ioc->facts.FWVersion, expVer);
-	y += sprintf(buffer+len+y, "  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
-	y += sprintf(buffer+len+y, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
-	y += sprintf(buffer+len+y, "  EventState = 0x%02x\n", ioc->facts.EventState);
-	y += sprintf(buffer+len+y, "  CurrentHostMfaHighAddr = 0x%08x\n",
-		 	ioc->facts.CurrentHostMfaHighAddr);
-	y += sprintf(buffer+len+y, "  CurrentSenseBufferHighAddr = 0x%08x\n",
-			ioc->facts.CurrentSenseBufferHighAddr);
-	y += sprintf(buffer+len+y, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
-	y += sprintf(buffer+len+y, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+	/* Reset the adapter. Prevent more than 1 call to
+	 * mpt_do_ioc_recovery at any instant in time.
+	 */
+	spin_lock_irqsave(&ioc->diagLock, flags);
+	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
+		spin_unlock_irqrestore(&ioc->diagLock, flags);
+		return 0;
+	} else {
+		ioc->diagPending = 1;
+	}
+	spin_unlock_irqrestore(&ioc->diagLock, flags);
 
-	y += sprintf(buffer+len+y, "  RequestFrames @ 0x%p (Dma @ 0x%08x)\n",
-					ioc->req_alloc, ioc->req_alloc_dma);
-	/*
-	 *  Rounding UP to nearest 4-kB boundary here...
+	/* FIXME: If do_ioc_recovery fails, repeat....
 	 */
-	sz = (ioc->req_sz * ioc->req_depth) + 128;
-	sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
-	y += sprintf(buffer+len+y, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
-					ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
-	y += sprintf(buffer+len+y, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
-					4*ioc->facts.RequestFrameSize,
-					ioc->facts.GlobalCredits);
 
-	y += sprintf(buffer+len+y, "  ReplyFrames   @ 0x%p (Dma @ 0x%08x)\n",
-					ioc->reply_alloc, ioc->reply_alloc_dma);
-	sz = (ioc->reply_sz * ioc->reply_depth) + 128;
-	y += sprintf(buffer+len+y, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
-					ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
-	y += sprintf(buffer+len+y, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
-					ioc->facts.CurReplyFrameSize,
-					ioc->facts.ReplyQueueDepth);
+	if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
+		printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+			rc, ioc->name);
+	}
 
-	*size = y;
+	spin_lock_irqsave(&ioc->diagLock, flags);
+	ioc->diagPending = 0;
+	if (ioc->alt_ioc)
+		ioc->alt_ioc->diagPending = 0;
+	spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+	dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+
+	return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3268,7 +4938,7 @@
 		ds = "External Bus Reset";
 		break;
 	case MPI_EVENT_RESCAN:
-		ds = "Bus Rescan Event"; 
+		ds = "Bus Rescan Event";
 		/* Ok, do we need to do anything here? As far as
 		   I can tell, this is when a new device gets added
 		   to the loop. */
@@ -3296,6 +4966,9 @@
 		else
 			ds = "Events(OFF) Change";
 		break;
+	case MPI_EVENT_INTEGRATED_RAID:
+		ds = "Integrated Raid";
+		break;
 	/*
 	 *  MPT base "custom" events may be added here...
 	 */
@@ -3307,7 +4980,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	ProcessEventNotification - Route a received EventNotificationReply to
  *	all currently regeistered event handlers.
  *	@ioc: Pointer to MPT_ADAPTER structure
@@ -3322,7 +4995,7 @@
 	u16 evDataLen;
 	u32 evData0 = 0;
 //	u32 evCtx;
-	int i;
+	int ii;
 	int r = 0;
 	int handlers = 0;
 	char *evStr;
@@ -3339,15 +5012,15 @@
 	}
 
 	evStr = EventDescriptionStr(event, evData0);
-	dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n",
+	dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
 			ioc->name,
 			evStr,
 			event));
 
 #if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
 	printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
-	for (i = 0; i < evDataLen; i++)
-		printk(" %08x", le32_to_cpu(pEventReply->Data[i]));
+	for (ii = 0; ii < evDataLen; ii++)
+		printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
 	printk("\n");
 #endif
 
@@ -3365,6 +5038,8 @@
 	case MPI_EVENT_LINK_STATUS_CHANGE:	/* 07 */
 	case MPI_EVENT_LOOP_STATE_CHANGE:	/* 08 */
 	case MPI_EVENT_LOGOUT:			/* 09 */
+	case MPI_EVENT_INTEGRATED_RAID:		/* 0B */
+	case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:	/* 0C */
 	default:
 		break;
 	case MPI_EVENT_EVENT_CHANGE:		/* 0A */
@@ -3382,13 +5057,36 @@
 	}
 
 	/*
+	 * Should this event be logged? Events are written sequentially.
+	 * When buffer is full, start again at the top.
+	 */
+	if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
+		int idx;
+
+		idx = ioc->eventContext % ioc->eventLogSize;
+
+		ioc->events[idx].event = event;
+		ioc->events[idx].eventContext = ioc->eventContext;
+
+		for (ii = 0; ii < 2; ii++) {
+			if (ii < evDataLen)
+				ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
+			else
+				ioc->events[idx].data[ii] =  0;
+		}
+
+		ioc->eventContext++;
+	}
+
+
+	/*
 	 *  Call each currently registered protocol event handler.
 	 */
-	for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
-		if (MptEvHandlers[i]) {
-			dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n",
-					ioc->name, i));
-			r += (*(MptEvHandlers[i]))(ioc, pEventReply);
+	for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+		if (MptEvHandlers[ii]) {
+			dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+					ioc->name, ii));
+			r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
 			handlers++;
 		}
 	}
@@ -3398,7 +5096,9 @@
 	 *  If needed, send (a single) EventAck.
 	 */
 	if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
-		if ((i = SendEventAck(ioc, pEventReply)) != 0) {
+		if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
+			printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+					ioc->name, ii);
 		}
 	}
 
@@ -3427,7 +5127,7 @@
 
 	switch(log_info) {
 /* FCP Initiator */
-    	case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+	case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
 		desc = "Received an out of order frame - unsupported";
 		break;
 	case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
@@ -3483,7 +5183,7 @@
 		desc = "Not sent because login to remote node not validated";
 		break;
 	case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
-		desc = "Cleared from the outbound after a logout";
+		desc = "Cleared from the outbound queue after a logout";
 		break;
 	case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
 		desc = "Cleared waiting for data after a logout";
@@ -3516,7 +5216,7 @@
 		break;
 	}
 
-	printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
+	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}",
 			ioc->name, log_info, subcl_str[subcl]);
 	if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
 		printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
@@ -3539,7 +5239,7 @@
 mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
 {
 	/* FIXME! */
-	printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info);
+	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x)\n", ioc->name, log_info);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3553,7 +5253,7 @@
  *	Specialized driver registration routine for the isense driver.
  */
 int
-mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable)
+mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable)
 {
 	int r = 0;
 
@@ -3562,6 +5262,7 @@
 		mpt_ASCQ_TableSz = ascqtbl_sz;
 		mpt_ScsiOpcodesPtr = opsTable;
 		printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+		isense_idx = last_drv_idx;
 		r = 1;
 	}
 	MOD_INC_USE_COUNT;
@@ -3582,11 +5283,15 @@
 	mpt_ASCQ_TableSz = 0;
 	mpt_ScsiOpcodesPtr = NULL;
 	printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+	isense_idx = -1;
 	MOD_DEC_USE_COUNT;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+EXPORT_SYMBOL(mpt_adapters);
+EXPORT_SYMBOL(mpt_proc_root_dir);
+EXPORT_SYMBOL(DmpService);
 EXPORT_SYMBOL(mpt_register);
 EXPORT_SYMBOL(mpt_deregister);
 EXPORT_SYMBOL(mpt_event_register);
@@ -3597,12 +5302,16 @@
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_free_msg_frame);
 EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_handshake_req_reply_wait);
 EXPORT_SYMBOL(mpt_adapter_find_first);
 EXPORT_SYMBOL(mpt_adapter_find_next);
 EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_GetIocState);
 EXPORT_SYMBOL(mpt_print_ioc_summary);
 EXPORT_SYMBOL(mpt_lan_index);
 EXPORT_SYMBOL(mpt_stm_index);
+EXPORT_SYMBOL(mpt_HardResetHandler);
+EXPORT_SYMBOL(mpt_config);
 
 EXPORT_SYMBOL(mpt_register_ascqops_strings);
 EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
@@ -3611,12 +5320,13 @@
 EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	fusion_init - Fusion MPT base driver initialization routine.
  *
  *	Returns 0 for success, non-zero for failure.
  */
-int __init fusion_init(void)
+int __init
+fusion_init(void)
 {
 	int i;
 
@@ -3636,12 +5346,22 @@
 		MptResetHandlers[i] = NULL;
 	}
 
+	DmpService = NULL;
+
 	/* NEW!  20010120 -sralston
 	 *  Register ourselves (mptbase) in order to facilitate
 	 *  EventNotification handling.
 	 */
 	mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
 
+	/* Register for hard reset handling callbacks.
+	 */
+	if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
+		dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
+	} else {
+		/* FIXME! */
+	}
+
 	if ((i = mpt_pci_scan()) < 0)
 		return i;
 
@@ -3649,13 +5369,14 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *	fusion_exit - Perform driver unload cleanup.
  *
  *	This routine frees all resources associated with each MPT adapter
  *	and removes all %MPT_PROCFS_MPTBASEDIR entries.
  */
-static void fusion_exit(void)
+static void
+fusion_exit(void)
 {
 	MPT_ADAPTER *this;
 
@@ -3665,7 +5386,7 @@
 	 *  Moved this *above* removal of all MptAdapters!
 	 */
 #ifdef CONFIG_PROC_FS
-	procmpt_destroy();
+	(void) procmpt_destroy();
 #endif
 
 	while (! Q_IS_EMPTY(&MptAdapters)) {
@@ -3673,6 +5394,8 @@
 		Q_DEL_ITEM(this);
 		mpt_adapter_dispose(this);
 	}
+
+	mpt_reset_deregister(mpt_base_index);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptbase.h linux-2.4.19-pre5/drivers/message/fusion/mptbase.h
--- linux-2.4.19-pre4/drivers/message/fusion/mptbase.h	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptbase.h	Fri Mar 29 14:49:34 2002
@@ -8,11 +8,12 @@
  *  Credits:
  *     (see mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.46.2.2.2.2 2001/09/18 03:22:29 sralston Exp $
+ *  $Id: mptbase.h,v 1.103 2002/02/27 20:24:38 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -55,6 +56,7 @@
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #include "linux_compat.h"	/* linux-2.2.x (vs. -2.4.x) tweaks */
+#include "scsi3.h"		/* SCSI defines */
 
 #include "lsi/mpi_type.h"
 #include "lsi/mpi.h"		/* Fusion MPI(nterface) basic defs */
@@ -62,6 +64,7 @@
 #include "lsi/mpi_cnfg.h"	/* IOC configuration support */
 #include "lsi/mpi_init.h"	/* SCSI Host (initiator) protocol support */
 #include "lsi/mpi_lan.h"	/* LAN over FC protocol support */
+#include "lsi/mpi_raid.h"	/* Integrated Mirroring support */
 
 #include "lsi/mpi_fc.h"		/* Fibre Channel (lowlevel) support */
 #include "lsi/mpi_targ.h"	/* SCSI/FCP Target protcol support */
@@ -74,11 +77,11 @@
 #endif
 
 #ifndef COPYRIGHT
-#define COPYRIGHT	"Copyright (c) 1999-2001 " MODULEAUTHOR
+#define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"1.02.02"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-1.02.02"
+#define MPT_LINUX_VERSION_COMMON	"2.00.11"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.00.11"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -89,39 +92,77 @@
  *  Fusion MPT(linux) driver configurable stuff...
  */
 #define MPT_MAX_ADAPTERS		16
-#define MPT_MAX_PROTOCOL_DRIVERS	8
+#define MPT_MAX_PROTOCOL_DRIVERS	16
+#define MPT_MAX_BUS			1
 #define MPT_MAX_FC_DEVICES		255
+#define MPT_MAX_SCSI_DEVICES		16
+#define MPT_LAST_LUN			31
+#define MPT_SENSE_BUFFER_ALLOC		64
+	/* allow for 256 max sense alloc, but only 255 max request */
+#if MPT_SENSE_BUFFER_ALLOC >= 256
+#	undef MPT_SENSE_BUFFER_ALLOC
+#	define MPT_SENSE_BUFFER_ALLOC	256
+#	define MPT_SENSE_BUFFER_SIZE	255
+#else
+#	define MPT_SENSE_BUFFER_SIZE	MPT_SENSE_BUFFER_ALLOC
+#endif
 
-#define MPT_MISCDEV_BASENAME		"mptctl"
-#define MPT_MISCDEV_PATHNAME		"/dev/" MPT_MISCDEV_BASENAME
+#define MPT_NAME_LENGTH			32
 
 #define MPT_PROCFS_MPTBASEDIR		"mpt"
 						/* chg it to "driver/fusion" ? */
-#define MPT_PROCFS_SUMMARY_NODE		MPT_PROCFS_MPTBASEDIR "/summary"
-#define MPT_PROCFS_SUMMARY_PATHNAME	"/proc/" MPT_PROCFS_SUMMARY_NODE
-#define MPT_FW_REV_MAGIC_ID_STRING	"FwRev="
+#define MPT_PROCFS_SUMMARY_ALL_NODE		MPT_PROCFS_MPTBASEDIR "/summary"
+#define MPT_PROCFS_SUMMARY_ALL_PATHNAME		"/proc/" MPT_PROCFS_SUMMARY_ALL_NODE
+#define MPT_FW_REV_MAGIC_ID_STRING		"FwRev="
 
-#ifdef __KERNEL__	/* { */
 #define  MPT_MAX_REQ_DEPTH		1023
-#define  MPT_REQ_DEPTH			256
+#define  MPT_DEFAULT_REQ_DEPTH		256
 #define  MPT_MIN_REQ_DEPTH		128
 
 #define  MPT_MAX_REPLY_DEPTH		MPT_MAX_REQ_DEPTH
-#define  MPT_REPLY_DEPTH		128
+#define  MPT_DEFAULT_REPLY_DEPTH	128
 #define  MPT_MIN_REPLY_DEPTH		8
 #define  MPT_MAX_REPLIES_PER_ISR	32
 
 #define  MPT_MAX_FRAME_SIZE		128
-#define  MPT_REQ_SIZE			128
-#define  MPT_REPLY_SIZE			128
+#define  MPT_DEFAULT_FRAME_SIZE		128
 
-#define  MPT_SG_BUCKETS_PER_HUNK	1
+#define  MPT_SG_REQ_128_SCALE		1
+#define  MPT_SG_REQ_96_SCALE		2
+#define  MPT_SG_REQ_64_SCALE		4
 
-#ifdef MODULE
-#define  MPT_REQ_DEPTH_RANGE_STR	__MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH)
-#define  MPT_REPLY_DEPTH_RANGE_STR	__MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH)
-#define  MPT_REPLY_SIZE_RANGE_STR	__MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE)
-#endif
+#define	 CAN_SLEEP			1
+#define  NO_SLEEP			0
+
+/* 
+ * SCSI transfer rate defines. 
+ */
+#define MPT_ULTRA320			0x08
+#define MPT_ULTRA160			0x09
+#define MPT_ULTRA2			0x0A
+#define MPT_ULTRA			0x0C
+#define MPT_FAST			0x19
+#define MPT_SCSI			0x32
+#define MPT_ASYNC			0xFF
+
+#define MPT_NARROW			0
+#define MPT_WIDE			1
+
+#ifdef __KERNEL__	/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/proc_fs.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Attempt semi-consistent error & warning msgs across
+ * MPT drivers.  NOTE: Users of these macro defs must
+ * themselves define their own MYNAM.
+ */
+#define MYIOC_s_INFO_FMT		KERN_INFO MYNAM ": %s: "
+#define MYIOC_s_NOTE_FMT		KERN_NOTICE MYNAM ": %s: "
+#define MYIOC_s_WARN_FMT		KERN_WARNING MYNAM ": %s: WARNING - "
+#define MYIOC_s_ERR_FMT			KERN_ERR MYNAM ": %s: ERROR - "
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -133,6 +174,7 @@
 	MPTSCSIH_DRIVER,	/* MPT SCSI host (initiator) class */
 	MPTLAN_DRIVER,		/* MPT LAN class */
 	MPTSTM_DRIVER,		/* MPT SCSI target mode class */
+	MPTDMP_DRIVER,		/* MPT Dynamic Multi-pathing class */
 	MPTUNKNOWN_DRIVER
 } MPT_DRIVER_CLASS;
 
@@ -145,10 +187,21 @@
 		struct _MPT_FRAME_HDR	*forw;
 		struct _MPT_FRAME_HDR	*back;
 		u32			 arg1;
+		u32			 pad;
 		void			*argp1;
+#ifndef MPT_SCSI_USE_NEW_EH
+		void			*argp2;
+#endif
 	} linkage;
 	/*
-	 * NOTE: On non-32-bit systems, where pointers are LARGE,
+	 * NOTE: When request frames are free, on the linkage structure
+	 * contets are valid.  All other values are invalid.
+	 * In particular, do NOT reply on offset [2]
+	 * (in words) being the * message context.
+	 * The message context must be reset (computed via base address
+	 * + an offset) prior to issuing any command.
+	 *
+	 * NOTE2: On non-32-bit systems, where pointers are LARGE,
 	 * using the linkage pointers destroys our sacred MsgContext
 	 * field contents.  But we don't care anymore because these
 	 * are now reset in mpt_put_msg_frame() just prior to sending
@@ -169,6 +222,12 @@
 			} fld;
 		} msgctxu;
 	} hwhdr;
+	/*
+	 * Remark: 32 bit identifier:
+	 *  31-24: reserved
+	 *  23-16: call back index
+	 *  15-0 : request index
+	 */
 } MPT_FRAME_TRACKER;
 
 /*
@@ -189,6 +248,11 @@
 	} u;
 } MPT_FRAME_HDR;
 
+#define MPT_REQ_MSGFLAGS_DROPME		0x80
+
+/* Used for tracking the free request frames
+ * and free reply frames.
+ */
 typedef struct _MPT_Q_TRACKER {
 	MPT_FRAME_HDR	*head;
 	MPT_FRAME_HDR	*tail;
@@ -214,9 +278,20 @@
 	struct _Q_ITEM	*tail;
 } Q_TRACKER;
 
+typedef struct _MPT_DONE_Q {
+	struct _MPT_DONE_Q	*forw;
+	struct _MPT_DONE_Q	*back;
+	void			*argp;
+} MPT_DONE_Q;
+
+typedef struct _DONE_Q_TRACKER {
+	MPT_DONE_Q	*head;
+	MPT_DONE_Q	*tail;
+} DONE_Q_TRACKER;
 
 /*
- *  Chip-specific stuff...
+ *  Chip-specific stuff... FC929 delineates break between
+ *  FC and Parallel SCSI parts. Do NOT re-order.
  */
 
 typedef enum {
@@ -237,7 +312,9 @@
 	u32	WriteSequence;	/* 04     Write Sequence register    */
 	u32	Diagnostic;	/* 08     Diagnostic register        */
 	u32	TestBase;	/* 0C     Test Base Address          */
-	u32	Reserved1[8];	/* 10-2F  reserved for future use    */
+	u32	DiagRwData;	/* 10     Read Write Data (fw download)   */
+	u32	DiagRwAddress;	/* 14     Read Write Address (fw download)*/
+	u32	Reserved1[6];	/* 18-2F  reserved for future use    */
 	u32	IntStatus;	/* 30     Interrupt Status           */
 	u32	IntMask;	/* 34     Interrupt Mask             */
 	u32	Reserved2[2];	/* 38-3F  reserved for future use    */
@@ -256,60 +333,271 @@
  */
 
 
+/*
+ *	Dynamic Multi-Pathing specific stuff...
+ */
+#define DMP_MAX_PATHS	8
+
+typedef struct _PathInfo {
+	u8		 ioc;
+	u8		 target;
+	u8		 pad;
+	u8		 pflags;
+} PathInfo;
+
+#define PATHINFO_FLAGS_OWNED		0x01
+#define PATHINFO_FLAGS_EXISTS		0x02
+#define PATHINFO_FLAGS_AVAILABLE	0x04
+#define PATHINFO_FLAGS_SECONDARY	0x08
+
+#define PFLAGS_EXISTS_AND_AVAIL		(PATHINFO_FLAGS_EXISTS|PATHINFO_FLAGS_AVAILABLE)
+#define PFLAGS_AVAIL_AND_OWNED		(PATHINFO_FLAGS_AVAILABLE|PATHINFO_FLAGS_OWNED)
+
+typedef struct _ScsiCmndTracker {
+	void			*head;
+	void			*tail;
+} ScsiCmndTracker;
+
+
+/*
+ *	VirtDevice - FC LUN device or SCSI target device
+ *	(used to be FCSCSI_TARGET)
+ */
+typedef struct _VirtDevice {
+	struct _VirtDevice	*forw;
+	struct _VirtDevice	*back;
+	rwlock_t		 VdevLock;
+	int			 ref_cnt;
+	u8			 tflags;
+	u8			 ioc_id;
+	u8			 target_id;
+	u8			 bus_id;
+	u8			 minSyncFactor;	/* 0xFF is async */
+	u8			 maxOffset;	/* 0 if async */
+	u8			 maxWidth;	/* 0 if narrow, 1 if wide*/
+	u8			 negoFlags;	/* 0 if WDTR/SDTR allowed */
+	u8			 raidVolume;	/* set, if RAID Volume */
+	u8			 rsvd;		/* alignment */
+	u16			 rsvd1raid;
+	int			 npaths;
+	u16			 fc_phys_lun;
+	u16			 fc_xlat_lun;
+	int			 stall_detected;
+	PathInfo		 path[DMP_MAX_PATHS];
+	struct timer_list	 stall_timer;
+	struct timer_list	 retry_timer;
+	struct timer_list	 gone_timer;
+	ScsiCmndTracker		 WaitQ;
+	ScsiCmndTracker		 SentQ;
+	ScsiCmndTracker		 DoneQ;
+//--- LUN split here?
+	u8			 sense[SCSI_STD_SENSE_BYTES];		/* 18 */
+	u8			 rsvd2[2];	/* alignment */
+	u32			 luns;		/* Max LUNs is 32 */
+	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
+	u8			 pad0[4];
+	u8			 uniq_prepad[8];
+	u8			 inq00_data[20];
+	u8			 pad1[4];
+		/* IEEE Registered Extended Identifier
+		   obtained via INQUIRY VPD page 0x83 */
+	u8			 uniq_data[20];
+	u8			 pad2[4];
+	u8			 inqC3_data[12];
+	u8			 pad3[4];
+	u8			 inqC9_data[12];
+	u8			 pad4[4];
+	u8			 dev_vol_name[64];
+} VirtDevice;
+
+/*
+ *  Fibre Channel (SCSI) target device and associated defines...
+ */
+#define MPT_TARGET_DEFAULT_DV_STATUS	0
+#define MPT_TARGET_FLAGS_VALID_NEGO	0x01
+#define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
+#define MPT_TARGET_FLAGS_VALID_SENSE	0x04
+#define MPT_TARGET_FLAGS_Q_YES		0x08
+
+#define MPT_TARGET_NO_NEGO_WIDE		0x01
+#define MPT_TARGET_NO_NEGO_SYNC		0x02
+
+typedef struct _VirtDevTracker {
+	struct _VirtDevice	*head;
+	struct _VirtDevice	*tail;
+	rwlock_t		 VlistLock;
+	int			 pad;
+} VirtDevTracker;
+
+
+/*
+ *	/proc/mpt interface
+ */
+typedef struct {
+	const char	*name;
+	mode_t		 mode;
+	int		 pad;
+	read_proc_t	*read_proc;
+	write_proc_t	*write_proc;
+} mpt_proc_entry_t;
+
+#define MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len) \
+do { \
+	len -= offset;			\
+	if (len < request) {		\
+		*eof = 1;		\
+		if (len <= 0)		\
+			return 0;	\
+	} else				\
+		len = request;		\
+	*start = buf + offset;		\
+	return len;			\
+} while (0)
+
+
+/*
+ *	IOCTL structure and associated defines
+ */
+
+#define MPT_IOCTL_STATUS_DID_TIMEOUT	0x01	/* The current IOCTL timed out */
+#define MPT_IOCTL_STATUS_RF_VALID	0x02	/* The Reply Frame is VALID */
+#define MPT_IOCTL_STATUS_TIMER_ACTIVE	0x04	/* The timer is running */
+#define MPT_IOCTL_STATUS_SENSE_VALID	0x08	/* Sense data is valid */
+#define MPT_IOCTL_STATUS_COMMAND_GOOD	0x10	/* Command Status GOOD */
+
+typedef struct _MPT_IOCTL {
+	struct _MPT_ADAPTER	*ioc;
+	struct timer_list	 timer;		/* timer function for this adapter */
+	u8			 ReplyFrame[MPT_DEFAULT_FRAME_SIZE];	/* reply frame data */
+	u8			 sense[MPT_SENSE_BUFFER_ALLOC];
+	int			 wait_done;	/* wake-up value for this ioc */
+	u8			 cmd;		/* current command */
+	u8			 status;	/* current command status */
+	u8			 pad[2];
+} MPT_IOCTL;
+
+/*
+ *  Event Structure and define
+ */
+#define MPTCTL_EVENT_LOG_SIZE		(0x0000000A)
+typedef struct _mpt_ioctl_events {
+	u32	event;		/* Specified by define above */
+	u32	eventContext;	/* Index or counter */
+	int	data[2];	/* First 8 bytes of Event Data */
+} MPT_IOCTL_EVENTS;
+
+/*
+ * CONFIGPARM status  defines
+ */
+#define MPT_CONFIG_GOOD		MPI_IOCSTATUS_SUCCESS
+#define MPT_CONFIG_ERROR	0x002F
+
+/*
+ *	Substructure to store SCSI specific configuration page data
+ */
+#define MPT_SCSICFG_NEGOTIATE		0x01	/* Negotiate on next IO */
+#define MPT_SCSICFG_NEED_DV		0x02	/* Schedule DV */
+#define MPT_SCSICFG_DV_PENDING		0x04	/* DV on this physical id pending */
+#define MPT_SCSICFG_DV_DONE		0x08	/* DV on this physical id complete */
+
+#define MPT_SCSICFG_USE_NVRAM		0x01	/* WriteSDP1 using NVRAM */
+#define MPT_SCSICFG_ALL_IDS		0x02	/* WriteSDP1 to all IDS */
+
+typedef	struct _ScsiCfgData {
+	int		*nvram;			/* table of device NVRAM values */
+	IOCPage3_t	*pIocPg3;		/* table of physical disks */
+	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
+	int		 isRaid;		/* bit field, 1 if RAID */
+	u8		 minSyncFactor;		/* 0xFF if async */
+	u8		 maxSyncOffset;		/* 0 if async */
+	u8		 maxBusWidth;		/* 0 if narrow, 1 if wide */
+	u8		 busType;		/* SE, LVD, HD */
+	u8		 sdp1version;		/* SDP1 version */
+	u8		 sdp1length;		/* SDP1 length  */
+	u8		 sdp0version;		/* SDP0 version */
+	u8		 sdp0length;		/* SDP0 length  */
+	u8		 dvScheduled;		/* 1 if scheduled */
+	u8		 forceDv;		/* 1 to force DV scheduling */
+	u8		 rsvd[2];
+} ScsiCfgData;
+
+/*
+ *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
+ */
 typedef struct _MPT_ADAPTER
 {
 	struct _MPT_ADAPTER	*forw;
 	struct _MPT_ADAPTER	*back;
-	int			 id;		/* Unique adapter id {0,1,2,...} */
-	int			 pci_irq;
-	char			 name[32];	/* "iocN"             */
+	int			 id;		/* Unique adapter id N {0,1,2,...} */
+	int			 pci_irq;	/* This irq           */
+	char			 name[MPT_NAME_LENGTH];	/* "iocN"             */
 	char			*prod_name;	/* "LSIFC9x9"         */
-	u32			 mem_phys;	/* == f4020000 (mmap) */
 	volatile SYSIF_REGS	*chip;		/* == c8817000 (mmap) */
-	CHIP_TYPE		 chip_type;
-	int			 mem_size;
+	volatile SYSIF_REGS	*pio_chip;	/* Programmed IO (downloadboot) */
+	u32			 mem_phys;	/* == f4020000 (mmap) */
+	u32			 pio_mem_phys;	/* Programmed IO (downloadboot) */
+	int			 mem_size;	/* mmap memory size */
 	int			 alloc_total;
 	u32			 last_state;
 	int			 active;
-	int			 sod_reset;
-	unsigned long		 last_kickstart;
-	u8			*reply_alloc;		/* Reply frames alloc ptr */
+	u8			*reply_alloc;	/* Reply frames alloc ptr */
 	dma_addr_t		 reply_alloc_dma;
-	MPT_FRAME_HDR		*reply_frames;		/* Reply frames - rounded up! */
+	MPT_FRAME_HDR		*reply_frames;	/* Reply msg frames - rounded up! */
 	dma_addr_t		 reply_frames_dma;
-	int			 reply_depth;
-	int			 reply_sz;
+	u32			 reply_frames_low_dma;
+	int			 reply_depth;	/* Num Allocated reply frames */
+	int			 reply_sz;	/* Reply frame size */
+	CHIP_TYPE		 chip_type;
 		/* We (host driver) get to manage our own RequestQueue! */
-	u8			*req_alloc;		/* Request frames alloc ptr */
+	u8			*req_alloc;	/* Request frames alloc ptr */
 	dma_addr_t		 req_alloc_dma;
-	MPT_FRAME_HDR		*req_frames;		/* Request msg frames for PULL mode! */
+	MPT_FRAME_HDR		*req_frames;	/* Request msg frames - rounded up! */
 	dma_addr_t		 req_frames_dma;
-	int			 req_depth;
-	int			 req_sz;
-	MPT_Q_TRACKER		 FreeQ;
+	u32			 req_frames_low_dma;
+	int			 req_depth;	/* Number of request frames */
+	int			 req_sz;	/* Request frame size (bytes) */
 	spinlock_t		 FreeQlock;
+	MPT_Q_TRACKER		 FreeQ;
 		/* Pool of SCSI sense buffers for commands coming from
 		 * the SCSI mid-layer.  We have one 256 byte sense buffer
 		 * for each REQ entry.
 		 */
 	u8			*sense_buf_pool;
 	dma_addr_t		 sense_buf_pool_dma;
-	struct pci_dev		*pcidev;
-/*	atomic_t		 userCnt;	*/
-	u8			*memmap;
+	u32			 sense_buf_low_dma;
 	int			 mtrr_reg;
-	struct Scsi_Host	*sh;
+	void			*pcidev;	/* struct pci_dev pointer */
+	u8			*memmap;	/* mmap address */
+	struct Scsi_Host	*sh;		/* Scsi Host pointer */
+	ScsiCfgData		spi_data;	/* Scsi config. data */
+	MPT_IOCTL		*ioctl;		/* ioctl data pointer */
 	struct proc_dir_entry	*ioc_dentry;
-	struct _MPT_ADAPTER	*alt_ioc;
+	struct _MPT_ADAPTER	*alt_ioc;	/* ptr to 929 bound adapter port */
+	spinlock_t		 diagLock;	/* diagnostic reset lock */
+	int			 diagPending;
+	u32			 biosVersion;	/* BIOS version from IO Unit Page 2 */
+	int			 eventTypes;	/* Event logging parameters */
+	int			 eventContext;	/* Next event context */
+	int			 eventLogSize;	/* Max number of cached events */
+	struct _mpt_ioctl_events *events;	/* pointer to event log */
+	u8			*FWImage;	/* Pointer to FW */
+	dma_addr_t		 FWImage_dma;
+	Q_TRACKER		 configQ;	/* linked list of config. requests */
 	int			 hs_reply_idx;
+#ifndef MFCNT
+	u32			 pad0;
+#else
+	u32			 mfcnt;
+#endif
 	u32			 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
 	u16			 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
 	IOCFactsReply_t		 facts;
 	PortFactsReply_t	 pfacts[2];
+	FCPortPage0_t		 fc_port_page0[2];
 	LANPage0_t		 lan_cnfg_page0;
 	LANPage1_t		 lan_cnfg_page1;
 	u8			 FirstWhoInit;
-	u8			 pad1[3];
+	u8			 pad1[7];
 } MPT_ADAPTER;
 
 
@@ -324,7 +612,6 @@
  *    0 = not Ok ...
  */
 typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
-
 typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply);
 typedef int (*MPT_RESETHANDLER)(MPT_ADAPTER *ioc, int reset_phase);
 /* reset_phase defs */
@@ -344,6 +631,47 @@
 #define MPT_HOSTEVENT_IOC_BRINGUP	0x91
 #define MPT_HOSTEVENT_IOC_RECOVER	0x92
 
+/* 32 vs 64 bit SGL code.
+ *
+ */
+#if defined(__ia64__)
+typedef SGESimple64_t	MptSge_t;
+typedef SGEChain64_t	MptChain_t;
+
+#define cpu_to_leXX(y, p) { \
+	u32 low = (u32) (y & 0xFFFFFFFF); \
+	u32 high = (u32) (y >> 32); \
+	p.Low = cpu_to_le32(low); \
+	p.High = cpu_to_le32(high); \
+}
+
+#define leXX_to_cpu(y, p) { \
+	y = (dma_addr_t) le32_to_cpu(p.High); \
+	y = (y << 32); \
+	y |= le32_to_cpu(p.Low); \
+}
+
+#define MPT_SGE_ADDRESS_SIZE		MPI_SGE_FLAGS_64_BIT_ADDRESSING
+#define MPT_SCSIIO_MSG_FLAGS		MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64
+
+
+#else
+
+typedef SGESimple32_t	MptSge_t;
+typedef SGEChain32_t	MptChain_t;
+#define cpu_to_leXX(y,p) { \
+	p = cpu_to_le32(y); \
+}
+
+#define leXX_to_cpu(y,p) { \
+	y = le32_to_cpu(p); \
+}
+
+#define MPT_SGE_ADDRESS_SIZE		MPI_SGE_FLAGS_32_BIT_ADDRESSING
+#define MPT_SCSIIO_MSG_FLAGS		MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32
+
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Funky (private) macros...
@@ -360,7 +688,8 @@
 #define dhsprintk(x)
 #endif
 
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+//#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#if defined(MPT_DEBUG_MSG_FRAME)
 #define dmfprintk(x)  printk x
 #else
 #define dmfprintk(x)
@@ -372,24 +701,35 @@
 #define dirqprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_EVENTS
-#define deventprintk(x)  printk x
+#ifdef MPT_DEBUG_SG
+#define dsgprintk(x)  printk x
 #else
-#define deventprintk(x)
+#define dsgprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_SPINLOCK
-#define dslprintk(x)  printk x
+#ifdef MPT_DEBUG_DV
+#define ddvprintk(x)  printk x
 #else
-#define dslprintk(x)
+#define ddvprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_SG
-#define dsgprintk(x)  printk x
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+#define ddvtprintk(x)  printk x
 #else
-#define dsgprintk(x)
+#define ddvtprintk(x)
 #endif
 
+#ifdef MPT_DEBUG_IOCTL
+#define dctlprintk(x) printk x
+#else
+#define dctlprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_RESET
+#define dtmprintk(x) printk x
+#else
+#define dtmprintk(x)
+#endif
 
 #define MPT_INDEX_2_MFPTR(ioc,idx) \
 	(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
@@ -397,6 +737,9 @@
 #define MFPTR_2_MPT_INDEX(ioc,mf) \
 	(int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz )
 
+#define MPT_INDEX_2_RFPTR(ioc,idx) \
+	(MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) )
+
 #define Q_INIT(q,type)  (q)->head = (q)->tail = (type*)(q)
 #define Q_IS_EMPTY(q)   ((Q_ITEM*)(q)->head == (Q_ITEM*)(q))
 
@@ -425,7 +768,6 @@
 	_forw->back = _back; \
 }
 
-
 #define SWAB4(value) \
 	(u32)(   (((value) & 0x000000ff) << 24) \
 	       | (((value) & 0x0000ff00) << 8)  \
@@ -457,64 +799,143 @@
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#endif		/* } __KERNEL__ */
 
+/*
+ * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers
+ * Private to the driver.
+ */
+/* LOCAL structure and fields used when processing
+ * internally generated commands. These include:
+ * bus scan, dv and config requests.
+ */
+typedef struct _MPT_LOCAL_REPLY {
+	ConfigPageHeader_t header;
+	int	completion;
+	u8	sense[SCSI_STD_SENSE_BYTES];
+	u8	scsiStatus;
+	u8	skip;
+	u32	pad;
+} MPT_LOCAL_REPLY;
+
+#define MPT_HOST_BUS_UNKNOWN		(0xFF)
+#define MPT_HOST_TOO_MANY_TM		(0x05)
+#define MPT_HOST_NVRAM_INVALID		(0xFFFFFFFF)
+#define MPT_HOST_NO_CHAIN		(0xFFFFFFFF)
+#define MPT_NVRAM_MASK_TIMEOUT		(0x000000FF)
+#define MPT_NVRAM_SYNC_MASK		(0x0000FF00)
+#define MPT_NVRAM_SYNC_SHIFT		(8)
+#define MPT_NVRAM_DISCONNECT_ENABLE	(0x00010000)
+#define MPT_NVRAM_ID_SCAN_ENABLE	(0x00020000)
+#define MPT_NVRAM_LUN_SCAN_ENABLE	(0x00040000)
+#define MPT_NVRAM_TAG_QUEUE_ENABLE	(0x00080000)
+#define MPT_NVRAM_WIDE_DISABLE		(0x00100000)
+#define MPT_NVRAM_BOOT_CHOICE		(0x00200000)
+
+typedef struct _MPT_SCSI_HOST {
+	MPT_ADAPTER		 *ioc;
+	int			  port;
+	u32			  pad0;
+	struct scsi_cmnd	**ScsiLookup;
+		/* Pool of buffers for chaining. ReqToChain
+		 * and ChainToChain track index of chain buffers.
+		 * ChainBuffer (DMA) virt/phys addresses.
+		 * FreeChainQ (lock) locking mechanisms.
+		 */
+	int			 *ReqToChain;
+	int			 *ChainToChain;
+	u8			 *ChainBuffer;
+	dma_addr_t		  ChainBufferDMA;
+	MPT_Q_TRACKER		  FreeChainQ;
+	spinlock_t		  FreeChainQlock;
+	u32			  qtag_tick;
+	VirtDevice		**Targets;
+	MPT_LOCAL_REPLY		 *pLocal;		/* used for internal commands */
+	struct timer_list	  timer;
+	struct timer_list	  TMtimer;		/* Timer for TM commands ONLY */
+		/* Pool of memory for holding SCpnts before doing
+		 * OS callbacks. freeQ is the free pool.
+		 */
+	u8			 *memQ;
+	DONE_Q_TRACKER		  freeQ;
+	DONE_Q_TRACKER		  doneQ;		/* Holds Linux formmatted requests */
+	DONE_Q_TRACKER		  pendingQ;		/* Holds MPI formmatted requests */
+	MPT_Q_TRACKER		  taskQ;		/* TM request Q */
+	spinlock_t		  freedoneQlock;
+	int			  taskQcnt;
+	u8			  numTMrequests;
+	u8			  tmPending;
+	u8			  resetPending;
+	u8			  is_spi;		/* Parallel SCSI i/f */
+	u8			  negoNvram;		/* DV disabled, nego NVRAM */
+	u8			  is_multipath;		/* Multi-path compatible */
+	u8			  rsvd[2];
+	MPT_FRAME_HDR		 *tmPtr;		/* Ptr to TM request*/
+	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
+	struct scsi_cmnd	 *abortSCpnt;
+	MPT_LOCAL_REPLY		  localReply;		/* internal cmd reply struct */
+} MPT_SCSI_HOST;
+
+/*
+ *	Structure for overlaying onto scsi_cmnd->SCp area
+ *	NOTE: SCp area is 36 bytes min, 44 bytes max?
+ */
+typedef struct _scPrivate {
+	struct scsi_cmnd	*forw;
+	struct scsi_cmnd	*back;
+	void			*p1;
+	void			*p2;
+	u8			 io_path_id;	/* DMP */
+	u8			 pad[7];
+} scPrivate;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	More Dynamic Multi-Pathing stuff...
+ */
+
+/* Forward decl, a strange C thing, to prevent gcc compiler warnings */
+struct scsi_cmnd;
 
 /*
- *  MPT Control IOCTLs and structures
+ *	DMP service layer structure / API interface
  */
-#define MPT_MAGIC_NUMBER	'm'
-#define MPTRWPERF		_IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w)
-#define MPTRWPERF_CHK		_IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w)
-#define MPTRWPERF_RESET		_IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w)
-#define MPTFWDOWNLOAD		_IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
-#define MPTSCSICMD		_IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd)
-
-/*
- *  Define something *vague* enough that caller doesn't
- *  really need to know anything about device parameters
- *  (blk_size, capacity, etc.)
- */
-struct mpt_raw_r_w {
-	unsigned int	 iocnum;	/* IOC unit number */
-	unsigned int	 port;		/* IOC port number */
-	unsigned int	 target;	/* SCSI Target */
-	unsigned int	 lun;		/* SCSI LUN */
-	unsigned int	 iters;		/* N iterations */
-	unsigned short	 nblks;		/* number of blocks per IO */
-	unsigned short	 qdepth;	/* max Q depth on this device */
-	unsigned char	 range;		/* 0-100% of FULL disk capacity, 0=use (nblks X iters) */
-	unsigned char	 skip;		/* % of disk to skip */
-	unsigned char	 rdwr;		/* 0-100%, 0=pure ReaDs, 100=pure WRites */
-	unsigned char	 seqran;	/* 0-100%, 0=pure SEQential, 100=pure RANdom */
-	unsigned int	 cache_sz;	/* In Kb!  Optimize hits to N Kb cache size */
-};
-
-struct mpt_fw_xfer {
-	unsigned int	 iocnum;	/* IOC unit number */
-/*	u8		 flags;*/	/* Message flags - bit field */
-	unsigned int	 fwlen;
-	void		*bufp;		/* Pointer to firmware buffer */
-};
-
-struct mpt_scsi_cmd {
-	unsigned int	 iocnum;	/* IOC unit number */
-	unsigned int	 port;		/* IOC port number */
-	unsigned int	 target;	/* SCSI Target */
-	unsigned int	 lun;		/* SCSI LUN */
-	SCSIIORequest_t	 scsi_req;
-	SCSIIOReply_t	 scsi_reply;
-};
-
-struct mpt_ioctl_sanity {
-	unsigned int	 iocnum;
-};
+typedef struct _DmpServices {
+	VirtDevTracker	  VdevList;
+	struct semaphore *Daemon;
+	int		(*ScsiPathSelect)
+				(struct scsi_cmnd *, MPT_SCSI_HOST **hd, int *target, int *lun);
+	int		(*DmpIoDoneChk)
+				(MPT_SCSI_HOST *, struct scsi_cmnd *,
+				 SCSIIORequest_t *,
+				 SCSIIOReply_t *);
+	void		(*mptscsih_scanVlist)
+				(MPT_SCSI_HOST *, int portnum);
+	int		(*ScsiAbort)
+				(struct scsi_cmnd *);
+	int		(*ScsiBusReset)
+				(struct scsi_cmnd *);
+} DmpServices_t;
 
-#ifdef __KERNEL__	/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Generic structure passed to the base mpt_config function.
+ */
+typedef struct _x_config_parms {
+	Q_ITEM			 linkage;	/* linked list */
+	struct timer_list	 timer;		/* timer function for this request  */
+	ConfigPageHeader_t	*hdr;
+	dma_addr_t		 physAddr;
+	int			 wait_done;	/* wait for this request */
+	u32			 pageAddr;	/* properly formatted */
+	u8			 action;
+	u8			 dir;
+	u8			 timeout;	/* seconds */
+	u8			 pad1;
+	u16			 status;
+	u16			 pad2;
+} CONFIGPARMS;
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Public entry points...
  */
@@ -524,21 +945,28 @@
 extern void	 mpt_event_deregister(int cb_idx);
 extern int	 mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func);
 extern void	 mpt_reset_deregister(int cb_idx);
-extern int	 mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable);
+extern int	 mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable);
 extern void	 mpt_deregister_ascqops_strings(void);
 extern MPT_FRAME_HDR	*mpt_get_msg_frame(int handle, int iocid);
 extern void	 mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
 extern void	 mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
-extern int	 mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req);
+extern int	 mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag);
+extern int	 mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag);
 extern int	 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
 extern MPT_ADAPTER	*mpt_adapter_find_first(void);
 extern MPT_ADAPTER	*mpt_adapter_find_next(MPT_ADAPTER *prev);
+extern u32	 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
-extern void	 mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
 
 /*
  *  Public data decl's...
  */
+extern MPT_ADAPTER	 	*mpt_adapters[MPT_MAX_ADAPTERS];
+extern struct proc_dir_entry	*mpt_proc_root_dir;
+extern DmpServices_t		*DmpService;
+
 extern int		  mpt_lan_index;	/* needed by mptlan.c */
 extern int		  mpt_stm_index;	/* needed by mptstm.c */
 
@@ -563,7 +991,7 @@
 #define offsetof(t, m)	((size_t) (&((t *)0)->m))
 #endif
 
-#if defined(__alpha__) || defined(__sparc_v9__)
+#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__)
 #define CAST_U32_TO_PTR(x)	((void *)(u64)x)
 #define CAST_PTR_TO_U32(x)	((u32)(u64)x)
 #else
@@ -577,6 +1005,40 @@
 	((pflags) & MPI_PORTFACTS_PROTOCOL_LAN)		? 'L' : 'l',	\
 	((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)	? 'B' : 'b'
 
+/*
+ *  Shifted SGE Defines - Use in SGE with FlagsLength member.
+ *  Otherwise, use MPI_xxx defines (refer to "lsi/mpi.h" header).
+ *  Defaults: 32 bit SGE, SYSTEM_ADDRESS if direction bit is 0, read
+ */
+#define MPT_TRANSFER_IOC_TO_HOST		(0x00000000)
+#define MPT_TRANSFER_HOST_TO_IOC		(0x04000000)
+#define MPT_SGE_FLAGS_LAST_ELEMENT		(0x80000000)
+#define MPT_SGE_FLAGS_END_OF_BUFFER		(0x40000000)
+#define MPT_SGE_FLAGS_LOCAL_ADDRESS		(0x08000000)
+#define MPT_SGE_FLAGS_DIRECTION			(0x04000000)
+#define MPT_SGE_FLAGS_ADDRESSING		(MPT_SGE_ADDRESS_SIZE << MPI_SGE_FLAGS_SHIFT)
+#define MPT_SGE_FLAGS_END_OF_LIST		(0x01000000)
+
+#define MPT_SGE_FLAGS_TRANSACTION_ELEMENT	(0x00000000)
+#define MPT_SGE_FLAGS_SIMPLE_ELEMENT		(0x10000000)
+#define MPT_SGE_FLAGS_CHAIN_ELEMENT		(0x30000000)
+#define MPT_SGE_FLAGS_ELEMENT_MASK		(0x30000000)
+
+#define MPT_SGE_FLAGS_SSIMPLE_READ \
+	(MPT_SGE_FLAGS_LAST_ELEMENT |	\
+	 MPT_SGE_FLAGS_END_OF_BUFFER |	\
+	 MPT_SGE_FLAGS_END_OF_LIST |	\
+	 MPT_SGE_FLAGS_SIMPLE_ELEMENT |	\
+	 MPT_SGE_FLAGS_ADDRESSING |	\
+	 MPT_TRANSFER_IOC_TO_HOST)
+#define MPT_SGE_FLAGS_SSIMPLE_WRITE \
+	(MPT_SGE_FLAGS_LAST_ELEMENT |	\
+	 MPT_SGE_FLAGS_END_OF_BUFFER |	\
+	 MPT_SGE_FLAGS_END_OF_LIST |	\
+	 MPT_SGE_FLAGS_SIMPLE_ELEMENT |	\
+	 MPT_SGE_FLAGS_ADDRESSING |	\
+	 MPT_TRANSFER_HOST_TO_IOC)
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif
 
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptctl.c linux-2.4.19-pre5/drivers/message/fusion/mptctl.c
--- linux-2.4.19-pre4/drivers/message/fusion/mptctl.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptctl.c	Fri Mar 29 14:49:34 2002
@@ -9,6 +9,12 @@
  *      This driver would not exist if not for Alan Cox's development
  *      of the linux i2o driver.
  *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
  *      A huge debt of gratitude is owed to David S. Miller (DaveM)
  *      for fixing much of the stupid and broken stuff in the early
  *      driver while porting to sparc64 platform.  THANK YOU!
@@ -18,16 +24,17 @@
  *      (plus Eddie's other helpful hints and insights)
  *
  *      Thanks to Arnaldo Carvalho de Melo for finding and patching
- *      a potential memory leak in mpt_ioctl_do_fw_download(),
+ *      a potential memory leak in mptctl_do_fw_download(),
  *      and for some kmalloc insight:-)
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston, Noah Romer
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.25.4.1 2001/08/24 20:07:06 sralston Exp $
+ *  $Id: mptctl.c,v 1.52 2002/02/27 18:44:24 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -79,11 +86,16 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#include <linux/proc_fs.h>
+#include <linux/kdev_t.h>	/* needed for access to Scsi_Host struct */
+#include <linux/blkdev.h>
+#include <linux/blk.h>          /* for io_request_lock (spinlock) decl */
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
 
 #define COPYRIGHT	"Copyright (c) 1999-2001 LSI Logic Corporation"
-#define MODULEAUTHOR	"Steven J. Ralston, Noah Romer"
+#define MODULEAUTHOR	"Steven J. Ralston, Noah Romer, Pamela Delaney"
 #include "mptbase.h"
+#include "mptctl.h"
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #define my_NAME		"Fusion MPT misc device (ioctl) driver"
@@ -95,21 +107,59 @@
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 static int mptctl_id = -1;
-static int rwperf_reset = 0;
 static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS];
 
+static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-static int mpt_ioctl_rwperf(unsigned long arg);
-static int mpt_ioctl_rwperf_status(unsigned long arg);
-static int mpt_ioctl_rwperf_reset(unsigned long arg);
-static int mpt_ioctl_fw_download(unsigned long arg);
-static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
-static int mpt_ioctl_scsi_cmd(unsigned long arg);
+struct buflist {
+	u8	*kptr;
+	int	 len;
+};
+
+/*
+ * Function prototypes. Called from OS entry point mptctl_ioctl.
+ * arg contents specific to function.
+ */
+static int mptctl_fw_download(unsigned long arg);
+static int mptctl_getiocinfo (unsigned long arg);
+static int mptctl_gettargetinfo (unsigned long arg);
+static int mptctl_readtest (unsigned long arg);
+static int mptctl_mpt_command (unsigned long arg);
+static int mptctl_eventquery (unsigned long arg);
+static int mptctl_eventenable (unsigned long arg);
+static int mptctl_eventreport (unsigned long arg);
+static int mptctl_replace_fw (unsigned long arg);
+
+static int mptctl_do_reset(unsigned long arg);
+
+static int mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static int mptctl_cpq_getpciinfo(unsigned long arg);
+static int mptctl_cpq_getdriver(unsigned long arg);
+static int mptctl_cpq_ctlr_status(unsigned long arg);
+static int mptctl_cpq_target_address(unsigned long arg);
+static int mptctl_cpq_passthru(unsigned long arg);
+static int mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass);
+
+/*
+ * Private function calls.
+ */
+static int mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local);
+static int mptctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
+static MptSge_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int sge_offset, int *frags,
+		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma,
+		struct buflist *buflist, MPT_ADAPTER *ioc);
+static void mptctl_timer_expired (unsigned long data);
+
+/*
+ * Reset Handler cleanup function
+ */
+static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -132,26 +182,27 @@
 /* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
 #define MAX_KMALLOC_SZ		(128*1024)
 
-struct buflist {
-	u8	*kptr;
-	int	 len;
-};
-
-#define myMAX_TARGETS	(1<<4)
-#define myMAX_LUNS	(1<<3)
-#define myMAX_T_MASK	(myMAX_TARGETS-1)
-#define myMAX_L_MASK	(myMAX_LUNS-1)
-static u8  DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
-static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+#define MPT_IOCTL_DEFAULT_TIMEOUT 10	/* Default timeout value (seconds) */
 
 static u32 fwReplyBuffer[16];
 static pMPIDefaultReply_t ReplyMsg = NULL;
 
-/* some private forw protos */
-static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags,
-		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
-static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma,
-		struct buflist *buflist, MPT_ADAPTER *ioc);
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	Function to return 0 if the sge Address member is 0 and
+ *	non-zero else.  Used in the mpt_do_fw_download routines.
+ */
+static inline int
+mptctl_test_address(MptSge_t *sge)
+{
+#ifdef __ia64__
+	if ((sge->Address.Low) || (sge->Address.High))
+		return 1;
+	else
+		return 0;
+#else
+	return sge->Address;
+#endif
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -159,7 +210,7 @@
  *	@ioc: Pointer to MPT adapter
  *	@nonblock: boolean, non-zero if O_NONBLOCK is set
  *
- *	All of the mptctl commands can potentially sleep, which is illegal
+ *	All of the ioctl commands can potentially sleep, which is illegal
  *	with a spinlock held, thus we perform mutual exclusion here.
  *
  *	Returns negative errno on error, or zero for success.
@@ -167,16 +218,27 @@
 static inline int
 mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 {
-	dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock));
+	int rc = 0;
+	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
 
+#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+	if (!nonblock) {
+		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
+			rc = -ERESTARTSYS;
+	} else {
+		rc = -EPERM;
+	}
+#else
 	if (nonblock) {
 		if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
-			return -EAGAIN;
+			rc = -EAGAIN;
 	} else {
 		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
-			return -ERESTARTSYS;
+			rc = -ERESTARTSYS;
 	}
-	return 0;
+#endif
+	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
+	return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -189,18 +251,150 @@
 static int
 mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-	u8 targ;
+	char *sense_data;
+	int sz, req_index;
+	u16 iocStatus;
+	u8 cmd;
+
+	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_reply()!\n", ioc->name));
+	if (req)
+		 cmd = req->u.hdr.Function;
+	else
+		return 1;
+
+	if (ioc->ioctl) {
+		/* If timer is not running, then an error occurred.
+		 * A timeout will call the reset routine to reload the messaging
+		 * queues.
+		 * Main callback will free message and reply frames.
+		 */
+		if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+			/* Delete this timer
+			 */
+			del_timer (&ioc->ioctl->timer);
+			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
+
+			/* Set the overall status byte.  Good if:
+			 * IOC status is good OR if no reply and a SCSI IO request
+			 */
+			if (reply) {
+				/* Copy the reply frame (which much exist
+				 * for non-SCSI I/O) to the IOC structure.
+				 */
+				dctlprintk((MYIOC_s_INFO_FMT ": Copying Reply Frame @%p to IOC!\n",
+						ioc->name, reply));
+				memcpy(ioc->ioctl->ReplyFrame, reply,
+					MIN(ioc->reply_sz, 4*reply->u.reply.MsgLength));
+				ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+
+				/* Set the command status to GOOD if IOC Status is GOOD
+				 * OR if SCSI I/O cmd and data underrun or recovered error.
+				 */
+				iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
+				if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
+					ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+
+				if ((iocStatus  == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || 
+						(iocStatus  == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
+					if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+						(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+						ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+					}
+				}
+
+				/* Copy the sense data - if present
+				 */
+				if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
+					(reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)){
+
+					sz = req->u.scsireq.SenseBufferLength;
+					req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+					sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+					memcpy(ioc->ioctl->sense, sense_data, sz);
+					ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
+				}
+			} else if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+					(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+				ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+			}
+
+			/* We are done, issue wake up
+			 */
+			ioc->ioctl->wait_done = 1;
+			wake_up (&mptctl_wait);
+		} else if (reply && cmd == MPI_FUNCTION_FW_DOWNLOAD) {
+			/* Two paths to FW DOWNLOAD! */
+			// NOTE: Expects/requires non-Turbo reply!
+			dctlprintk((MYIOC_s_INFO_FMT ":Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n",
+				ioc->name));
+			memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
+			ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+		}
+	}
+	return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_timer_expired
+ *
+ * Call back for timer process. Used only for ioctl functionality.
+ *
+ */
+static void mptctl_timer_expired (unsigned long data)
+{
+	MPT_IOCTL *ioctl = (MPT_IOCTL *) data;
+
+	dctlprintk((KERN_NOTICE MYNAM ": Timer Expired! Host %d\n",
+				ioctl->ioc->id));
 
-	//dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n"));
+	/* Issue a reset for this device.
+	 * The IOC is not responding.
+	 */
+	mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_ioc_reset
+ *
+ * Clean-up functionality. Used only if there has been a
+ * reload of the FW due.
+ *
+ */
+static int
+mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+	MPT_IOCTL *ioctl = ioc->ioctl;
+	dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+	if (reset_phase == MPT_IOC_PRE_RESET){
+
+		/* Someone has called the reset handler to
+		 * do a hard reset. No more replies from the FW.
+		 * Delete the timer.
+		 */
+		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
+
+			/* Delete this timer
+			 */
+			del_timer(&ioctl->timer);
+		}
 
-	if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
-		targ = req->u.scsireq.TargetID & myMAX_T_MASK;
-		DevIosCount[targ][0]--;
-	} else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) {
-		// NOTE: Expects/requires non-Turbo reply!
-		dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n"));
-		memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
-		ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+	} else {
+		/* Set the status and continue IOCTL
+		 * processing. All memory will be free'd
+		 * by originating thread after wake_up is
+		 * called.
+		 */
+		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
+			ioctl->status = MPT_IOCTL_STATUS_DID_TIMEOUT;
+
+			/* Wake up the calling process
+			 */
+			ioctl->wait_done = 1;
+			wake_up(&mptctl_wait);
+		}
 	}
 
 	return 1;
@@ -208,7 +402,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  struct file_operations functionality. 
+ *  struct file_operations functionality.
  *  Members:
  *	llseek, write, read, ioctl, open, release
  */
@@ -234,63 +428,93 @@
 static ssize_t
 mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
 {
+	printk(KERN_ERR MYNAM ": ioctl READ not yet supported\n");
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  MPT ioctl handler
+ *  cmd - specify the particular IOCTL command to be issued
+ *  arg - data specific to the command. Must not be null.
  */
 static int
-mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+mptctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct mpt_ioctl_sanity	*usanity = (struct mpt_ioctl_sanity *) arg;
-	struct mpt_ioctl_sanity	 ksanity;
+	mpt_ioctl_header	*uhdr = (mpt_ioctl_header *) arg;
+	mpt_ioctl_header	 khdr;
 	int iocnum;
 	unsigned iocnumX;
 	int nonblock = (file->f_flags & O_NONBLOCK);
 	int ret;
 	MPT_ADAPTER *iocp = NULL;
 
-	dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n"));
+	dctlprintk(("mptctl_ioctl() called\n"));
 
-	if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) {
-		printk(KERN_ERR "%s::mpt_ioctl() @%d - "
-				"Unable to copy mpt_ioctl_sanity data @ %p\n",
-				__FILE__, __LINE__, (void*)usanity);
+	if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
+		printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
+				"Unable to copy mpt_ioctl_header data @ %p\n",
+				__FILE__, __LINE__, (void*)uhdr);
 		return -EFAULT;
 	}
 	ret = -ENXIO;				/* (-6) No such device or address */
 
-	/* Verify intended MPT adapter */
-	iocnumX = ksanity.iocnum & 0xFF;
+	/* Test for Compaq-specific IOCTL's.
+	 */
+	if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) ||
+		(cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
+		(cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS))
+		return mptctl_compaq_ioctl(file, cmd, arg);
+
+	/* Verify intended MPT adapter - set iocnum and the adapter
+	 * pointer (iocp)
+	 */
+	iocnumX = khdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n",
+		printk(KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnumX);
 		return -ENODEV;
 	}
 
+	/* Handle those commands that are just returning
+	 * information stored in the driver.
+	 * These commands should never time out and are unaffected
+	 * by TM and FW reloads.
+	 */
+	if (cmd == MPTIOCINFO) {
+		return mptctl_getiocinfo(arg);
+	} else if (cmd == MPTTARGETINFO) {
+		return mptctl_gettargetinfo(arg);
+	} else if (cmd == MPTTEST) {
+		return mptctl_readtest(arg);
+	} else if (cmd == MPTEVENTQUERY) {
+		return mptctl_eventquery(arg);
+	} else if (cmd == MPTEVENTENABLE) {
+		return mptctl_eventenable(arg);
+	} else if (cmd == MPTEVENTREPORT) {
+		return mptctl_eventreport(arg);
+	} else if (cmd == MPTFWREPLACE) {
+		return mptctl_replace_fw(arg);
+	}
+
+	/* All of these commands require an interrupt or
+	 * are unknown/illegal.
+	 */
 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
 		return ret;
 
-	dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name));
+	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name));
 
 	switch(cmd) {
-	case MPTRWPERF:
-		ret = mpt_ioctl_rwperf(arg);
-		break;
-	case MPTRWPERF_CHK:
-		ret = mpt_ioctl_rwperf_status(arg);
-		break;
-	case MPTRWPERF_RESET:
-		ret = mpt_ioctl_rwperf_reset(arg);
-		break;
 	case MPTFWDOWNLOAD:
-		ret = mpt_ioctl_fw_download(arg);
+		ret = mptctl_fw_download(arg);
+		break;
+	case MPTCOMMAND:
+		ret = mptctl_mpt_command(arg);
 		break;
-	case MPTSCSICMD:
-		ret = mpt_ioctl_scsi_cmd(arg);
+	case MPTHARDRESET:
+		ret = mptctl_do_reset(arg);
 		break;
 	default:
 		ret = -EINVAL;
@@ -301,6 +525,36 @@
 	return ret;
 }
 
+static int mptctl_do_reset(unsigned long arg)
+{
+	struct mpt_ioctl_diag_reset *urinfo = (struct mpt_ioctl_diag_reset *) arg;
+	struct mpt_ioctl_diag_reset krinfo;
+	MPT_ADAPTER		*iocp;
+
+	dctlprintk((KERN_INFO "mptctl_do_reset called.\n"));
+
+	if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
+		printk(KERN_ERR "%s@%d::mptctl_do_reset - "
+				"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
+				__FILE__, __LINE__, (void*)urinfo);
+		return -EFAULT;
+	}
+
+	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
+		printk(KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+				__FILE__, __LINE__, krinfo.hdr.iocnum);
+		return -ENXIO; /* (-6) No such device or address */
+	}
+
+	if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) {
+		printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
+			__FILE__, __LINE__);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int mptctl_open(struct inode *inode, struct file *file)
 {
@@ -317,13 +571,29 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT FW download function.  Cast the arg into the mpt_fw_xfer structure.
+ * This structure contains: iocnum, firmware length (bytes),
+ *      pointer to user space memory where the fw image is stored.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENXIO  if no such device
+ *		-EAGAIN if resource problem
+ *		-ENOMEM if no memory for SGE
+ *		-EMLINK if too many chain buffers required
+ *		-EBADRQC if adapter does not support FW download
+ *		-EBUSY if adapter is busy
+ *		-ENOMSG if FW upload returned bad status
+ */
 static int
-mpt_ioctl_fw_download(unsigned long arg)
+mptctl_fw_download(unsigned long arg)
 {
 	struct mpt_fw_xfer	*ufwdl = (struct mpt_fw_xfer *) arg;
 	struct mpt_fw_xfer	 kfwdl;
 
-	dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
+	dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
 	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
 		printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
 				"Unable to copy mpt_fw_xfer struct @ %p\n",
@@ -331,44 +601,52 @@
 		return -EFAULT;
 	}
 
-	return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
+	return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- * MPT FW Download
+ * FW Download engine.
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENXIO  if no such device
+ *		-EAGAIN if resource problem
+ *		-ENOMEM if no memory for SGE
+ *		-EMLINK if too many chain buffers required
+ *		-EBADRQC if adapter does not support FW download
+ *		-EBUSY if adapter is busy
+ *		-ENOMSG if FW upload returned bad status
  */
 static int
-mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
+mptctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
 {
 	FWDownload_t		*dlmsg;
 	MPT_FRAME_HDR		*mf;
 	MPT_ADAPTER		*iocp;
-//	char			*fwbuf;
-//	dma_addr_t		 fwbuf_dma;
-	FWDownloadTCSGE_t	*fwVoodoo;
-//	SGEAllUnion_t		*fwSgl;
+	FWDownloadTCSGE_t	*ptsge;
+	MptSge_t		*sgl;
+	MptSge_t		*sgOut, *sgIn;
+	struct buflist		*buflist;
+	struct buflist		*bl;
+	dma_addr_t		 sgl_dma;
 	int			 ret;
-
-	SGESimple32_t	*sgl;
-	SGESimple32_t	*sgOut, *sgIn;
-	dma_addr_t	 sgl_dma;
-	struct buflist	*buflist = NULL;
-	struct buflist	*bl = NULL;
-	int		 numfrags = 0;
-	int		 maxfrags;
-	int		 n = 0;
-	u32		 sgdir;
-	u32		 nib;
-	int		 fw_bytes_copied = 0;
-	u16		 iocstat;
-	int		 i;
-
-	dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
-
-	dprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));
-	dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
-	dprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
+	int			 numfrags = 0;
+	int			 maxfrags;
+	int			 n = 0;
+	u32			 sgdir;
+	u32			 nib;
+	int			 fw_bytes_copied = 0;
+	int			 i;
+	int			 cntdn;
+	int			 sge_offset = 0;
+	u16			 iocstat;
+
+	dctlprintk((KERN_INFO "mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
+
+	dctlprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));
+	dctlprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
+	dctlprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
 
 	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
 		printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
@@ -376,11 +654,13 @@
 		return -ENXIO; /* (-6) No such device or address */
 	}
 
+	/*  Valid device. Get a message frame and construct the FW download message.
+	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
 		return -EAGAIN;
 	dlmsg = (FWDownload_t*) mf;
-	fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL;
-	sgOut = (SGESimple32_t *) (fwVoodoo + 1);
+	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
+	sgOut = (MptSge_t *) (ptsge + 1);
 
 	/*
 	 * Construct f/w download request
@@ -392,27 +672,36 @@
 	dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
 	dlmsg->MsgFlags = 0;
 
-	fwVoodoo->Reserved = 0;
-	fwVoodoo->ContextSize = 0;
-	fwVoodoo->DetailsLength = 12;
-	fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
-	fwVoodoo->Reserved1 = 0;
-	fwVoodoo->ImageOffset = 0;
-	fwVoodoo->ImageSize = cpu_to_le32(fwlen);
+	/* Set up the Transaction SGE.
+	 */
+	ptsge->Reserved = 0;
+	ptsge->ContextSize = 0;
+	ptsge->DetailsLength = 12;
+	ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+	ptsge->Reserved_0100_Checksum = 0;
+	ptsge->ImageOffset = 0;
+	ptsge->ImageSize = cpu_to_le32(fwlen);
+
+	/* Add the SGL
+	 */
 
 	/*
 	 * Need to kmalloc area(s) for holding firmware image bytes.
 	 * But we need to do it piece meal, using a proper
 	 * scatter gather list (with 128kB MAX hunks).
-	 * 
+	 *
 	 * A practical limit here might be # of sg hunks that fit into
 	 * a single IOC request frame; 12 or 8 (see below), so:
 	 * For FC9xx: 12 x 128kB == 1.5 mB (max)
 	 * For C1030:  8 x 128kB == 1   mB (max)
 	 * We could support chaining, but things get ugly(ier:)
+	 *
+	 * Set the sge_offset to the start of the sgl (bytes).
 	 */
 	sgdir = 0x04000000;		/* IOC will READ from sys mem */
-	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+	sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t);
+	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset,
+				    &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
 		return -ENOMEM;
 
 	/*
@@ -420,16 +709,19 @@
 	 * for FC9xx f/w image, but calculate max number of sge hunks
 	 * we can fit into a request frame, and limit ourselves to that.
 	 * (currently no chain support)
-	 * For FC9xx: (128-12-16)/8 = 12.5 = 12
-	 * For C1030:  (96-12-16)/8 =  8.5 =  8
+	 * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE
+	 *	Request		maxfrags
+	 *	128		12
+	 *	96		8
+	 *	64		4
 	 */
-	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t);
+	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(MptSge_t);
 	if (numfrags > maxfrags) {
 		ret = -EMLINK;
 		goto fwdl_out;
 	}
 
-	dprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
+	dctlprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
 
 	/*
 	 * Parse SG list, copying sgl itself,
@@ -439,11 +731,17 @@
 	sgIn = sgl;
 	bl = buflist;
 	for (i=0; i < numfrags; i++) {
-		nib = (le32_to_cpu(sgIn->FlagsLength) & 0xF0000000) >> 28;
-		/* skip ignore/chain. */
+
+		/* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE
+		 * Skip everything but Simple. If simple, copy from
+		 *	user space into kernel space.
+		 * Note: we should not have anything but Simple as
+		 *	Chain SGE are illegal.
+		 */
+		nib = (le32_to_cpu(sgIn->FlagsLength) & 0x30000000) >> 28;
 		if (nib == 0 || nib == 3) {
 			;
-		} else if (sgIn->Address) {
+		} else if (mptctl_test_address(sgIn)) {
 			*sgOut = *sgIn;
 			n++;
 			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
@@ -478,26 +776,24 @@
 	/*
 	 *  Wait until the reply has been received
 	 */
-	{
-		int	 foo = 0;
-
-		while (ReplyMsg == NULL) {
-			if (!(foo%1000000)) {
-				dprintk((KERN_INFO "DbG::_do_fwdl: "
-					   "In ReplyMsg loop - iteration %d\n",
-					   foo)); //tc
-			}
+	for (cntdn=HZ*60, i=1; ReplyMsg == NULL; cntdn--, i++) {
+		if (!cntdn) {
 			ret = -ETIME;
-			if (++foo > 60000000)
-				goto fwdl_out;
-			mb();
-			schedule();
-			barrier();
+			goto fwdl_out;
 		}
+
+		if (!(i%HZ)) {
+			dctlprintk((KERN_INFO "DbG::_do_fwdl: "
+				   "In ReplyMsg loop - iteration %d\n",
+				   i));
+		}
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(1);
 	}
 
 	if (sgl)
-        	kfree_sgl(sgl, sgl_dma, buflist, iocp);
+		kfree_sgl(sgl, sgl_dma, buflist, iocp);
 
 	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
 	if (iocstat == MPI_IOCSTATUS_SUCCESS) {
@@ -527,32 +823,46 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  NEW rwperf (read/write performance) stuff starts here...
+ * SGE Allocation routine
+ *
+ * Inputs:	bytes - number of bytes to be transferred
+ *		sgdir - data direction
+ *		sge_offset - offset (in bytes) from the start of the request
+ *			frame to the first SGE
+ *		ioc - pointer to the mptadapter
+ * Outputs:	frags - number of scatter gather elements
+ *		blp - point to the buflist pointer
+ *		sglbuf_dma - pointer to the (dma) sgl
+ * Returns:	Null if failes
+ *		pointer to the (virtual) sgl if successful.
  */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static SGESimple32_t *
-kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
+static MptSge_t *
+kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
 		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
 {
-	SGESimple32_t	*sglbuf = NULL;
-	struct buflist	*buflist = NULL;
+	MptSge_t	*sglbuf = NULL;		/* pointer to array of SGE
+						 * and chain buffers */
+	struct buflist	*buflist = NULL;	/* kernel routine */
+	MptSge_t	*sgl;
+	MptChain_t	*last_chain = NULL;
 	int		 numfrags = 0;
 	int		 fragcnt = 0;
 	int		 alloc_sz = MIN(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!
 	int		 bytes_allocd = 0;
 	int		 this_alloc;
-	SGESimple32_t	*sgl;
-	u32		 pa;					// phys addr
-	SGEChain32_t	*last_chain = NULL;
-	SGEChain32_t	*old_chain = NULL;
+	dma_addr_t	 pa;					// phys addr
 	int		 chaincnt = 0;
 	int		 i, buflist_ent;
 	int		 sg_spill = MAX_FRAGS_SPILL1;
 	int		 dir;
 
+	/* initialization */
 	*frags = 0;
 	*blp = NULL;
+
+	/* Allocate and initialize an array of kernel
+	 * structures for the SG elements.
+	 */
 	i = MAX_SGL_BYTES / 8;
 	buflist = kmalloc(i, GFP_USER);
 	if (buflist == NULL)
@@ -560,6 +870,11 @@
 	memset(buflist, 0, i);
 	buflist_ent = 0;
 
+	/* Allocate a single block of memory to store the sg elements and
+	 * the chain buffers.  The calling routine is responsible for
+	 * copying the data in this array into the correct place in the
+	 * request and chain buffers.
+	 */
 	sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
 	if (sglbuf == NULL)
 		goto free_and_fail;
@@ -569,7 +884,15 @@
 	else
 		dir = PCI_DMA_FROMDEVICE;
 
+	/* At start:
+	 *	sgl = sglbuf = point to beginning of sg buffer
+	 *	buflist_ent = 0 = first kernel structure
+	 *	sg_spill = number of SGE that can be written before the first
+	 *		chain element.
+	 *
+	 */
 	sgl = sglbuf;
+	sg_spill = ((ioc->req_sz  - sge_offset)/ sizeof(MptSge_t)) - 1;
 	while (bytes_allocd < bytes) {
 		this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
 		buflist[buflist_ent].len = this_alloc;
@@ -594,7 +917,7 @@
 			/* Write one SIMPLE sge */
 			sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
 			dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
-			sgl->Address = cpu_to_le32(dma_addr);
+			cpu_to_leXX(dma_addr, sgl->Address);
 
 			fragcnt++;
 			numfrags++;
@@ -609,24 +932,43 @@
 		if (fragcnt == sg_spill) {
 			dma_addr_t chain_link;
 
-			if (last_chain != NULL)
-				last_chain->NextChainOffset = 0x1E;
-
-			fragcnt = 0;
-			sg_spill = MAX_FRAGS_SPILL2;
+			/* If there is a chain element, set the offset
+			 * (in 32 bit words) to the next chain element.
+			 * fragcnt = # sge = 8 bytes = 2 words
+			 *
+			 * Set the length of the chain element (bytes)
+			 * This includes the size of the next chain element.
+			 *
+			 * We are now done with last_chain and the previous
+			 * buffer.
+			 */
+			if (last_chain != NULL) {
+				last_chain->NextChainOffset = fragcnt * 2;
+				last_chain->Length = cpu_to_le16((fragcnt+1) * 8);
+			}
 
-			/* fixup previous SIMPLE sge */
+			/* Finish the current buffer:
+			 * - add the LE bit to last sge
+			 * - add the chain element
+			*/
 			sgl[-1].FlagsLength |= cpu_to_le32(0x80000000);
 
 			chain_link = (*sglbuf_dma) +
 				((u8 *)(sgl+1) - (u8 *)sglbuf);
 
 			/* Write one CHAIN sge */
-			sgl->FlagsLength = cpu_to_le32(0x30000080);
-			sgl->Address = cpu_to_le32(chain_link);
+//			sgl->FlagsLength = cpu_to_le32(0x30000080);
+			sgl->FlagsLength = cpu_to_le32(0x30000000);
+			cpu_to_leXX(chain_link, sgl->Address);
+
+			/* Reset everything for the next SGE series,
+			 * save a ptr to the chain element in last_chain
+			 */
+			fragcnt = 0;
+//			sg_spill = MAX_FRAGS_SPILL2;
+			sg_spill = (ioc->req_sz / sizeof(MptSge_t)) - 1;
 
-			old_chain = last_chain;
-			last_chain = (SGEChain32_t*)sgl;
+			last_chain = (MptChain_t*)sgl;
 			chaincnt++;
 			numfrags++;
 			sgl++;
@@ -646,18 +988,19 @@
 	/* Last sge fixup: set LE+eol+eob bits */
 	sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000);
 
-	/* Chain fixup needed? */
-	if (last_chain != NULL && fragcnt < 16)
+	/* Chain fixup needed? */	/* SteveR CHECKME!!! */
+//	if (last_chain != NULL && fragcnt < 16)
+	if (last_chain != NULL)
 		last_chain->Length = cpu_to_le16(fragcnt * 8);
 
 	*frags = numfrags;
 	*blp = buflist;
 
-	dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
 			   "%d SG frags generated!  (%d CHAIN%s)\n",
 			   numfrags, chaincnt, chaincnt>1?"s":""));
 
-	dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
 			   "last (big) alloc_sz=%d\n",
 			   alloc_sz));
 
@@ -675,7 +1018,7 @@
 			if ((le32_to_cpu(sglbuf[i].FlagsLength) >> 24) == 0x30)
 				continue;
 
-			dma_addr = le32_to_cpu(sglbuf[i].Address);
+			leXX_to_cpu(dma_addr, sglbuf[i].Address);
 			kptr = buflist[i].kptr;
 			len = buflist[i].len;
 
@@ -688,16 +1031,19 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Routine to free the SGL elements.
+ */
 static void
-kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
+kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
 {
-	SGESimple32_t	*sg = sgl;
+	MptSge_t	*sg = sgl;
 	struct buflist	*bl = buflist;
 	u32		 nib;
 	int		 dir;
 	int		 n = 0;
 
-	if (le32_to_cpu(sg->FlagsLength) & 0x04000000)
+	if ((le32_to_cpu(sg->FlagsLength) & 0x04000000))
 		dir = PCI_DMA_TODEVICE;
 	else
 		dir = PCI_DMA_FROMDEVICE;
@@ -707,12 +1053,12 @@
 		/* skip ignore/chain. */
 		if (nib == 0 || nib == 3) {
 			;
-		} else if (sg->Address) {
+		} else if (mptctl_test_address(sg)) {
 			dma_addr_t dma_addr;
 			void *kptr;
 			int len;
 
-			dma_addr = le32_to_cpu(sg->Address);
+			leXX_to_cpu(dma_addr, sg->Address);
 			kptr = bl->kptr;
 			len = bl->len;
 			pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
@@ -725,12 +1071,12 @@
 	}
 
 	/* we're at eob! */
-	if (sg->Address) {
+	if (mptctl_test_address(sg)) {
 		dma_addr_t dma_addr;
 		void *kptr;
 		int len;
 
-		dma_addr = le32_to_cpu(sg->Address);
+		leXX_to_cpu(dma_addr, sg->Address);
 		kptr = bl->kptr;
 		len = bl->len;
 		pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
@@ -740,392 +1086,1686 @@
 
 	pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
 	kfree(buflist);
-	dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
+	dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptctl_getiocinfo - Query the host adapter for IOC information.
+ *	@arg: User space argument
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENODEV  if no such device/adapter
+ */
 static int
-mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src,
-		      char *caller, MPT_ADAPTER **iocpp)
+mptctl_getiocinfo (unsigned long arg)
 {
-	char	*myname = "_rwperf_init()";
-	int	 ioc;
+	struct mpt_ioctl_iocinfo *uarg = (struct mpt_ioctl_iocinfo *) arg;
+	struct mpt_ioctl_iocinfo karg;
+	MPT_ADAPTER		*ioc;
+	struct pci_dev		*pdev;
+	struct Scsi_Host	*sh;
+	MPT_SCSI_HOST		*hd;
+	int			iocnum;
+	int			numDevices = 0;
+	unsigned int		max_id;
+	int			ii;
+	int			port;
+	u8			revision;
+
+	dctlprintk((": mptctl_getiocinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_iocinfo))) {
+		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+			"Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 
-	/* get copy of structure passed from user space */
-	if (copy_from_user(dest, (void*)src, sizeof(*dest))) {
-		printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n",
-				myname, __LINE__, (void*)src);
-		return -EFAULT;				/* (-14) Bad address */
-	} else {
-		dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}"
-				   ": %d %d %d %d %d\n",
-				   dest->iocnum, dest->target,
-				   (int)dest->qdepth, dest->iters, dest->nblks ));
-		dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}"
-				   ": %d %d %d %d %d\n",
-				   dest->cache_sz, dest->skip, dest->range,
-				   dest->rdwr, dest->seqran ));
-
-		/* Get the MPT adapter id. */
-		if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) {
-			printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n",
-					myname, __LINE__, dest->iocnum);
-			return -ENXIO;			/* (-6) No such device or address */
-		} else {
-			dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n",
-					caller, dest->iocnum, dest->target));
-		}
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
 	}
 
-	return ioc;
-}
+	/* Verify the data transfer size is correct.
+	 * Ignore the port setting.
+	 */
+	if (karg.hdr.maxDataSize != sizeof(struct mpt_ioctl_iocinfo)) {
+		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+			"Structure size mismatch. Command not completed.\n",
+				__FILE__, __LINE__);
+		return -EFAULT;
+	}
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+	/* Fill in the data and return the structure to the calling
+	 * program
+	 */
+	if (ioc->chip_type == C1030)
+		karg.adapterType = MPT_IOCTL_INTERFACE_SCSI;
+	else
+		karg.adapterType = MPT_IOCTL_INTERFACE_FC;
 
-/*  Treat first N blocks of disk as sacred!  */
-#define SACRED_BLOCKS	100
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int
-mpt_ioctl_rwperf(unsigned long arg)
-{
-	struct mpt_raw_r_w	 kPerfInfo;
-				/* NOTE: local copy, on stack==KERNEL_SPACE! */
-	u8		 target, targetM;
-	u8		 lun, lunM;
-	u8		 scsiop;
-	int		 qdepth;
-	int		 iters;
-	int		 cache_sz;
-	u32		 xferbytes;
-	u32		 scsidir;
-	u32		 qtag;
-	u32		 scsictl;
-	u32		 sgdir;
-	u32		 blkno;
-	u32		 sbphys;
-	SGESimple32_t	*sgl;
-	dma_addr_t	 sgl_dma;
-	struct buflist	*buflist;
-	SGESimple32_t	*sgOut, *sgIn;
-	int		 numfrags;
-	u32		*msg;
-	int		 i;
-	int		 ioc;
-	MPT_FRAME_HDR	*mf;
-	MPT_ADAPTER	*iocp;
-	int		 sgfragcpycnt;
-	int		 blklo, blkhi;
-	u8		 nextchainoffset;
-	u8		*SenseBuf;
-	dma_addr_t	 SenseBufDMA;
-	char		*myname = "_rwperf()";
-
-    dprintk((KERN_INFO "%s - starting...\n", myname));
-
-    /* Validate target device */
-    if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
-        return ioc;
-
-    /* Allocate DMA'able memory for the sense buffer. */
-    SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA);
-
-    /* set perf parameters from input */
-    target = kPerfInfo.target & 0x0FF;
-    targetM = target & myMAX_T_MASK;
-    lun = kPerfInfo.lun & 0x1F;			// LUN=31 max
-    lunM = lun & myMAX_L_MASK;
-    qdepth = kPerfInfo.qdepth;
-    iters = kPerfInfo.iters;
-    xferbytes = ((u32)kPerfInfo.nblks)<<9;
-
-    DevInUse[targetM][lunM] = 1;
-    DevIosCount[targetM][lunM] = 0;
-
-    cache_sz = kPerfInfo.cache_sz * 1024;	// CacheSz in kB!
-
-    /* ToDo: */
-    /* get capacity (?) */
-
-
-    // pre-build, one time, everything we can for speed in the loops below...
-
-    scsiop = 0x28;				// default to SCSI READ!
-    scsidir = MPI_SCSIIO_CONTROL_READ;		// DATA IN  (host<--ioc<--dev)
-						// 02000000
-    qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;		// 00000000
-
-    if (xferbytes == 0) {
-        // Do 0-byte READ!!!
-        //  IMPORTANT!  Need to set no SCSI DIR for this!
-        scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
-    }
-
-    scsictl = scsidir | qtag;
-
-    /*
-     *  Set sgdir for DMA transfer.
-     */
-//    sgdir   = 0x04000000;		// SCSI WRITE
-    sgdir = 0x00000000;			// SCSI READ
-
-    if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
-        return -ENOMEM;
-
-    sgfragcpycnt = MIN(10,numfrags);
-    nextchainoffset = 0;
-    if (numfrags > 10)
-        nextchainoffset = 0x1E;
-
-    sbphys = SenseBufDMA;
-
-    rwperf_reset = 0;
-
-//    do {	// target-loop
-
-        blkno = SACRED_BLOCKS;		// Treat first N blocks as sacred!
-					// FIXME!  Skip option
-        blklo = blkno;
-        blkhi = blkno;
-
-        do {    // inner-loop
-
-            while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
-                mb();
-                schedule();
-                barrier();
-            }
-            msg = (u32*)mf;
-
-            /* Start piecing the SCSIIORequest together */
-            msg[0] = 0x00000000 | nextchainoffset<<16 | target;
-            msg[1] = 0x0000FF0A;				// 255 sense bytes, 10-byte CDB!
-            msg[3] = lun << 8;
-            msg[4] = 0;
-            msg[5] = scsictl;
-
-            // 16 bytes of CDB @ msg[6,7,8,9] are below...
-
-            msg[6] = (   ((blkno & 0xFF000000) >> 8)
-                       | ((blkno & 0x00FF0000) << 8)
-                       | scsiop );
-            msg[7] = (   (((u32)kPerfInfo.nblks & 0x0000FF00) << 16)
-                       | ((blkno & 0x000000FF) << 8)
-                       | ((blkno & 0x0000FF00) >> 8) );
-            msg[8] = (kPerfInfo.nblks & 0x00FF);
-            msg[9] = 0;
-
-            msg[10] = xferbytes;
-
-//            msg[11] = 0xD0000100;
-//            msg[12] = sbphys;
-//            msg[13] = 0;
-            msg[11] = sbphys;
-
-            // Copy the SGL...
-            if (xferbytes) {
-                sgOut = (SGESimple32_t*)&msg[12];
-                sgIn  = sgl;
-                for (i=0; i < sgfragcpycnt; i++)
-                    *sgOut++ = *sgIn++;
-            }
-
-            // fubar!  QueueDepth issue!!!
-            while (    !rwperf_reset
-                    && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) )
-            {
-                mb();
-                schedule();
-                barrier();
-            }
-
-//            blkno += kPerfInfo.nblks;
-// EXP Stuff!
-// Try optimizing to certain cache size for the target!
-// by keeping blkno within cache range if at all possible
-#if 0
-            if (    cache_sz
-                 && ((2 * kPerfInfo.nblks) <= (cache_sz>>9))
-                 && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
-                blkno = SACRED_BLOCKS;
-            else
-                blkno += kPerfInfo.nblks;
-#endif
-// Ok, cheat!
-            if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
-                   blkno = SACRED_BLOCKS;
-            else
-                blkno += kPerfInfo.nblks;
+	port = karg.hdr.port;
+
+	karg.port = port;
+	pdev = (struct pci_dev *) ioc->pcidev;
 
-            if (blkno > blkhi)
-                blkhi = blkno;
+	karg.pciId = pdev->device;
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+	karg.hwRev = revision;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	karg.subSystemDevice = pdev->subsystem_device;
+	karg.subSystemVendor = pdev->subsystem_vendor;
+#endif
 
-            DevIosCount[targetM][lunM]++;
+	/* Get number of devices
+         */
+	if ( (sh = ioc->sh) != NULL) {
+
+		 /* sh->max_id = maximum target ID + 1
+		 */
+		max_id = sh->max_id - 1;
+		hd = (MPT_SCSI_HOST *) sh->hostdata;
+
+		/* Check all of the target structures and
+		 * keep a counter.
+		 */
+		if (hd && hd->Targets) {
+			for (ii = 0; ii <= max_id; ii++) {
+				if (hd->Targets[ii])
+					numDevices++;
+			}
+		}
+	}
+	karg.numDevices = numDevices;
 
-            /*
-             *  Finally, post the request
-             */
-            mpt_put_msg_frame(mptctl_id, ioc, mf);
+	/* Set the BIOS and FW Version
+	 */
+	karg.FWVersion = ioc->facts.FWVersion.Word;
+	karg.BIOSVersion = ioc->biosVersion;
 
+	/* Set the Version Strings.
+	 */
+	strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
 
-            /* let linux breath! */
-            mb();
-            schedule();
-            barrier();
+	karg.busChangeEvent = 0;
+	karg.hostId = ioc->pfacts[port].PortSCSIID;
+	karg.rsvd[0] = karg.rsvd[1] = 0;
 
-            //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters));
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(struct mpt_ioctl_iocinfo))) {
+		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+			"Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 
-        } while ((--iters > 0) && !rwperf_reset);
+	return 0;
+}
 
-        dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi));
-        dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target));
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptctl_gettargetinfo - Query the host adapter for target information.
+ *	@arg: User space argument
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENODEV  if no such device/adapter
+ */
+static int
+mptctl_gettargetinfo (unsigned long arg)
+{
+	struct mpt_ioctl_targetinfo *uarg = (struct mpt_ioctl_targetinfo *) arg;
+	struct mpt_ioctl_targetinfo karg;
+	MPT_ADAPTER		*ioc;
+	struct Scsi_Host	*sh;
+	MPT_SCSI_HOST		*hd;
+	char			*pmem;
+	int			*pdata;
+	int			iocnum;
+	int			numDevices = 0;
+	unsigned int		max_id;
+	int			ii, jj, lun;
+	int			maxWordsLeft;
+	int			numBytes;
+	u8			port;
+
+	dctlprintk(("mptctl_gettargetinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
+		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+			"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 
-//        //  TEMPORARY!
-//        target = 0;
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
 
-//    } while (target);
+	/* Get the port number and set the maximum number of bytes
+	 * in the returned structure.
+	 * Ignore the port setting.
+	 */
+	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
+	maxWordsLeft = numBytes/sizeof(int);
+	port = karg.hdr.port;
+
+	if (maxWordsLeft <= 0) {
+		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+				__FILE__, __LINE__);
+		return -ENOMEM;
+	}
 
+	/* Fill in the data and return the structure to the calling
+	 * program
+	 */
 
-    if (DevIosCount[targetM][lunM]) {
-        dprintk((KERN_INFO "  DbG: DevIosCount[%d][%d]=%d\n",
-                targetM, lunM, DevIosCount[targetM][lunM]));
-    }
+	/* struct mpt_ioctl_targetinfo does not contain sufficient space
+	 * for the target structures so when the IOCTL is called, there is
+	 * not sufficient stack space for the structure. Allocate memory,
+	 * populate the memory, copy back to the user, then free memory.
+	 * targetInfo format:
+	 * bits 31-24: reserved
+	 *      23-16: LUN
+	 *      15- 8: Bus Number
+	 *       7- 0: Target ID
+	 */
+	pmem = kmalloc(numBytes, GFP_KERNEL);
+	if (pmem == NULL) {
+		printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+				__FILE__, __LINE__);
+		return -ENOMEM;
+	}
+	memset(pmem, 0, numBytes);
+	pdata =  (int *) pmem;
 
-    while (DevIosCount[targetM][lunM]) {
-        //dprintk((KERN_DEBUG "  DbG: Waiting... DevIosCount[%d][%d]=%d\n",
-        //        targetM, lunM, DevIosCount[targetM][lunM]));
-        mb();
-        schedule();
-        barrier();
-    }
-    DevInUse[targetM][lunM] = 0;
+	/* Get number of devices
+         */
+	if ( (sh = ioc->sh) != NULL) {
+
+		max_id = sh->max_id - 1;
+		hd = (MPT_SCSI_HOST *) sh->hostdata;
+
+		/* Check all of the target structures.
+		 * Save the Id and increment the counter,
+		 * if ptr non-null.
+		 * sh->max_id = maximum target ID + 1
+		 */
+		if (hd && hd->Targets) {
+			ii = 0;
+			while (ii <= max_id) {
+				if (hd->Targets[ii]) {
+					for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
+						lun = (1 << jj);
+						if (hd->Targets[ii]->luns & lun) {
+							numDevices++;
+							*pdata = (jj << 16) | ii;
+							--maxWordsLeft;
+
+							pdata++;
+
+							if (maxWordsLeft <= 0) {
+								break;
+							}
+						}
+					}
+				}
+				ii++;
+			}
+		}
+	}
+	karg.numDevices = numDevices;
 
-    pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA);
+	/* Copy part of the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(struct mpt_ioctl_targetinfo))) {
+		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		kfree(pmem);
+		return -EFAULT;
+	}
 
-    if (sgl)
-        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+	/* Copy the remaining data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *) uarg->targetInfo, pmem, numBytes)) {
+		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)pdata);
+		kfree(pmem);
+		return -EFAULT;
+	}
 
-    dprintk((KERN_INFO "  *** done ***\n"));
+	kfree(pmem);
 
-    return 0;
+	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* MPT IOCTL Test function.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENODEV  if no such device/adapter
+ */
 static int
-mpt_ioctl_rwperf_status(unsigned long arg)
+mptctl_readtest (unsigned long arg)
 {
-	struct mpt_raw_r_w	 kPerfInfo;
-				/* NOTE: local copy, on stack==KERNEL_SPACE! */
-	MPT_ADAPTER	*iocp;
-	int		 ioc;
-//	u8		 targ;
-//	u8		 lun;
-	int		 T, L;
-	char		*myname = "_rwperf_status()";
+	struct mpt_ioctl_test	*uarg = (struct mpt_ioctl_test *) arg;
+	struct mpt_ioctl_test	 karg;
+	MPT_ADAPTER *ioc;
+	int iocnum;
 
+	dctlprintk(("mptctl_readtest called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
+		printk(KERN_ERR "%s@%d::mptctl_readtest - "
+			"Unable to read in mpt_ioctl_test struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 
-	dprintk((KERN_INFO "%s - starting...\n", myname));
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
 
-	/* Get a pointer to the MPT adapter. */
-	if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
-		return ioc;
+	/* Fill in the data and return the structure to the calling
+	 * program
+	 */
 
-	/* set perf parameters from input */
-//	targ = kPerfInfo.target & 0xFF;
-//	lun = kPerfInfo.lun & 0x1F;
+#ifdef MFCNT
+	karg.chip_type = ioc->mfcnt;
+#else
+	karg.chip_type = ioc->chip_type;
+#endif
+	strncpy (karg.name, ioc->name, MPT_MAX_NAME);
+	strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
 
-	for (T=0; T < myMAX_TARGETS; T++)
-		for (L=0; L < myMAX_LUNS; L++)
-			if (DevIosCount[T][L]) {
-				printk(KERN_INFO "%s: ioc%d->00:%02x:%02x"
-						 ", IosCnt=%d\n",
-						 myname, ioc, T, L, DevIosCount[T][L] );
-			}
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
+		printk(KERN_ERR "%s@%d::mptctl_readtest - "
+			"Unable to write out mpt_ioctl_test struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptctl_eventquery - Query the host adapter for the event types
+ *	that are being logged.
+ *	@arg: User space argument
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENODEV  if no such device/adapter
+ */
 static int
-mpt_ioctl_rwperf_reset(unsigned long arg)
+mptctl_eventquery (unsigned long arg)
 {
-	struct mpt_raw_r_w	 kPerfInfo;
-				/* NOTE: local copy, on stack==KERNEL_SPACE! */
-	MPT_ADAPTER	*iocp;
-	int		 ioc;
-//	u8		 targ;
-//	u8		 lun;
-	int		 T, L;
-	int		 i;
-	char		*myname = "_rwperf_reset()";
-
-	dprintk((KERN_INFO "%s - starting...\n", myname));
-
-	/* Get MPT adapter id. */
-	if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
-		return ioc;
-
-	/* set perf parameters from input */
-//	targ = kPerfInfo.target & 0xFF;
-//	lun = kPerfInfo.lun & 0x1F;
-
-	rwperf_reset = 1;
-	for (i=0; i < 1000000; i++) {
-		mb();
-		schedule();
-		barrier();
-	}
-	rwperf_reset = 0;
-
-	for (T=0; T < myMAX_TARGETS; T++)
-		for (L=0; L < myMAX_LUNS; L++)
-			if (DevIosCount[T][L]) {
-				printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, "
-						 "IosCnt RESET! (from %d to 0)\n",
-						 myname, ioc, T, L, DevIosCount[T][L] );
-				DevIosCount[T][L] = 0;
-				DevInUse[T][L] = 0;
-			}
+	struct mpt_ioctl_eventquery	*uarg = (struct mpt_ioctl_eventquery *) arg;
+	struct mpt_ioctl_eventquery	 karg;
+	MPT_ADAPTER *ioc;
+	int iocnum;
+
+	dctlprintk(("mptctl_eventquery called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
+		printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+			"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
 
+	karg.eventEntries = ioc->eventLogSize;
+	karg.eventTypes = ioc->eventTypes;
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
+		printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+			"Unable to write out mpt_ioctl_eventquery struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
-mpt_ioctl_scsi_cmd(unsigned long arg)
+mptctl_eventenable (unsigned long arg)
 {
-	return -ENOSYS;
+	struct mpt_ioctl_eventenable	*uarg = (struct mpt_ioctl_eventenable *) arg;
+	struct mpt_ioctl_eventenable	 karg;
+	MPT_ADAPTER *ioc;
+	int iocnum;
+
+	dctlprintk(("mptctl_eventenable called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
+		printk(KERN_ERR "%s@%d::mptctl_eventenable - "
+			"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	if (ioc->events == NULL) {
+		/* Have not yet allocated memory - do so now.
+		 */
+		int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+		ioc->events = kmalloc(sz, GFP_KERNEL);
+		if (ioc->events == NULL) {
+			printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+			return -ENOMEM;
+		}
+		memset(ioc->events, 0, sz);
+		ioc->alloc_total += sz;
+
+		ioc->eventLogSize = MPTCTL_EVENT_LOG_SIZE;
+		ioc->eventContext = 0;
+        }
+
+	/* Update the IOC event logging flag.
+	 */
+	ioc->eventTypes = karg.eventTypes;
+
+	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptctl_eventreport (unsigned long arg)
+{
+	struct mpt_ioctl_eventreport	*uarg = (struct mpt_ioctl_eventreport *) arg;
+	struct mpt_ioctl_eventreport	 karg;
+	MPT_ADAPTER		 *ioc;
+	int			 iocnum;
+	int			 numBytes, maxEvents, max;
+
+	dctlprintk(("mptctl_eventreport called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
+		printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+			"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
-#define	owner_THIS_MODULE  owner:		THIS_MODULE,
-#else
-#define	owner_THIS_MODULE
-#endif
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
 
-static struct file_operations mptctl_fops = {
-	owner_THIS_MODULE
-	llseek:		no_llseek,
-	read:		mptctl_read,
-	write:		mptctl_write,
-	ioctl:		mpt_ioctl,
-	open:		mptctl_open,
-	release:	mptctl_release,
-};
+	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
+	maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
 
-static struct miscdevice mptctl_miscdev = {
-	MPT_MINOR,
-	MYNAM,
-	&mptctl_fops
-};
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+	max = ioc->eventLogSize < maxEvents ? ioc->eventLogSize : maxEvents;
 
-#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+	/* If fewer than 1 event is requested, there must have
+	 * been some type of error.
+	 */
+	if ((max < 1) || !ioc->events)
+		return -ENODATA;
 
-/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
+	/* Copy the data from kernel memory to user memory
+	 */
+	numBytes = max * sizeof(MPT_IOCTL_EVENTS);
+	if (copy_to_user((char *) uarg->eventData, ioc->events, numBytes)) {
+		printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+			"Unable to write out mpt_ioctl_eventreport struct @ %p\n",
+				__FILE__, __LINE__, (void*)ioc->events);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptctl_replace_fw (unsigned long arg)
+{
+	struct mpt_ioctl_replace_fw	*uarg = (struct mpt_ioctl_replace_fw *) arg;
+	struct mpt_ioctl_replace_fw	 karg;
+	MPT_ADAPTER		 *ioc;
+	int			 iocnum;
+	u8			 *mem = NULL;
+	dma_addr_t		 mem_dma;
+	int			 oldFwSize, newFwSize;
+
+	dctlprintk(("mptctl_replace_fw called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
+		printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+			"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	/* If not caching FW, return 0
+	 */
+	if ((ioc->FWImage == NULL) && (ioc->alt_ioc) && (ioc->alt_ioc->FWImage == NULL)) {
+		return 0;
+	}
+
+
+	/* Allocate memory for the new FW image
+	 */
+	newFwSize = karg.newImageSize;
+	mem = pci_alloc_consistent(ioc->pcidev, newFwSize, &mem_dma);
+	if (mem == NULL)
+		return -ENOMEM;
+
+	ioc->alloc_total += newFwSize;	
+
+	/* Copy the data from user memory to kernel space
+	 */
+	if (copy_from_user(mem, uarg->newImage, newFwSize)) {
+		printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+			"Unable to read in mpt_ioctl_replace_fw image @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		pci_free_consistent(ioc->pcidev, newFwSize, mem, mem_dma);
+		ioc->alloc_total -= newFwSize;	
+		return -EFAULT;
+	}
+
+	/* Free the old FW image 
+	 */
+	oldFwSize = ioc->facts.FWImageSize;
+	if (ioc->FWImage) {
+		pci_free_consistent(ioc->pcidev, oldFwSize, ioc->FWImage, ioc->FWImage_dma);
+		ioc->alloc_total -= oldFwSize;	
+		ioc->FWImage = mem;
+		ioc->FWImage_dma = mem_dma;
+		
+	} else if ((ioc->alt_ioc) && (ioc->alt_ioc->FWImage)) {
+		pci_free_consistent(ioc->pcidev, oldFwSize, ioc->alt_ioc->FWImage, ioc->alt_ioc->FWImage_dma);
+		ioc->alloc_total -= oldFwSize;	
+		ioc->alt_ioc->FWImage = mem;
+		ioc->alt_ioc->FWImage_dma = mem_dma;
+	}
+
+	/* Update IOCFactsReply
+	 */
+	ioc->facts.FWImageSize = newFwSize;
+	if (ioc->alt_ioc)
+		ioc->alt_ioc->facts.FWImageSize = newFwSize;
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* MPT IOCTL MPTCOMMAND function.
+ * Cast the arg into the mpt_ioctl_mpt_command structure.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_mpt_command (unsigned long arg)
+{
+	struct mpt_ioctl_command *uarg = (struct mpt_ioctl_command *) arg;
+	struct mpt_ioctl_command  karg;
+	MPT_ADAPTER	*ioc;
+	int		iocnum;
+	int		rc;
+
+	dctlprintk(("mptctl_command called.\n"));
+
+	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
+		printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
+			"Unable to read in mpt_ioctl_command struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	rc = mptctl_do_mpt_command (karg, (char *) &uarg->MF, 0);
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local)
+{
+	MPT_ADAPTER	*ioc;
+	MPT_FRAME_HDR	*mf = NULL;
+	MPIHeader_t	*hdr;
+	MptSge_t	*psge;
+	MptSge_t	*this_sge = NULL;
+	MptSge_t	*sglbuf = NULL;
+	struct buflist	bufIn;	/* data In buffer */
+	struct buflist	bufOut; /* data Out buffer */
+	dma_addr_t	sglbuf_dma;
+	dma_addr_t	dma_addr;
+	int		dir;	/* PCI data direction */
+	int		sgSize = 0;	/* Num SG elements */
+	int		this_alloc;
+	int iocnum, flagsLength;
+	int sz, rc = 0;
+	int msgContext;
+	u16		req_idx;
+
+	dctlprintk(("mptctl_do_mpt_command called.\n"));
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+	if (!ioc->ioctl) {
+		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+			"No memory available during driver init.\n",
+				__FILE__, __LINE__);
+		return -ENOMEM;
+	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_TIMEOUT) {
+		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+			"Busy with IOC Reset \n", __FILE__, __LINE__);
+		return -EBUSY;
+	}
+
+	/* Verify that the final request frame will not be too large.
+	 */
+	sz = karg.dataSgeOffset * 4;
+	if (karg.dataInSize > 0)
+		sz += sizeof (MptSge_t);
+	if (karg.dataOutSize > 0)
+		sz += sizeof (MptSge_t);
+
+	if ( sz > ioc->req_sz) {
+		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+			"Request frame too large (%d) maximum (%d)\n",
+				__FILE__, __LINE__, sz, ioc->req_sz);
+		return -EFAULT;
+	}
+
+	/* Get a free request frame and save the message context.
+	 */
+        if ((mf = mpt_get_msg_frame(mptctl_id, ioc->id)) == NULL)
+                return -EAGAIN;
+
+	hdr = (MPIHeader_t *) mf;
+	msgContext = le32_to_cpu(hdr->MsgContext);
+	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+	/* Copy the request frame
+	 * Reset the saved message context.
+	 */
+        if (local) {
+		/* Request frame in kernel space
+		 */
+		memcpy((char *)mf, (char *) mfPtr, karg.dataSgeOffset * 4);
+        } else {
+		/* Request frame in user space
+		 */
+		if (copy_from_user((char *)mf, (char *) mfPtr,
+					karg.dataSgeOffset * 4)){
+			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+				"Unable to read MF from mpt_ioctl_command struct @ %p\n",
+				__FILE__, __LINE__, (void*)mfPtr);
+			rc = -EFAULT;
+			goto done_free_mem;
+		}
+        }
+	hdr->MsgContext = cpu_to_le32(msgContext);
+
+
+	/* Verify that this request is allowed.
+	 */
+	switch (hdr->Function) {
+	case MPI_FUNCTION_IOC_FACTS:
+	case MPI_FUNCTION_PORT_FACTS:
+	case MPI_FUNCTION_CONFIG:
+	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
+	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
+	case MPI_FUNCTION_FW_UPLOAD:
+	case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
+	case MPI_FUNCTION_FW_DOWNLOAD:
+		break;
+
+	case MPI_FUNCTION_SCSI_IO_REQUEST:
+		if (ioc->sh) {
+			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
+			VirtDevice	*pTarget = NULL;
+			MPT_SCSI_HOST	*hd = NULL;
+			int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
+			int scsidir = 0;
+			int target = (int) pScsiReq->TargetID;
+			int dataSize;
+
+			pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+
+			/* verify that app has not requested
+			 *	more sense data than driver
+			 *	can provide, if so, reset this parameter
+			 * set the sense buffer pointer low address
+			 * update the control field to specify Q type
+			 */
+			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
+				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+			pScsiReq->SenseBufferLowAddr =
+				cpu_to_le32(ioc->sense_buf_low_dma
+				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+			if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
+				if (hd->Targets)
+					pTarget = hd->Targets[target];
+			}
+
+			if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+				qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+
+			/* Have the IOCTL driver set the direction based
+			 * on the dataOutSize (ordering issue with Sparc).
+			 */
+			if (karg.dataOutSize > 0 ) {
+				scsidir = MPI_SCSIIO_CONTROL_WRITE;
+				dataSize = karg.dataOutSize;
+			}
+			else {
+				scsidir = MPI_SCSIIO_CONTROL_READ;
+				dataSize = karg.dataInSize;
+			}
+
+			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
+			pScsiReq->DataLength = cpu_to_le32(dataSize);
+
+		} else {
+			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+				"SCSI driver is not loaded. \n",
+					__FILE__, __LINE__);
+			rc = -EFAULT;
+			goto done_free_mem;
+		}
+		break;
+
+	case MPI_FUNCTION_RAID_ACTION:
+		/* Just add a SGE
+		 */
+		break;
+
+	case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
+		if (ioc->sh) {
+			SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
+			int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+			int scsidir = MPI_SCSIIO_CONTROL_READ;
+			int dataSize;
+
+			pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+
+			/* verify that app has not requested
+			 *	more sense data than driver
+			 *	can provide, if so, reset this parameter
+			 * set the sense buffer pointer low address
+			 * update the control field to specify Q type
+			 */
+			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
+				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+			pScsiReq->SenseBufferLowAddr =
+				cpu_to_le32(ioc->sense_buf_low_dma
+				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+			/* All commands to physical devices are tagged
+			 */
+
+			/* Have the IOCTL driver set the direction based
+			 * on the dataOutSize (ordering issue with Sparc).
+			 */
+			if (karg.dataOutSize > 0 ) {
+				scsidir = MPI_SCSIIO_CONTROL_WRITE;
+				dataSize = karg.dataOutSize;
+			}
+			else {
+				scsidir = MPI_SCSIIO_CONTROL_READ;
+				dataSize = karg.dataInSize;
+			}
+
+			pScsiReq->Control = cpu_to_le32(scsidir | qtag);
+			pScsiReq->DataLength = cpu_to_le32(dataSize);
+
+		} else {
+			printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+				"SCSI driver is not loaded. \n",
+					__FILE__, __LINE__);
+			rc = -EFAULT;
+			goto done_free_mem;
+		}
+		break;
+
+	default:
+		/*
+		 * MPI_FUNCTION_IOC_INIT
+		 * MPI_FUNCTION_PORT_ENABLE
+		 * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
+		 * MPI_FUNCTION_TARGET_ASSIST
+		 * MPI_FUNCTION_TARGET_STATUS_SEND
+		 * MPI_FUNCTION_TARGET_MODE_ABORT
+		 * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
+		 * MPI_FUNCTION_IO_UNIT_RESET
+		 * MPI_FUNCTION_HANDSHAKE
+		 * MPI_FUNCTION_REPLY_FRAME_REMOVAL
+		 * MPI_FUNCTION_EVENT_NOTIFICATION
+		 *  (driver handles event notification)
+		 * MPI_FUNCTION_EVENT_ACK
+		 * MPI_FUNCTION_SCSI_TASK_MGMT
+		 */
+
+		/*  What to do with these???  CHECK ME!!!
+			MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
+			MPI_FUNCTION_FC_LINK_SRVC_RSP
+			MPI_FUNCTION_FC_ABORT
+			MPI_FUNCTION_FC_PRIMITIVE_SEND
+			MPI_FUNCTION_LAN_SEND
+			MPI_FUNCTION_LAN_RECEIVE
+		 	MPI_FUNCTION_LAN_RESET
+		*/
+
+		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+			"Illegal request (function 0x%x) \n",
+			__FILE__, __LINE__, hdr->Function);
+		rc = -EFAULT;
+		goto done_free_mem;
+	}
+
+	/* Add the SGL ( at most one data in SGE and one data out SGE )
+	 * In the case of two SGE's - the data out (write) will always
+	 * preceede the data in (read) SGE. psgList is used to free the
+	 * allocated memory.
+	 */
+	psge = (MptSge_t *) ( ((int *) mf) + karg.dataSgeOffset);
+	flagsLength = 0;
+
+	/* bufIn and bufOut are used for user to kernel space transfers
+	 */
+	bufIn.kptr = bufOut.kptr = NULL;
+	bufIn.len = bufOut.len = 0;
+
+	if (karg.dataOutSize > 0 )
+		sgSize ++;
+
+	if (karg.dataInSize > 0 )
+		sgSize ++;
+
+	if (sgSize > 0) {
+
+		/* Allocate memory for the SGL.
+		 * Used to free kernel memory once
+		 * the MF is freed.
+		 */
+		sglbuf = pci_alloc_consistent (ioc->pcidev,
+			sgSize*sizeof(MptSge_t), &sglbuf_dma);
+		if (sglbuf == NULL) {
+			rc = -ENOMEM;
+			goto done_free_mem;
+		}
+		this_sge = sglbuf;
+
+		/* Set up the dataOut memory allocation */
+		if (karg.dataOutSize > 0) {
+			dir = PCI_DMA_TODEVICE;
+			if (karg.dataInSize > 0 ) {
+				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+						MPI_SGE_FLAGS_DIRECTION |
+						MPT_SGE_ADDRESS_SIZE )
+						<< MPI_SGE_FLAGS_SHIFT;
+			} else {
+				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+			}
+			flagsLength |= karg.dataOutSize;
+
+			this_alloc = karg.dataOutSize;
+			bufOut.len = this_alloc;
+			bufOut.kptr = pci_alloc_consistent(
+					ioc->pcidev, this_alloc, &dma_addr);
+
+			if (bufOut.kptr == NULL) {
+				rc = -ENOMEM;
+				goto done_free_mem;
+			} else {
+				/* Copy user data to kernel space.
+				 */
+				if (copy_from_user(bufOut.kptr,
+						karg.dataOutBufPtr,
+						bufOut.len)) {
+
+					printk(KERN_ERR
+						"%s@%d::mptctl_do_mpt_command - Unable "
+						"to read user data "
+						"struct @ %p\n",
+						__FILE__, __LINE__,(void*)karg.dataOutBufPtr);
+					rc =  -EFAULT;
+					goto done_free_mem;
+				}
+
+				/* Set up this SGE.
+				 * Copy to MF and to sglbuf
+				 */
+
+				psge->FlagsLength = cpu_to_le32 (flagsLength);
+				cpu_to_leXX(dma_addr, psge->Address);
+				psge++;
+
+				this_sge->FlagsLength=cpu_to_le32(flagsLength);
+				cpu_to_leXX(dma_addr, this_sge->Address);
+				this_sge++;
+			}
+		}
+
+		if (karg.dataInSize > 0) {
+			dir = PCI_DMA_FROMDEVICE;
+			flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+			flagsLength |= karg.dataInSize;
+
+			this_alloc = karg.dataInSize;
+			bufIn.len = this_alloc;
+			bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
+							this_alloc, &dma_addr);
+			if (bufIn.kptr == NULL) {
+				rc = -ENOMEM;
+				goto done_free_mem;
+			} else {
+				/* Set up this SGE
+				 * Copy to MF and to sglbuf
+				 */
+				psge->FlagsLength = cpu_to_le32 (flagsLength);
+				cpu_to_leXX(dma_addr, psge->Address);
+
+				this_sge->FlagsLength=cpu_to_le32(flagsLength);
+				cpu_to_leXX(dma_addr, this_sge->Address);
+				this_sge++;
+			}
+		}
+	} else  {
+		/* Add a NULL SGE
+		 */
+		flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+		psge->FlagsLength = cpu_to_le32 (flagsLength);
+		cpu_to_leXX( (dma_addr_t) -1, psge->Address);
+	}
+
+	/* The request is complete. Set the timer parameters
+	 * and issue the request.
+	 */
+	if (karg.timeout > 0) {
+		ioc->ioctl->timer.expires = jiffies + HZ*karg.timeout;
+	} else {
+		ioc->ioctl->timer.expires = jiffies + HZ*MPT_IOCTL_DEFAULT_TIMEOUT;
+	}
+
+	ioc->ioctl->wait_done = 0;
+	ioc->ioctl->status |= MPT_IOCTL_STATUS_TIMER_ACTIVE;
+	add_timer(&ioc->ioctl->timer);
+
+	mpt_put_msg_frame(mptctl_id, ioc->id, mf);
+	wait_event(mptctl_wait, ioc->ioctl->wait_done);
+
+	/* The command is complete.  * Return data to the user.
+	 *
+	 * If command completed,  mf has been freed so cannot
+	 * use this memory.
+	 *
+	 * If timeout, a recovery  mechanism has been called.
+	 * Need to free the mf.
+	 */
+	if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_TIMEOUT) {
+
+		/* A timeout - there is no data to return to the
+		 * the user other than an error.
+		 * The timer callback deleted the
+		 * timer and reset the adapter queues.
+		 */
+		printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - "
+			"Timeout Occurred on IOCTL! Resetting IOC.\n", __FILE__, __LINE__);
+		rc = -ETIME;
+
+		/* Free memory and return to the calling function
+		 */
+		goto done_free_mem;
+
+	} else {
+		/* Callback freed request frame.
+		 */
+		mf = NULL;
+
+		/* If a valid reply frame, copy to the user.
+		 * Offset 2: reply length in U32's
+		 */
+		if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
+			if (karg.maxReplyBytes < ioc->reply_sz) {
+				 sz = MIN(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+			} else {
+				 sz = MIN(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+			}
+
+			if (sz > 0) {
+				if (copy_to_user((char *)karg.replyFrameBufPtr,
+					 &ioc->ioctl->ReplyFrame, sz)){
+
+					 printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+					 "Unable to write out reply frame %p\n",
+					 __FILE__, __LINE__, (void*)karg.replyFrameBufPtr);
+					 rc =  -ENODATA;
+					 goto done_free_mem;
+				}
+			}
+		}
+
+		/* If valid sense data, copy to user.
+		 */
+		if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+			sz = MIN(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
+			if (sz > 0) {
+				if (copy_to_user((char *)karg.senseDataPtr, ioc->ioctl->sense, sz)) {
+					printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+					"Unable to write sense data to user %p\n",
+					__FILE__, __LINE__,
+					(void*)karg.senseDataPtr);
+					rc =  -ENODATA;
+					goto done_free_mem;
+				}
+			}
+		}
+
+		/* If the overall status is _GOOD and data in, copy data
+		 * to user.
+		 */
+		if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
+					(karg.dataInSize > 0) && (bufIn.kptr)) {
+
+			if (copy_to_user((char *)karg.dataInBufPtr,
+					 bufIn.kptr, karg.dataInSize)) {
+				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+					"Unable to write data to user %p\n",
+					__FILE__, __LINE__,
+					(void*)karg.dataInBufPtr);
+				rc =  -ENODATA;
+			}
+		}
+	}
+
+done_free_mem:
+	/* Clear status bits.
+	 */
+	ioc->ioctl->status = 0;
+
+	if (sglbuf) {
+		this_sge = sglbuf;
+
+		/* Free the allocated memory.
+		 */
+		 if (bufOut.kptr != NULL ) {
+
+			leXX_to_cpu (dma_addr, this_sge->Address);
+
+			this_sge++;	/* go to next structure */
+			this_alloc = bufOut.len;
+			pci_free_consistent(ioc->pcidev,
+				this_alloc, (void *) &bufOut, dma_addr);
+		}
+
+		if (bufIn.kptr != NULL ) {
+			leXX_to_cpu (dma_addr, this_sge->Address);
+			this_alloc = bufIn.len;
+
+			pci_free_consistent(ioc->pcidev,
+					this_alloc, (void *) &bufIn, dma_addr);
+		}
+
+		this_alloc = sgSize * sizeof(MptSge_t);
+		pci_free_consistent(ioc->pcidev,
+				this_alloc, (void *) sglbuf, sglbuf_dma);
+
+	}
+
+	/* mf will be null if allocation failed OR
+	 * if command completed OK (callback freed)
+	 */
+	if (mf)
+		mpt_free_msg_frame(mptctl_id, ioc->id, mf);
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Routine for the Compaq IOCTL commands.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int iocnum = 0;
+	unsigned iocnumX = 0;
+	int ret;
+	int nonblock = (file->f_flags & O_NONBLOCK);
+	MPT_ADAPTER *iocp = NULL;
+
+	if (cmd == CPQFCTS_SCSI_PASSTHRU) {
+		/* Update the iocnum */
+		if (copy_from_user(&iocnumX, (int *)arg, sizeof(int))) {
+			printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - "
+				"Unable to read controller number @ %p\n",
+				__FILE__, __LINE__, (void*)arg);
+			return -EFAULT;
+		}
+		iocnumX &= 0xFF;
+	}
+
+	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+	    (iocp == NULL)) {
+		printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX);
+		return -ENODEV;
+	}
+
+	/* All of these commands require an interrupt or
+	 * are unknown/illegal.
+	 */
+	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+		return ret;
+
+	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_compaq_ioctl()\n", iocp->name));
+
+	switch(cmd) {
+	case CPQFCTS_GETPCIINFO:
+		ret = mptctl_cpq_getpciinfo(arg);
+		break;
+	case CPQFCTS_GETDRIVER:
+		ret = mptctl_cpq_getdriver(arg);
+		break;
+	case CPQFCTS_CTLR_STATUS:
+		ret = mptctl_cpq_ctlr_status(arg);
+		break;
+	case CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS:
+		ret = mptctl_cpq_target_address(arg);
+		break;
+	case CPQFCTS_SCSI_PASSTHRU:
+		ret = mptctl_cpq_passthru(arg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+	return ret;
+
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_getpciinfo - Get PCI Information in format desired by Compaq
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ */
+static int
+mptctl_cpq_getpciinfo(unsigned long arg)
+{
+	cpqfc_pci_info_struct *uarg = (cpqfc_pci_info_struct *) arg;
+	cpqfc_pci_info_struct karg;
+	MPT_ADAPTER		*ioc;
+	struct pci_dev		*pdev;
+	CONFIGPARMS		cfg;
+	ConfigPageHeader_t	hdr;
+	int			iocnum = 0, iocnumX = 0;
+	dma_addr_t		buf_dma;
+	u8			*pbuf = NULL;
+	int			failed;
+
+	dctlprintk((": mptctl_cpq_pciinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(cpqfc_pci_info_struct))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - "
+			"Unable to read in cpqfc_pci_info_struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	pdev = (struct pci_dev *) ioc->pcidev;
+
+	/* Populate the structure. */
+	karg.bus = pdev->bus->number;
+	karg.bus_type = 1;	/* 1 = PCI; 4 = unknown */
+	karg.device_fn = PCI_FUNC(pdev->devfn);
+	karg.slot_number = PCI_SLOT(pdev->devfn);
+	karg.vendor_id = pdev->vendor;
+	karg.device_id = pdev->device;
+	karg.board_id = (karg.device_id | (karg.vendor_id << 16));
+	karg.class_code = pdev->class;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	karg.sub_vendor_id = pdev->subsystem_vendor;
+	karg.sub_device_id = pdev->subsystem_device;
+#endif
+
+	/* Issue a config request to get the device serial number
+	 */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;	/* read */
+	cfg.timeout = 10;
+
+	failed = 1;
+
+	if (mpt_config(ioc, &cfg) == 0) {
+		if (cfg.hdr->PageLength > 0) {
+			/* Issue the second config page request */
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+			pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+			if (pbuf) {
+				cfg.physAddr = buf_dma;
+				if (mpt_config(ioc, &cfg) == 0) {
+					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
+					strncpy(karg.serial_number, pdata->BoardTracerNumber, 17);
+					failed = 0;
+				}
+				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+				pbuf = NULL;
+			}
+		}
+	}
+	if (failed)
+		strncpy(karg.serial_number, " ", 17);
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(cpqfc_pci_info_struct))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - "
+			"Unable to write out cpqfc_pci_info_struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_getdriver - Get Driver Version in format desired by Compaq
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ */
+static int
+mptctl_cpq_getdriver(unsigned long arg)
+{
+	int		*uarg = (int *)arg;
+	int		karg;
+	MPT_ADAPTER	*ioc = NULL;
+	int		iocnum = 0, iocnumX = 0;
+	int		ii, jj;
+	char		version[10];
+	char		val;
+	char		*vptr = NULL;
+	char		*pptr = NULL;
+
+	dctlprintk((": mptctl_cpq_getdriver called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(int))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - "
+			"Unable to read in struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	strncpy(version, MPT_LINUX_VERSION_COMMON, 8);
+
+	karg = 0;
+	vptr = version;
+	ii = 3;
+	while (ii > 0) {
+		pptr = strchr(vptr, '.');
+		if (pptr) {
+			*pptr = '\0';
+			val = 0;
+			for (jj=0; vptr[jj]>='0' && vptr[jj]<='9'; jj++)
+				val = 10 * val + (vptr[jj] - '0');
+			karg |= (val << (8*ii));
+			pptr++;
+			vptr = pptr;
+		} else
+			break;
+		ii--;
+	}
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(int))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - "
+			"Unable to write out stuct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_ctlr_status - Get controller status in format desired by Compaq
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ */
+static int
+mptctl_cpq_ctlr_status(unsigned long arg)
+{
+	cpqfc_ctlr_status *uarg = (cpqfc_ctlr_status *) arg;
+	cpqfc_ctlr_status karg;
+	MPT_ADAPTER		*ioc;
+	int			iocnum = 0, iocnumX = 0;
+
+	dctlprintk((": mptctl_cpq_pciinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(cpqfc_ctlr_status))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - "
+			"Unable to read in cpqfc_ctlr_status @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	karg.status = ioc->last_state;
+	karg.offline_reason = 0;
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(cpqfc_ctlr_status))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - "
+			"Unable to write out cpqfc_ctlr_status @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_target_address - Get WWN Information in format desired by Compaq
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ */
+static int
+mptctl_cpq_target_address(unsigned long arg)
+{
+	Scsi_FCTargAddress *uarg = (Scsi_FCTargAddress *) arg;
+	Scsi_FCTargAddress karg;
+	MPT_ADAPTER		*ioc;
+	int			iocnum = 0, iocnumX = 0;
+	CONFIGPARMS		cfg;
+	ConfigPageHeader_t	hdr;
+	dma_addr_t		buf_dma;
+	u8			*pbuf = NULL;
+	FCPortPage0_t		*ppp0;
+	int			ii, failed;
+	u32			low, high;
+
+	dctlprintk((": mptctl_cpq_target_address called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(Scsi_FCTargAddress))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - "
+			"Unable to read in Scsi_FCTargAddress @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	karg.host_port_id = 0;
+
+	/* Issue a config request to get the device wwn
+	 */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;	/* read */
+	cfg.timeout = 10;
+
+	failed = 1;
+
+	if (mpt_config(ioc, &cfg) == 0) {
+		if (cfg.hdr->PageLength > 0) {
+			/* Issue the second config page request */
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+			pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+			if (pbuf) {
+				cfg.physAddr = buf_dma;
+				if (mpt_config(ioc, &cfg) == 0) {
+					ppp0 = (FCPortPage0_t *) pbuf;
+
+					low = le32_to_cpu(ppp0->WWNN.Low);
+					high = le32_to_cpu(ppp0->WWNN.High);
+
+					for (ii = 0; ii < 4; ii++) {
+						karg.host_wwn[7-ii] = low & 0xFF;
+						karg.host_wwn[3-ii] = high & 0xFF;
+						low = (low >> 8);
+						high = (high >> 8);
+					}
+					failed = 0;
+				}
+				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+				pbuf = NULL;
+			}
+		}
+	}
+
+	if (failed) {
+		for (ii = 7; ii >= 0; ii--)
+			karg.host_wwn[ii] = 0;
+	}
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(Scsi_FCTargAddress))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - "
+			"Unable to write out Scsi_FCTargAddress @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_passthru - Construct and issue a SCSI IO Passthru
+ *
+ * Requires the SCSI host driver to be loaded.
+ * I386 version.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ */
+static int
+mptctl_cpq_passthru(unsigned long arg)
+{
+	VENDOR_IOCTL_REQ	*uarg = (VENDOR_IOCTL_REQ *) arg;
+	VENDOR_IOCTL_REQ	karg;
+	cpqfc_passthru_t	kpass;
+	MPT_ADAPTER		*ioc;
+	int			iocnum = 0, iocnumX = 0;
+	int			rc;
+
+	dctlprintk((": mptctl_cpq_passthru called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(VENDOR_IOCTL_REQ))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - "
+			"Unable to read in VENDOR_IOCTL_REQ @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	/* Set the IOC number */
+	iocnumX = karg.lc & 0xFF;
+	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
+		return -ENODEV;
+	}
+
+	if (ioc->sh == NULL) {
+		printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - SCSI Host driver not loaded!\n",
+				__FILE__, __LINE__);
+		return -EFAULT;
+	}
+
+	/* Read in the second buffer */
+	if (copy_from_user(&kpass, uarg->argp, sizeof(cpqfc_passthru_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - "
+			"Unable to read in cpqfc_passthru_t @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+
+	/* Generate the SCSI IO command and issue */
+	rc = mptctl_compaq_scsiio(&karg, &kpass);
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_compaq_scsiio - Reformat Compaq structures into driver structures
+ * Call the generic _do_mpt_command function.
+ *
+ * Requires the SCSI host driver to be loaded.
+ * I386 version.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-EFAULT if data unavailable
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ */
+static int
+mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass)
+{
+	struct mpt_ioctl_command karg;
+	SCSIIORequest_t		 request ;
+	SCSIIORequest_t		 *pMf;
+	int			 ii, rc;
+	u8			 opcode;
+
+	/* Fill in parameters to karg */
+	karg.hdr.iocnum = pVenReq->lc;
+	karg.hdr.port = 0;
+	karg.hdr.maxDataSize = 0;	/* not used */
+	karg.timeout = 0;		/* use default */
+
+	karg.replyFrameBufPtr = NULL;	/* no reply data */
+	karg.maxReplyBytes = 0;
+
+	karg.senseDataPtr = pPass->sense_data;
+	karg.maxSenseBytes = pPass->sense_len;	/* max is 40 */
+
+	if (pPass->rw_flag == MPT_COMPAQ_WRITE) {
+		karg.dataOutBufPtr = pPass->bufp;
+		karg.dataOutSize = pPass->len;
+		karg.dataInBufPtr = NULL;
+		karg.dataInSize = 0;
+	} else {
+		karg.dataInBufPtr = pPass->bufp;
+		karg.dataInSize = pPass->len;
+		karg.dataOutBufPtr = NULL;
+		karg.dataOutSize = 0;
+	}
+
+	karg.dataSgeOffset = (sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION))/4;
+
+	/* Construct the Message frame */
+	pMf = &request;
+
+	pMf->TargetID =	(u8) pVenReq->ld;			/* ???? FIXME */
+	pMf->Bus = (u8) pPass->bus;
+	pMf->ChainOffset = 0;
+	pMf->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+
+	/* May need some tweaking here */
+	opcode = (u8) pPass->cdb[0];
+	if (opcode < 0x20)
+		pMf->CDBLength = 6;
+	else if (opcode < 0x60)
+		pMf->CDBLength = 10;
+	else if ((opcode < 0xC0) && (opcode >= 0xA0))
+		pMf->CDBLength = 12;
+	else
+		pMf->CDBLength = 16;
+
+	pMf->SenseBufferLength = karg.maxSenseBytes;	/* max is 40 */
+	pMf->Reserved = 0;
+	pMf->MsgFlags = 0;				/* set later */
+	pMf->MsgContext = 0;				/* set later */
+
+	for (ii = 0; ii < 8; ii++)
+		pMf->LUN[ii] = 0;
+	pMf->LUN[1] = 0;				/* ???? FIXME */
+
+	/* Tag values set by _do_mpt_command */
+	if (pPass->rw_flag == MPT_COMPAQ_WRITE)
+		pMf->Control = MPI_SCSIIO_CONTROL_WRITE;
+	else
+		pMf->Control = MPI_SCSIIO_CONTROL_READ;
+
+	for (ii = 0; ii < 16; ii++)
+		pMf->CDB[ii] = pPass->cdb[ii];
+
+	pMf->DataLength = pPass->len;
+
+	/* All remaining fields are set by the next function
+	 */
+	rc = mptctl_do_mpt_command (karg, (char *)pMf, 1);
+	return rc;
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
+#define	owner_THIS_MODULE  owner:		THIS_MODULE,
+#else
+#define	owner_THIS_MODULE
+#endif
+
+static struct file_operations mptctl_fops = {
+	owner_THIS_MODULE
+	llseek:		no_llseek,
+	read:		mptctl_read,
+	write:		mptctl_write,
+	ioctl:		mptctl_ioctl,
+	open:		mptctl_open,
+	release:	mptctl_release,
+};
+
+static struct miscdevice mptctl_miscdev = {
+	MPT_MINOR,
+	MYNAM,
+	&mptctl_fops
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+
+/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
 extern int register_ioctl32_conversion(unsigned int cmd,
 				       int (*handler)(unsigned int,
@@ -1133,18 +2773,15 @@
 						      unsigned long,
 						      struct file *));
 int unregister_ioctl32_conversion(unsigned int cmd);
-
-struct mpt_fw_xfer32 {
-	unsigned int iocnum;
-	unsigned int fwlen;
-	u32 bufp;
-};
-
-#define MPTFWDOWNLOAD32     _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
-
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* sparc32_XXX functions are used to provide a conversion between
+ * pointers and u32's. If the arg does not contain any pointers, then
+ * a specialized function (sparc32_XXX) is not needed. If the arg
+ * does contain pointer(s), then the specialized function is used
+ * to ensure the structure contents is properly processed by mptctl.
+ */
 static int
 sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
 			unsigned long arg, struct file *filp)
@@ -1156,7 +2793,7 @@
 	int nonblock = (filp->f_flags & O_NONBLOCK);
 	int ret;
 
-	dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+	dctlprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
 
 	if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
 		return -EFAULT;
@@ -1177,13 +2814,131 @@
 	kfw.fwlen = kfw32.fwlen;
 	kfw.bufp = (void *)(unsigned long)kfw32.bufp;
 
-	ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+	ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+
+	up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+	return ret;
+}
+
+static int
+sparc32_mpt_command(unsigned int fd, unsigned int cmd,
+			unsigned long arg, struct file *filp)
+{
+	struct mpt_ioctl_command32 karg32;
+	struct mpt_ioctl_command32 *uarg = (struct mpt_ioctl_command32 *) arg;
+	struct mpt_ioctl_command karg;
+	MPT_ADAPTER *iocp = NULL;
+	int iocnum, iocnumX;
+	int nonblock = (filp->f_flags & O_NONBLOCK);
+	int ret;
+
+	dctlprintk((KERN_INFO MYNAM "::sparc32_mpt_command() called\n"));
+
+	if (copy_from_user(&karg32, (char *)arg, sizeof(karg32)))
+		return -EFAULT;
+
+	/* Verify intended MPT adapter */
+	iocnumX = karg32.hdr.iocnum & 0xFF;
+	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+	    (iocp == NULL)) {
+		printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX);
+		return -ENODEV;
+	}
+
+	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+		return ret;
+
+	/* Copy data to karg */
+	karg.hdr.iocnum = karg32.hdr.iocnum;
+	karg.hdr.port = karg32.hdr.port;
+	karg.timeout = karg32.timeout;
+	karg.maxReplyBytes = karg32.maxReplyBytes;
+
+	karg.dataInSize = karg32.dataInSize;
+	karg.dataOutSize = karg32.dataOutSize;
+	karg.maxSenseBytes = karg32.maxSenseBytes;
+	karg.dataSgeOffset = karg32.dataSgeOffset;
+
+	karg.replyFrameBufPtr = (char *)(unsigned long)karg32.replyFrameBufPtr;
+	karg.dataInBufPtr = (char *)(unsigned long)karg32.dataInBufPtr;
+	karg.dataOutBufPtr = (char *)(unsigned long)karg32.dataOutBufPtr;
+	karg.senseDataPtr = (char *)(unsigned long)karg32.senseDataPtr;
+
+	/* Pass new structure to do_mpt_command
+	 */
+	ret = mptctl_do_mpt_command (karg, (char *) &uarg->MF, 0);
 
 	up(&mptctl_syscall_sem_ioc[iocp->id]);
 
 	return ret;
 }
 
+static int
+sparc32_mptctl_cpq_passthru(unsigned int fd, unsigned int cmd,
+			unsigned long arg, struct file *filp)
+{
+	VENDOR_IOCTL_REQ32	*uarg = (VENDOR_IOCTL_REQ32 *) arg;
+	VENDOR_IOCTL_REQ32	karg32;
+	VENDOR_IOCTL_REQ	karg;
+	cpqfc_passthru32_t	kpass32;
+	cpqfc_passthru_t	kpass;
+	MPT_ADAPTER		*ioc;
+	int			nonblock = (filp->f_flags & O_NONBLOCK);
+	int			iocnum = 0, iocnumX = 0;
+	int			rc;
+	int			ii;
+
+	dctlprintk((KERN_INFO MYNAM "::sparc32_mptctl_cpq_passthru() called\n"));
+
+	if (copy_from_user(&karg32, (char *)arg, sizeof(karg32)))
+		return -EFAULT;
+
+	/* Verify intended MPT adapter */
+	iocnumX = karg32.lc & 0xFF;
+	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX);
+		return -ENODEV;
+	}
+
+	if ((rc = mptctl_syscall_down(ioc, nonblock)) != 0)
+		return rc;
+
+	/* Copy data to karg */
+	karg.ld = karg32.ld;
+	karg.node = karg32.node;
+	karg.lc = karg32.lc;
+	karg.nexus = karg32.nexus;
+	karg.argp = (void *)(unsigned long)karg32.argp;
+
+	/* Read in the second buffer */
+	if (copy_from_user(&kpass32, karg.argp, sizeof(cpqfc_passthru32_t))) {
+		printk(KERN_ERR "%s@%d::sparc32_mptctl_cpq_passthru - "
+			"Unable to read in cpqfc_passthru_t @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	/* Copy the 32bit buffer to kpass */
+	for (ii = 0; ii < 16; ii++)
+		kpass.cdb[ii] = kpass32.cdb[ii];
+	kpass.bus = kpass32.bus;
+	kpass.pdrive = kpass32.pdrive;
+	kpass.len = kpass32.len;
+	kpass.sense_len = kpass32.sense_len;
+	kpass.bufp = (void *)(unsigned long)kpass32.bufp;
+	kpass.rw_flag = kpass32.rw_flag;
+
+	/* Generate the SCSI IO command and issue */
+	rc = mptctl_compaq_scsiio(&karg, &kpass);
+
+	up(&mptctl_syscall_sem_ioc[ioc->id]);
+	return rc;
+}
+
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
@@ -1193,26 +2948,76 @@
 	int err;
 	int i;
 	int where = 1;
+	int sz;
+	u8 *mem;
+	MPT_ADAPTER *ioc = NULL;
+	int iocnum;
 
 	show_mptmod_ver(my_NAME, my_VERSION);
 
 	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
 		sema_init(&mptctl_syscall_sem_ioc[i], 1);
+
+		ioc = NULL;
+		if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) ||
+		    (ioc == NULL)) {
+			continue;
+		}
+		else {
+			/* This adapter instance is found.
+			 * Allocate and inite a MPT_IOCTL structure
+			 */
+			sz = sizeof (MPT_IOCTL);
+			mem = kmalloc(sz, GFP_KERNEL);
+			if (mem == NULL) {
+				err = -ENOMEM;
+				goto out_fail;
+			}
+
+			memset(mem, 0, sz);
+			ioc->ioctl = (MPT_IOCTL *) mem;
+			ioc->ioctl->ioc = ioc;
+			init_timer (&ioc->ioctl->timer);
+			ioc->ioctl->timer.data = (unsigned long) ioc->ioctl;
+			ioc->ioctl->timer.function = mptctl_timer_expired;
+		}
 	}
 
 #if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
-	err = register_ioctl32_conversion(MPTRWPERF, NULL);
+	err = register_ioctl32_conversion(MPTIOCINFO, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTTARGETINFO, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTTEST, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTEVENTQUERY, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTEVENTENABLE, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTEVENTREPORT, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTHARDRESET, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTCOMMAND32, sparc32_mpt_command);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
+					  sparc32_mptfwxfer_ioctl);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(CPQFCTS_GETPCIINFO, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL);
+	err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL);
+	err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTFWDOWNLOAD32, sparc32_mptfwxfer_ioctl);
+	err = register_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32, sparc32_mptctl_cpq_passthru);
 	if (++where && err) goto out_fail;
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
+	/* Register this device */
 	if (misc_register(&mptctl_miscdev) == -1) {
 		printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
 		err = -EBUSY;
@@ -1226,13 +3031,19 @@
 	 *  Install our handler
 	 */
 	++where;
-	if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) <= 0) {
+	if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
 		misc_deregister(&mptctl_miscdev);
 		err = -EBUSY;
 		goto out_fail;
 	}
 
+	if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) {
+		dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+	} else {
+		/* FIXME! */
+	}
+
 	return 0;
 
 out_fail:
@@ -1241,35 +3052,72 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
 	printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
 			" (%d:err=%d)\n", where, err);
-	unregister_ioctl32_conversion(MPTRWPERF);
-	unregister_ioctl32_conversion(MPTRWPERF_CHK);
-	unregister_ioctl32_conversion(MPTRWPERF_RESET);
+	unregister_ioctl32_conversion(MPTIOCINFO);
+	unregister_ioctl32_conversion(MPTTARGETINFO);
+	unregister_ioctl32_conversion(MPTTEST);
+	unregister_ioctl32_conversion(MPTEVENTQUERY);
+	unregister_ioctl32_conversion(MPTEVENTENABLE);
+	unregister_ioctl32_conversion(MPTEVENTREPORT);
+	unregister_ioctl32_conversion(MPTHARDRESET);
+	unregister_ioctl32_conversion(MPTCOMMAND32);
 	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
+	unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO);
+	unregister_ioctl32_conversion(CPQFCTS_GETDRIVER);
+	unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS);
+	unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS);
+	unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32);
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
+	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+		ioc = NULL;
+		if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) ||
+		    (ioc == NULL)) {
+			continue;
+		}
+		else {
+			if (ioc->ioctl) {
+				kfree ( ioc->ioctl );
+				ioc->ioctl = NULL;
+			}
+		}
+	}
 	return err;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 void mptctl_exit(void)
 {
-
-#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
-	unregister_ioctl32_conversion(MPTRWPERF);
-	unregister_ioctl32_conversion(MPTRWPERF_CHK);
-	unregister_ioctl32_conversion(MPTRWPERF_RESET);
-	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
-#endif		/*} linux >= 2.3.x */
-#endif		/*} sparc */
+	int i;
+	MPT_ADAPTER *ioc;
+	int iocnum;
 
 	misc_deregister(&mptctl_miscdev);
-	printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+	printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
-	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
 
+	/* De-register reset handler from base module */
+	mpt_reset_deregister(mptctl_id);
+	dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+
+	/* De-register callback handler from base module */
 	mpt_deregister(mptctl_id);
+	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
+
+	/* Free allocated memory */
+	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+		ioc = NULL;
+		if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) ||
+		    (ioc == NULL)) {
+			continue;
+		}
+		else {
+			if (ioc->ioctl) {
+				kfree ( ioc->ioctl );
+				ioc->ioctl = NULL;
+			}
+		}
+	}
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptctl.h linux-2.4.19-pre5/drivers/message/fusion/mptctl.h
--- linux-2.4.19-pre4/drivers/message/fusion/mptctl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/message/fusion/mptctl.h	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,395 @@
+/*
+ *  linux/drivers/message/fusion/mptioctl.h
+ *      Fusion MPT misc device (ioctl) driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
+ *
+ *  $Id: mptctl.h,v 1.9 2002/02/27 18:44:26 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    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.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef MPTCTL_H_INCLUDED
+#define MPTCTL_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux/version.h"
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *
+ */
+#define MPT_MISCDEV_BASENAME            "mptctl"
+#define MPT_MISCDEV_PATHNAME            "/dev/" MPT_MISCDEV_BASENAME
+
+#define MPT_PRODUCT_LENGTH              12
+
+/*
+ *  Generic MPT Control IOCTLs and structures
+ */
+#define MPT_MAGIC_NUMBER	'm'
+
+#define MPTRWPERF		_IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w)
+
+#define MPTFWDOWNLOAD		_IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
+#define MPTCOMMAND		_IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command)
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+#define MPTFWDOWNLOAD32		_IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
+#define MPTCOMMAND32		_IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command32)
+#endif	/*}*/
+
+#define MPTIOCINFO		_IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo)
+#define MPTTARGETINFO		_IOWR(MPT_MAGIC_NUMBER,18,struct mpt_ioctl_targetinfo)
+#define MPTTEST			_IOWR(MPT_MAGIC_NUMBER,19,struct mpt_ioctl_test)
+#define MPTEVENTQUERY		_IOWR(MPT_MAGIC_NUMBER,21,struct mpt_ioctl_eventquery)
+#define MPTEVENTENABLE		_IOWR(MPT_MAGIC_NUMBER,22,struct mpt_ioctl_eventenable)
+#define MPTEVENTREPORT		_IOWR(MPT_MAGIC_NUMBER,23,struct mpt_ioctl_eventreport)
+#define MPTHARDRESET		_IOWR(MPT_MAGIC_NUMBER,24,struct mpt_ioctl_diag_reset)
+#define MPTFWREPLACE		_IOWR(MPT_MAGIC_NUMBER,25,struct mpt_ioctl_replace_fw)
+
+/*
+ * SPARC PLATFORM REMARK:
+ * IOCTL data structures that contain pointers
+ * will have different sizes in the driver and applications
+ * (as the app. will not use 8-byte pointers).
+ * Apps should use MPTFWDOWNLOAD and MPTCOMMAND.
+ * The driver will convert data from
+ * mpt_fw_xfer32 (mpt_ioctl_command32) to mpt_fw_xfer (mpt_ioctl_command)
+ * internally.
+ */
+struct mpt_fw_xfer {
+	unsigned int	 iocnum;	/* IOC unit number */
+	unsigned int	 fwlen;
+	void		*bufp;		/* Pointer to firmware buffer */
+};
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+struct mpt_fw_xfer32 {
+	unsigned int iocnum;
+	unsigned int fwlen;
+	u32 bufp;
+};
+#endif	/*}*/
+
+
+/*
+ *  IOCTL header structure.
+ *  iocnum - must be defined.
+ *  port - must be defined for all IOCTL commands other than MPTIOCINFO
+ *  maxDataSize - ignored on MPTCOMMAND commands
+ *		- ignored on MPTFWREPLACE commands
+ *		- on query commands, reports the maximum number of bytes to be returned
+ *		  to the host driver (count includes the header).
+ *		  That is, set to sizeof(struct mpt_ioctl_iocinfo) for fixed sized commands.
+ *		  Set to sizeof(struct mpt_ioctl_targetinfo) + datasize for variable
+ *			sized commands. (MPTTARGETINFO, MPTEVENTREPORT)
+ */
+typedef struct _mpt_ioctl_header {
+	unsigned int	 iocnum;	/* IOC unit number */
+	unsigned int	 port;		/* IOC port number */
+	int		 maxDataSize;	/* Maximum Num. bytes to transfer on read */
+} mpt_ioctl_header;
+
+/*
+ * Issue a diagnostic reset
+ */
+struct mpt_ioctl_diag_reset {
+	mpt_ioctl_header hdr;
+};
+
+
+/*
+ *  Adapter Information Page
+ *  Read only.
+ *  Data starts at offset 0xC
+ */
+#define MPT_IOCTL_INTERFACE_FC		(0x01)
+#define MPT_IOCTL_INTERFACE_SCSI	(0x00)
+#define MPT_IOCTL_VERSION_LENGTH	(32)
+
+struct mpt_ioctl_iocinfo {
+	mpt_ioctl_header hdr;
+	int		 adapterType;	/* SCSI or FCP */
+	int		 port;		/* port number */
+	int		 pciId;		/* PCI Id. */
+	int		 hwRev;		/* hardware revision */
+	int		 subSystemDevice;	/* PCI subsystem Device ID */
+	int		 subSystemVendor;	/* PCI subsystem Vendor ID */
+	int		 numDevices;		/* number of devices */
+	int		 FWVersion;		/* FW Version (integer) */
+	int		 BIOSVersion;		/* BIOS Version (integer) */
+	char		 driverVersion[MPT_IOCTL_VERSION_LENGTH];	/* Driver Version (string) */
+	char		 busChangeEvent;
+	char		 hostId;
+	char		 rsvd[2];
+};
+
+/*
+ * Device Information Page
+ * Report the number of, and ids of, all targets
+ * on this IOC.  The ids array is a packed structure
+ * of the known targetInfo.
+ * bits 31-24: reserved
+ *      23-16: LUN
+ *      15- 8: Bus Number
+ *       7- 0: Target ID
+ */
+struct mpt_ioctl_targetinfo {
+	mpt_ioctl_header hdr;
+	int		 numDevices;	/* Num targets on this ioc */
+	int		 targetInfo[1];
+};
+
+
+/*
+ * Event reporting IOCTL's.  These IOCTL's will
+ * use the following defines:
+ */
+struct mpt_ioctl_eventquery {
+	mpt_ioctl_header hdr;
+	unsigned short	 eventEntries;
+	unsigned short	 reserved;
+	unsigned int	 eventTypes;
+};
+
+struct mpt_ioctl_eventenable {
+	mpt_ioctl_header hdr;
+	unsigned int	 eventTypes;
+};
+
+#ifndef __KERNEL__
+typedef struct {
+	uint	event;
+	uint	eventContext;
+	uint	data[2];
+} MPT_IOCTL_EVENTS;
+#endif
+
+struct mpt_ioctl_eventreport {
+	mpt_ioctl_header	hdr;
+	MPT_IOCTL_EVENTS	eventData[1];
+};
+
+#define MPT_MAX_NAME	32
+struct mpt_ioctl_test {
+	mpt_ioctl_header hdr;
+	u8		 name[MPT_MAX_NAME];
+	int		 chip_type;
+	u8		 product [MPT_PRODUCT_LENGTH];
+};
+
+/* Replace the FW image cached in host driver memory
+ * newImageSize - image size in bytes
+ * newImage - first byte of the new image
+ */
+typedef struct mpt_ioctl_replace_fw {
+	mpt_ioctl_header hdr;
+	int		 newImageSize;
+	u8		 newImage[1];
+} mpt_ioctl_replace_fw_t;
+
+/* General MPT Pass through data strucutre
+ *
+ * iocnum
+ * timeout - in seconds, command timeout. If 0, set by driver to
+ *		default value.
+ * replyFrameBufPtr - reply location
+ * dataInBufPtr - destination for read
+ * dataOutBufPtr - data source for write
+ * senseDataPtr - sense data location
+ * maxReplyBytes - maximum number of reply bytes to be sent to app.
+ * dataInSize - num bytes for data transfer in (read)
+ * dataOutSize - num bytes for data transfer out (write)
+ * dataSgeOffset - offset in words from the start of the request message
+ *		to the first SGL
+ * MF[1];
+ *
+ * Remark:  Some config pages have bi-directional transfer,
+ * both a read and a write. The basic structure allows for
+ * a bidirectional set up. Normal messages will have one or
+ * both of these buffers NULL.
+ */
+struct mpt_ioctl_command {
+	mpt_ioctl_header hdr;
+	int		timeout;	/* optional (seconds) */
+	char		*replyFrameBufPtr;
+	char		*dataInBufPtr;
+	char		*dataOutBufPtr;
+	char		*senseDataPtr;
+	int		maxReplyBytes;
+	int		dataInSize;
+	int		dataOutSize;
+	int		maxSenseBytes;
+	int		dataSgeOffset;
+	char		MF[1];
+};
+
+/*
+ * SPARC PLATFORM: See earlier remark.
+ */
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+struct mpt_ioctl_command32 {
+	mpt_ioctl_header hdr;
+	int	timeout;
+	u32	replyFrameBufPtr;
+	u32	dataInBufPtr;
+	u32	dataOutBufPtr;
+	u32	senseDataPtr;
+	int	maxReplyBytes;
+	int	dataInSize;
+	int	dataOutSize;
+	int	maxSenseBytes;
+	int	dataSgeOffset;
+	char	MF[1];
+};
+#endif	/*}*/
+
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+  *	COMPAQ Specific IOCTL Defines and Structures
+  */
+
+#define CPQFCTS_IOC_MAGIC 'Z'
+
+#define CPQFCTS_GETPCIINFO		_IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
+#define CPQFCTS_GETDRIVER		_IOR(CPQFCTS_IOC_MAGIC, 2, int)
+#define CPQFCTS_CTLR_STATUS		_IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status)
+#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress)
+#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ)
+#if defined(__sparc__) && defined(__sparc_v9__)
+#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32)
+#endif
+
+typedef struct {
+	unsigned short bus;
+	unsigned short bus_type;
+	unsigned short device_fn;
+	u32 board_id;
+	u32 slot_number;
+	unsigned short vendor_id;
+	unsigned short device_id;
+	unsigned short class_code;
+	unsigned short sub_vendor_id;
+	unsigned short sub_device_id;
+	u8 serial_number[81];
+} cpqfc_pci_info_struct;
+
+
+typedef struct scsi_fctargaddress {
+	unsigned int host_port_id;
+	u8 host_wwn[8];	/* WW Network Name */
+} Scsi_FCTargAddress;
+
+typedef struct _cpqfc_ctlr_status {
+	u32 status;
+	u32 offline_reason;
+} cpqfc_ctlr_status;
+
+
+/* Compaq SCSI I/O Passthru structures.
+ */
+#define MPT_COMPAQ_READ		0x26
+#define MPT_COMPAQ_WRITE	0x27
+
+typedef struct {
+	int lc;		/* controller number */
+	int node;	/* node number */
+	int ld;		/* target logical id */
+	u32 nexus;
+	void *argp;
+} VENDOR_IOCTL_REQ;
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+typedef struct {
+	int lc;		/* controller number */
+	int node;	/* node number */
+	int ld;		/* target logical id */
+	u32 nexus;
+	u32 argp;
+} VENDOR_IOCTL_REQ32;
+#endif
+
+typedef struct {
+	char cdb[16];		/* cdb */
+	unsigned short bus;	/* bus number */
+	unsigned short pdrive;	/* physical drive */
+	int len;		/* data area size */
+	int sense_len;		/* sense size */
+	char sense_data[40];	/* sense buffer */
+	void *bufp;		/* data buffer pointer */
+	char rw_flag;
+} cpqfc_passthru_t;
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+typedef struct {
+	char cdb[16];		/* cdb */
+	unsigned short bus;	/* bus number */
+	unsigned short pdrive;	/* physical drive */
+	int len;		/* data area size */
+	int sense_len;		/* sense size */
+	char sense_data[40];	/* sense buffer */
+	u32 bufp;		/* data buffer pointer */
+	char rw_flag;
+} cpqfc_passthru32_t;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#endif
+
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptlan.c linux-2.4.19-pre5/drivers/message/fusion/mptlan.c
--- linux-2.4.19-pre4/drivers/message/fusion/mptlan.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptlan.c	Fri Mar 29 14:49:34 2002
@@ -23,10 +23,10 @@
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 2000-2001 LSI Logic Corporation
+ *  Copyright (c) 2000-2002 LSI Logic Corporation
  *  Originally By: Noah Romer
  *
- *  $Id: mptlan.c,v 1.32.2.2 2001/07/12 19:43:33 nromer Exp $
+ *  $Id: mptlan.c,v 1.51 2002/02/11 14:40:55 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -79,6 +79,8 @@
 
 #define MYNAM		"mptlan"
 
+MODULE_LICENSE("GPL");
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  * MPT LAN message sizes without variable part.
@@ -109,8 +111,8 @@
 	MPT_ADAPTER *mpt_dev;
 	u8 pnum; /* Port number in the IOC. This is not a Unix network port! */
 
-	atomic_t buckets_out;	  	/* number of unused buckets on IOC */
-	int bucketthresh;		/* Send more when this many used */
+	atomic_t buckets_out;		/* number of unused buckets on IOC */
+	int bucketthresh;		/* Send more when this many left */
 
 	int *mpt_txfidx; /* Free Tx Context list */
 	int mpt_txfidx_tail;
@@ -123,8 +125,8 @@
 	struct BufferControl *RcvCtl;	/* Receive BufferControl structs */
 	struct BufferControl *SendCtl;	/* Send BufferControl structs */
 
-	int max_buckets_out;	   	/* Max buckets to send to IOC */
-	int tx_max_out;		   	/* IOC's Tx queue len */
+	int max_buckets_out;		/* Max buckets to send to IOC */
+	int tx_max_out;			/* IOC's Tx queue len */
 
 	u32 total_posted;
 	u32 total_received;
@@ -152,7 +154,8 @@
 static int  mpt_lan_reset(struct net_device *dev);
 static int  mpt_lan_close(struct net_device *dev);
 static void mpt_lan_post_receive_buckets(void *dev_id);
-static void mpt_lan_wake_post_buckets_task(struct net_device *dev);
+static void mpt_lan_wake_post_buckets_task(struct net_device *dev, 
+					   int priority);
 static int  mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
 static int  mpt_lan_receive_post_reply(struct net_device *dev,
 				       LANReceivePostReply_t *pRecvRep);
@@ -175,8 +178,10 @@
 
 static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
 
+#ifdef QLOGIC_NAA_WORKAROUND
 static struct NAA_Hosed *mpt_bad_naa = NULL;
 rwlock_t bad_naa_lock;
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -229,7 +234,7 @@
 		case LAN_REPLY_FORM_SEND_SINGLE:
 //			dioprintk((MYNAM "/lan_reply: "
 //				  "calling mpt_lan_send_reply (turbo)\n"));
-  
+
 			// Potential BUG here?  -sralston
 			//	FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
 			//  If/when mpt_lan_send_turbo would return 1 here,
@@ -333,7 +338,7 @@
 	struct net_device *dev = mpt_landev[ioc->id];
 	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
 
-	dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
+	dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
 			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
 
 	if (priv->mpt_rxfidx == NULL)
@@ -342,9 +347,11 @@
 	if (reset_phase == MPT_IOC_PRE_RESET) {
 		int i;
 		unsigned long flags;
-		
+
 		netif_stop_queue(dev);
 
+		dlprintk ((KERN_INFO "mptlan/ioc_reset: called netif_stop_queue for %s.\n", dev->name));
+
 		atomic_set(&priv->buckets_out, 0);
 
 		/* Reset Rx Free Tail index and re-populate the queue. */
@@ -365,7 +372,7 @@
 static int
 mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
-	dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
+	dlprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
 
 	switch (le32_to_cpu(pEvReply->Event)) {
 	case MPI_EVENT_NONE:				/* 00 */
@@ -403,9 +410,9 @@
 
 	if (mpt_lan_reset(dev) != 0) {
 		MPT_ADAPTER *mpt_dev = priv->mpt_dev;
-		
+
 		printk (KERN_WARNING MYNAM "/lan_open: lan_reset failed.");
-		
+
 		if (mpt_dev->active)
 			printk ("The ioc is active. Perhaps it needs to be"
 				" reset?\n");
@@ -429,7 +436,7 @@
 		priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
 	}
 
-	dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
+	dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
 
 	priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
 				   GFP_KERNEL);
@@ -447,12 +454,12 @@
 		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
 	}
 
-/**/	dprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
+/**/	dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
 /**/	for (i = 0; i < priv->tx_max_out; i++)
-/**/		dprintk((" %xh", priv->mpt_txfidx[i]));
-/**/	dprintk(("\n"));
+/**/		dlprintk((" %xh", priv->mpt_txfidx[i]));
+/**/	dlprintk(("\n"));
 
-	dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+	dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
 
 	mpt_lan_post_receive_buckets(dev);
 	printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
@@ -466,7 +473,7 @@
 	}
 
 	netif_start_queue(dev);
-	dprintk((KERN_INFO MYNAM "/lo: Done.\n"));
+	dlprintk((KERN_INFO MYNAM "/lo: Done.\n"));
 
 	return 0;
 out_mpt_rxfidx:
@@ -494,7 +501,7 @@
 	mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
 
 	if (mf == NULL) {
-/*		dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
+/*		dlprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
 		"Unable to allocate a request frame.\n"));
 */
 		return -1;
@@ -523,11 +530,11 @@
 	unsigned int timeout;
 	int i;
 
-	dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
+	dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
 
 	mpt_event_deregister(LanCtx);
 
-	dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
+	dlprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
 		  "since driver was loaded, %d still out\n",
 		  priv->total_posted,atomic_read(&priv->buckets_out)));
 
@@ -537,18 +544,18 @@
 
 	timeout = 2 * HZ;
 	while (atomic_read(&priv->buckets_out) && --timeout) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
 	}
 
 	for (i = 0; i < priv->max_buckets_out; i++) {
 		if (priv->RcvCtl[i].skb != NULL) {
-/**/			dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
+/**/			dlprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
 /**/				  "is still out\n", i));
 			pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma,
-				 	 priv->RcvCtl[i].len,
+					 priv->RcvCtl[i].len,
 					 PCI_DMA_FROMDEVICE);
- 			dev_kfree_skb(priv->RcvCtl[i].skb);
+			dev_kfree_skb(priv->RcvCtl[i].skb);
 		}
 	}
 
@@ -556,11 +563,11 @@
 	kfree (priv->mpt_rxfidx);
 
 	for (i = 0; i < priv->tx_max_out; i++) {
- 		if (priv->SendCtl[i].skb != NULL) {
+		if (priv->SendCtl[i].skb != NULL) {
 			pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma,
 					 priv->SendCtl[i].len,
 					 PCI_DMA_TODEVICE);
- 			dev_kfree_skb(priv->SendCtl[i].skb);
+			dev_kfree_skb(priv->SendCtl[i].skb);
 		}
 	}
 
@@ -599,7 +606,13 @@
 static void
 mpt_lan_tx_timeout(struct net_device *dev)
 {
-	netif_wake_queue(dev);  
+	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+
+	if (mpt_dev->active) {
+		dlprintk (("mptlan/tx_timeout: calling netif_wake_queue for %s.\n", dev->name));
+		netif_wake_queue(dev);
+	}
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -722,7 +735,6 @@
 	dma_addr_t dma;
 	unsigned long flags;
 	int ctx;
-	struct NAA_Hosed *nh;
 	u16 cur_naa = 0x1000;
 
 	dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
@@ -741,7 +753,6 @@
 	mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
 	if (mf == NULL) {
 		netif_stop_queue(dev);
-		dev_kfree_skb(skb);
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 
 		printk (KERN_ERR "%s: Unable to alloc request frame\n",
@@ -791,6 +802,10 @@
 //			IOC_AND_NETDEV_NAMES_s_s(dev),
 //			ctx, skb, skb->data));
 
+#ifdef QLOGIC_NAA_WORKAROUND
+{
+	struct NAA_Hosed *nh;
+
 	/* Munge the NAA for Tx packets to QLogic boards, which don't follow
 	   RFC 2625. The longer I look at this, the more my opinion of Qlogic
 	   drops. */
@@ -803,12 +818,14 @@
 		    (nh->ieee[4] == skb->mac.raw[4]) &&
 		    (nh->ieee[5] == skb->mac.raw[5])) {
 			cur_naa = nh->NAA;
-			dprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
+			dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
 				  "= %04x.\n", cur_naa));
 			break;
 		}
 	}
 	read_unlock_irq(&bad_naa_lock);
+}
+#endif
 
 	pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa         << 16) |
 						    (skb->mac.raw[0] <<  8) |
@@ -821,10 +838,10 @@
 	pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
 
 	/* If we ever decide to send more than one Simple SGE per LANSend, then
-	   we will need to make sure that LAST_ELEMENT only gets set on the 
+	   we will need to make sure that LAST_ELEMENT only gets set on the
 	   last one. Otherwise, bad voodoo and evil funkiness will commence. */
 	pSimple->FlagsLength = cpu_to_le32(
-			((MPI_SGE_FLAGS_LAST_ELEMENT | 
+			((MPI_SGE_FLAGS_LAST_ELEMENT |
 			  MPI_SGE_FLAGS_END_OF_BUFFER |
 			  MPI_SGE_FLAGS_SIMPLE_ELEMENT |
 			  MPI_SGE_FLAGS_SYSTEM_ADDRESS |
@@ -842,23 +859,32 @@
 	dev->trans_start = jiffies;
 
 	dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
-		 	IOC_AND_NETDEV_NAMES_s_s(dev),
-		       	le32_to_cpu(pSimple->FlagsLength)));
+			IOC_AND_NETDEV_NAMES_s_s(dev),
+			le32_to_cpu(pSimple->FlagsLength)));
 
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static inline void
-mpt_lan_wake_post_buckets_task(struct net_device *dev)
+mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
+/* 
+ * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
+ */
 {
 	struct mpt_lan_priv *priv = dev->priv;
-
+	
 	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
-		queue_task(&priv->post_buckets_task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
-				IOC_AND_NETDEV_NAMES_s_s(dev) ));
+		if (priority) {
+			queue_task(&priv->post_buckets_task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		} else {
+			queue_task(&priv->post_buckets_task, &tq_timer);
+			dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
+				   "timer.\n"));
+		}
+	        dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
+			   IOC_AND_NETDEV_NAMES_s_s(dev) ));
 	}
 }
 
@@ -870,7 +896,7 @@
 
 	skb->protocol = mpt_lan_type_trans(skb, dev);
 
-	dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " 
+	dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) "
 		 "delivered to upper level.\n",
 			IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
 
@@ -884,7 +910,7 @@
 		 atomic_read(&priv->buckets_out)));
 
 	if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
-		mpt_lan_wake_post_buckets_task(dev);
+		mpt_lan_wake_post_buckets_task(dev, 1);
 
 	dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
 		  "remaining, %d received back since sod\n",
@@ -956,12 +982,12 @@
 	unsigned long flags;
 	struct sk_buff *skb;
 	u32 ctx;
-	u8 count;
+	int count;
 	int i;
 
 	count = pRecvRep->NumberOfContexts;
 
-/**/	dprintk((KERN_INFO MYNAM "/receive_post_reply: "
+/**/	dlprintk((KERN_INFO MYNAM "/receive_post_reply: "
 		  "IOC returned %d buckets, freeing them...\n", count));
 
 	spin_lock_irqsave(&priv->rxfidx_lock, flags);
@@ -970,11 +996,11 @@
 
 		skb = priv->RcvCtl[ctx].skb;
 
-//		dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
+//		dlprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
 //				IOC_AND_NETDEV_NAMES_s_s(dev)));
-//		dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
-//			  	priv, &(priv->buckets_out)));
-//		dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
+//		dlprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
+//				priv, &(priv->buckets_out)));
+//		dlprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
 
 		priv->RcvCtl[ctx].skb = NULL;
 		pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
@@ -989,13 +1015,13 @@
 
 //	for (i = 0; i < priv->max_buckets_out; i++)
 //		if (priv->RcvCtl[i].skb != NULL)
-//			dprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
+//			dlprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
 //				  "is still out\n", i));
 
-/*	dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
+/*	dlprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
 		  count));
 */
-/**/	dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
+/**/	dlprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
 /**/		  "remaining, %d received back since sod.\n",
 /**/		  atomic_read(&priv->buckets_out), priv->total_received));
 	return 0;
@@ -1010,9 +1036,9 @@
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	struct sk_buff *skb, *old_skb;
 	unsigned long flags;
-	u32 len, ctx;
-	u32 offset;
-	u8 count;
+	u32 len, ctx, offset;
+	u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
+	int count;
 	int i, l;
 
 	dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n"));
@@ -1059,7 +1085,7 @@
 		if (!skb) {
 			printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
 					IOC_AND_NETDEV_NAMES_s_s(dev),
-			       		__FILE__, __LINE__);
+					__FILE__, __LINE__);
 			return -ENOMEM;
 		}
 
@@ -1096,7 +1122,7 @@
 		if (!skb) {
 			printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
 					IOC_AND_NETDEV_NAMES_s_s(dev),
-			       		__FILE__, __LINE__);
+					__FILE__, __LINE__);
 			return -ENOMEM;
 		}
 
@@ -1140,25 +1166,32 @@
 				"Arrgghh! We've done it again!\n");
 	}
 
-#if 0
-	{
-		u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
-		if (remaining < priv->bucketthresh)
-			mpt_lan_wake_post_buckets_task(dev);
-
-		if (remaining == 0)
-			printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
-				"(priv->buckets_out = %d)\n",
-					IOC_AND_NETDEV_NAMES_s_s(dev),
-					atomic_read(&priv->buckets_out));
-		else
-			printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
-				"(priv->buckets_out = %d)\n",
-					IOC_AND_NETDEV_NAMES_s_s(dev),
-					remaining, atomic_read(&priv->buckets_out));
+	if (remaining == 0)
+		printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
+			"(priv->buckets_out = %d)\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev),
+			atomic_read(&priv->buckets_out));
+	else if (remaining < 10)
+		printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
+			"(priv->buckets_out = %d)\n",
+			IOC_AND_NETDEV_NAMES_s_s(dev),
+			remaining, atomic_read(&priv->buckets_out));
+	
+	if ((remaining < priv->bucketthresh) &&
+	    ((atomic_read(&priv->buckets_out) - remaining) > 
+	     MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) {
+		
+		printk (KERN_WARNING MYNAM " Mismatch between driver's "
+			"buckets_out count and fw's BucketsRemaining "
+			"count has crossed the threshold, issuing a "
+			"LanReset to clear the fw's hashtable. You may "
+			"want to check your /var/log/messages for \"CRC "
+			"error\" event notifications.\n");
+		
+		mpt_lan_reset(dev);
+		mpt_lan_wake_post_buckets_task(dev, 0);
 	}
-#endif
-
+	
 	return mpt_lan_receive_skb(dev, skb);
 }
 
@@ -1242,15 +1275,15 @@
 			if (skb == NULL) {
 				skb = dev_alloc_skb(len);
 				if (skb == NULL) {
-/**/					printk (KERN_WARNING
-/**/						MYNAM "/%s: Can't alloc skb\n",
-/**/						__FUNCTION__);
+					printk (KERN_WARNING
+						MYNAM "/%s: Can't alloc skb\n",
+						__FUNCTION__);
 					priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 					spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
 					break;
 				}
 
-		    		dma = pci_map_single(mpt_dev->pcidev, skb->data,
+				dma = pci_map_single(mpt_dev->pcidev, skb->data,
 						     len, PCI_DMA_FROMDEVICE);
 
 				priv->RcvCtl[ctx].skb = skb;
@@ -1308,7 +1341,7 @@
 	dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
 		  __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
 	dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
-	__FUNCTION__, priv->total_posted, priv->total_received)); 
+	__FUNCTION__, priv->total_posted, priv->total_received));
 
 	clear_bit(0, &priv->post_buckets_active);
 }
@@ -1336,7 +1369,7 @@
 	priv->post_buckets_task.data = dev;
 	priv->post_buckets_active = 0;
 
-	dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+	dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
 			__LINE__, dev->mtu + dev->hard_header_len + 4));
 
 	atomic_set(&priv->buckets_out, 0);
@@ -1346,7 +1379,7 @@
 	if (mpt_dev->pfacts[0].MaxLanBuckets < max_buckets_out)
 		priv->max_buckets_out = mpt_dev->pfacts[0].MaxLanBuckets;
 
-	dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
+	dlprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
 			__LINE__,
 			mpt_dev->pfacts[0].MaxLanBuckets,
 			max_buckets_out,
@@ -1389,7 +1422,7 @@
 	dev->tx_timeout = mpt_lan_tx_timeout;
 	dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
 
-	dprintk((KERN_INFO MYNAM ": Finished registering dev "
+	dlprintk((KERN_INFO MYNAM ": Finished registering dev "
 		"and setting initial values\n"));
 
 	SET_MODULE_OWNER(dev);
@@ -1407,9 +1440,11 @@
 
 	show_mptmod_ver(LANAME, LANVER);
 
-	/* Init the global r/w lock for the bad_naa list. We want to do this 
+#ifdef QLOGIC_NAA_WORKAROUND
+	/* Init the global r/w lock for the bad_naa list. We want to do this
 	   before any boards are initialized and may be used. */
 	rwlock_init(&bad_naa_lock);
+#endif
 
 	if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
 		printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
@@ -1419,10 +1454,10 @@
 	/* Set the callback index to be used by driver core for turbo replies */
 	mpt_lan_index = LanCtx;
 
-	dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
+	dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
 
 	if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) {
-		dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+		dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
 	} else {
 		printk(KERN_ERR MYNAM ": Eieee! unable to register a reset "
 		       "handler with mptbase! The world is at an end! "
@@ -1458,7 +1493,7 @@
 //							IOC_AND_NETDEV_NAMES_s_s(dev),
 //							NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
 					mpt_landev[j] = dev;
-					dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
+					dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
 							dev, j,  mpt_landev[j]));
 
 					j++;
@@ -1508,18 +1543,15 @@
 MODULE_PARM(tx_max_out_p, "i");
 MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
 
-MODULE_LICENSE("GPL");
-
 module_init(mpt_lan_init);
 module_exit(mpt_lan_exit);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static unsigned short
-mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) 
+mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
 	struct fcllc *fcllc;
-	u16 source_naa = fch->stype, found = 0;
 
 	skb->mac.raw = skb->data;
 	skb_pull(skb, sizeof(struct mpt_lan_ohdr));
@@ -1535,7 +1567,7 @@
 		printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
 				NETDEV_PTR_TO_IOC_NAME_s(dev));
 		printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
-		       		fch->saddr[0], fch->saddr[1], fch->saddr[2],
+				fch->saddr[0], fch->saddr[1], fch->saddr[2],
 				fch->saddr[3], fch->saddr[4], fch->saddr[5]);
 	}
 
@@ -1555,6 +1587,10 @@
 
 	fcllc = (struct fcllc *)skb->data;
 
+#ifdef QLOGIC_NAA_WORKAROUND
+{
+	u16 source_naa = fch->stype, found = 0;
+
 	/* Workaround for QLogic not following RFC 2625 in regards to the NAA
 	   value. */
 
@@ -1562,15 +1598,15 @@
 		source_naa = swab16(source_naa);
 
 	if (fcllc->ethertype == htons(ETH_P_ARP))
-	    dprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of "
+	    dlprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of "
 		      "%04x.\n", source_naa));
 
-	if ((fcllc->ethertype == htons(ETH_P_ARP)) && 
+	if ((fcllc->ethertype == htons(ETH_P_ARP)) &&
 	   ((source_naa >> 12) !=  MPT_LAN_NAA_RFC2625)){
 		struct NAA_Hosed *nh, *prevnh;
 		int i;
 
-		dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from "
+		dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from "
 			  "system with non-RFC 2625 NAA value (%04x).\n",
 			  source_naa));
 
@@ -1584,17 +1620,17 @@
 			    (nh->ieee[4] == fch->saddr[4]) &&
 			    (nh->ieee[5] == fch->saddr[5])) {
 				found = 1;
-				dprintk ((KERN_INFO "mptlan/type_trans: ARP Re"
+				dlprintk ((KERN_INFO "mptlan/type_trans: ARP Re"
 					 "q/Rep w/ bad NAA from system already"
 					 " in DB.\n"));
 				break;
 			}
 		}
-		
+
 		if ((!found) && (nh == NULL)) {
 
 			nh = kmalloc(sizeof(struct NAA_Hosed), GFP_KERNEL);
-			dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/"
+			dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/"
 				 " bad NAA from system not yet in DB.\n"));
 
 			if (nh != NULL) {
@@ -1603,11 +1639,11 @@
 					mpt_bad_naa = nh;
 				if (prevnh)
 					prevnh->next = nh;
-				
+
 				nh->NAA = source_naa; /* Set the S_NAA value. */
 				for (i = 0; i < FC_ALEN; i++)
 					nh->ieee[i] = fch->saddr[i];
-				dprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:"
+				dlprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:"
 					  "%02x:%02x with non-compliant S_NAA value.\n",
 					  fch->saddr[0], fch->saddr[1], fch->saddr[2],
 					  fch->saddr[3], fch->saddr[4],fch->saddr[5]));
@@ -1622,9 +1658,10 @@
 		}
 		write_unlock_irq(&bad_naa_lock);
 	}
-		
+}
+#endif
 
-	/* Strip the SNAP header from ARP packets since we don't 
+	/* Strip the SNAP header from ARP packets since we don't
 	 * pass them through to the 802.2/SNAP layers.
 	 */
 	if (fcllc->dsap == EXTENDED_SAP &&
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptlan.h linux-2.4.19-pre5/drivers/message/fusion/mptlan.h
--- linux-2.4.19-pre4/drivers/message/fusion/mptlan.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptlan.h	Fri Mar 29 14:49:34 2002
@@ -21,6 +21,7 @@
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
+#include <linux/delay.h>
 // #include <linux/trdevice.h>
 
 #include <asm/uaccess.h>
@@ -43,13 +44,15 @@
 
 #define MPT_LAN_MAX_BUCKETS_OUT 256
 #define MPT_LAN_BUCKET_THRESH	18 /* 9 buckets in one message */
+#define MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH 10
 #define MPT_LAN_RX_COPYBREAK	200
-#define MPT_LAN_TX_TIMEOUT 	(1*HZ)
+#define MPT_LAN_TX_TIMEOUT	(1*HZ)
 #define MPT_TX_MAX_OUT_LIM      127
 
 #define MPT_LAN_MIN_MTU		96		/* RFC2625 */
 #define MPT_LAN_MAX_MTU		65280		/* RFC2625 */
-#define MPT_LAN_MTU             16128		/* be nice to slab allocator */
+#define MPT_LAN_MTU             13312		/* Max perf range + lower mem
+						   usage than 16128 */
 
 #define MPT_LAN_NAA_RFC2625     0x1
 #define MPT_LAN_NAA_QLOGIC      0x2
@@ -66,6 +69,12 @@
 #define dioprintk(x)
 #endif
 
+#ifdef MPT_LAN_DEBUG
+#define dlprintk(x)  printk x
+#else
+#define dlprintk(x)
+#endif
+
 #define NETDEV_TO_LANPRIV_PTR(d)	((struct mpt_lan_priv *)(d)->priv)
 #define NETDEV_PTR_TO_IOC_NAME_s(d)	(NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name)
 #define IOC_AND_NETDEV_NAMES_s_s(d)	NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptscsih.c linux-2.4.19-pre5/drivers/message/fusion/mptscsih.c
--- linux-2.4.19-pre4/drivers/message/fusion/mptscsih.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptscsih.c	Fri Mar 29 14:49:34 2002
@@ -9,17 +9,24 @@
  *      This driver would not exist if not for Alan Cox's development
  *      of the linux i2o driver.
  *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
  *      A huge debt of gratitude is owed to David S. Miller (DaveM)
  *      for fixing much of the stupid and broken stuff in the early
  *      driver while porting to sparc64 platform.  THANK YOU!
  *
  *      (see mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Original author: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.29.4.1 2001/09/18 03:22:30 sralston Exp $
+ *  $Id: mptscsih.c,v 1.80 2002/02/27 18:44:27 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -66,6 +73,9 @@
 #include <linux/kdev_t.h>
 #include <linux/blkdev.h>
 #include <linux/blk.h>		/* for io_request_lock (spinlock) decl */
+#include <linux/delay.h>	/* for mdelay */
+#include <linux/interrupt.h>	/* needed for in_interrupt() proto */
+#include <linux/reboot.h>	/* notifier code */
 #include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "../../scsi/sd.h"
@@ -83,52 +93,131 @@
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
 
+/* Set string for command line args from insmod */
+#ifdef MODULE
+char *mptscsih = 0;
+MODULE_PARM(mptscsih, "s");
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 typedef struct _BIG_SENSE_BUF {
-	u8		data[256];
+	u8		data[MPT_SENSE_BUFFER_ALLOC];
 } BIG_SENSE_BUF;
 
-typedef struct _MPT_SCSI_HOST {
-	MPT_ADAPTER		 *ioc;
-	int			  port;
-	struct scsi_cmnd	**ScsiLookup;
-	u8			 *SgHunks;
-	dma_addr_t		  SgHunksDMA;
-	u32			  qtag_tick;
-} MPT_SCSI_HOST;
-
-typedef struct _MPT_SCSI_DEV {
-	struct _MPT_SCSI_DEV	 *forw;
-	struct _MPT_SCSI_DEV	 *back;
-	MPT_ADAPTER		 *ioc;
-	int			  sense_sz;
-	BIG_SENSE_BUF		  CachedSense;
-	unsigned long		  io_cnt;
-	unsigned long		  read_cnt;
-} MPT_SCSI_DEV;
+#define MPT_SCANDV_GOOD			(0x00000000) /* must be 0 */
+#define MPT_SCANDV_DID_RESET		(0x00000001)
+#define MPT_SCANDV_SENSE		(0x00000002)
+#define MPT_SCANDV_SOME_ERROR		(0x00000004)
+#define MPT_SCANDV_SELECTION_TIMEOUT	(0x00000008)
+
+#define MPT_SCANDV_MAX_RETRIES		(10)
+
+#define MPT_ICFLAG_BUF_CAP	0x01	/* ReadBuffer Read Capacity format */
+#define MPT_ICFLAG_ECHO		0x02	/* ReadBuffer Echo buffer format */
+#define MPT_ICFLAG_PHYS_DISK	0x04	/* Any SCSI IO but do Phys Disk Format */
+#define MPT_ICFLAG_TAGGED_CMD	0x08	/* Do tagged IO */
+#define MPT_ICFLAG_DID_RESET	0x20	/* Bus Reset occured with this command */
+#define MPT_ICFLAG_RESERVED	0x40	/* Reserved has been issued */
+
+typedef struct _internal_cmd {
+	char		*data;		/* data pointer */
+	dma_addr_t	data_dma;	/* data dma address */
+	int		size;		/* transfer size */
+	u8		cmd;		/* SCSI Op Code */
+	u8		bus;		/* bus number */
+	u8		id;		/* SCSI ID (virtual) */
+	u8		lun;
+	u8		flags;		/* Bit Field - See above */
+	u8		physDiskNum;	/* Phys disk number, -1 else */
+	u8		rsvd2;
+	u8		rsvd;
+} INTERNAL_CMD;
+
+typedef struct _negoparms {
+	u8 width;
+	u8 offset;
+	u8 factor;
+	u8 flags;
+} NEGOPARMS;
+
+typedef struct _dv_parameters {
+	NEGOPARMS	 max;
+	NEGOPARMS	 now;
+	u8		 cmd;
+	u8		 id;
+	u16		 pad1;
+} DVPARAMETERS;
+
 
 /*
  *  Other private/forward protos...
  */
-
 static int	mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void	mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
 static int	mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static int	mptscsih_io_direction(Scsi_Cmnd *cmd);
+
+static int	mptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+				 SCSIIORequest_t *pReq, int req_idx);
+static void	mptscsih_AddNullSGE(SCSIIORequest_t *pReq);
+static int	mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
+static void	mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
+static int	mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
+
 static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
-static u32	SCPNT_TO_MSGCTX(Scsi_Cmnd *sc);
+#ifndef MPT_SCSI_USE_NEW_EH
+static void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
+#endif
+static u32	SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc);
+static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
+static void	post_pendingQ_commands(MPT_SCSI_HOST *hd);
+
+static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);
+static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);
 
 static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
+static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
+void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target);
+static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data);
+static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
+static int	mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
+static int	mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void	mptscsih_timer_expired(unsigned long data);
+static void	mptscsih_taskmgmt_timeout(unsigned long data);
+static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
+static int	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
+static void	mptscsih_domainValidation(void *hd);
+static void	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
+static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
+#endif
+static int	mptscsih_setup(char *str);
+static int	mptscsih_halt(struct notifier_block *nb, ulong event, void *buf);
+
+/*
+ *	Reboot Notification
+ */
+static struct notifier_block mptscsih_notifier = {
+	mptscsih_halt, NULL, 0
+};
+
+/*
+ *	Private data...
+ */
 
 static int	mpt_scsi_hosts = 0;
 static atomic_t	queue_depth;
 
 static int	ScsiDoneCtx = -1;
 static int	ScsiTaskCtx = -1;
+static int	ScsiScanDvCtx = -1; /* Used only for bus scan and dv */
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
 static struct proc_dir_entry proc_mpt_scsihost =
@@ -141,23 +230,40 @@
 };
 #endif
 
-#define SNS_LEN(scp)  sizeof((scp)->sense_buffer)
+#define SNS_LEN(scp)	sizeof((scp)->sense_buffer)
 
 #ifndef MPT_SCSI_USE_NEW_EH
 /*
  *  Stuff to handle single-threading SCSI TaskMgmt
  *  (abort/reset) requests...
  */
-static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED;
-static MPT_Q_TRACKER mpt_scsih_taskQ = {
-	(MPT_FRAME_HDR*) &mpt_scsih_taskQ,
-	(MPT_FRAME_HDR*) &mpt_scsih_taskQ
-};
-static int mpt_scsih_taskQ_cnt = 0;
-static int mpt_scsih_taskQ_bh_active = 0;
-static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL;
+static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
+static int mytaskQ_bh_active = 0;
+static struct tq_struct	mptscsih_ptaskfoo;
+static atomic_t	mpt_taskQdepth;
+#endif
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*
+ * Domain Validation task structure
+ */
+static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
+static int dvtaskQ_active = 0;
+static int dvtaskQ_release = 0;
+static struct tq_struct	mptscsih_dvTask;
 #endif
 
+/*
+ * Wait Queue setup
+ */
+static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq);
+static int scandv_wait_done = 1;
+
+/* Driver default setup
+ */
+static struct mptscsih_driver_setup
+	driver_setup = MPTSCSIH_DRIVER_SETUP;
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mptscsih_io_done - Main SCSI IO callback routine registered to
@@ -174,123 +280,109 @@
  *	Returns 1 indicating alloc'd request frame ptr should be freed.
  */
 static int
-mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
 	Scsi_Cmnd	*sc;
 	MPT_SCSI_HOST	*hd;
-	MPT_SCSI_DEV	*mpt_sdev = NULL;
+	SCSIIORequest_t	*pScsiReq;
+	SCSIIOReply_t	*pScsiReply;
+	unsigned long	 flags;
 	u16		 req_idx;
 
+	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
 	if ((mf == NULL) ||
 	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-		printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf);
-		return 1;
+		printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
+				ioc->name, mf?"BAD":"NULL", mf);
+		/* return 1; CHECKME SteveR. Don't free. */
+		return 0;
 	}
 
-	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 	sc = hd->ScsiLookup[req_idx];
-	hd->ScsiLookup[req_idx] = NULL;
+	if (sc == NULL) {
+		MPIHeader_t *hdr = (MPIHeader_t *)mf;
 
-	dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+		atomic_dec(&queue_depth);
 
-	atomic_dec(&queue_depth);
+		/* writeSDP1 will use the ScsiDoneCtx
+		 * There is no processing for the reply.
+		 * Just return to the calling function.
+		 */
+		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
+			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
 
-	/*
-	 *  Check for {1st} {IO} completion to "new" device.
-	 *  How do we know it's a new device?
-	 *  If we haven't set SDpnt->hostdata I guess...
-	 */
-	if (sc && sc->device) {
-		mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata;
-		if (!mpt_sdev) {
-			dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n",
-					   sc->device->id, sc->device->lun, sc->device->channel));
-			if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) {
-				printk(KERN_ERR MYNAM ": ERROR - kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV));
-			} else {
-				memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV));
-				mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata;
-				mpt_sdev->ioc = ioc;
-			}
-		} else {
-			if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) {
-				if (++mpt_sdev->read_cnt == 3) {
-					dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n",
-							sc->cmnd[0]));
-				}
-			}
-#if 0
-			if (mpt_sdev->sense_sz) {
-				/*
-				 *  Completion of first IO down this path
-				 *  *should* invalidate device SenseData...
-				 */
-				mpt_sdev->sense_sz = 0;
-			}
-#endif
-		}
+		mptscsih_freeChainBuffers(hd, req_idx);
+		return 1;
 	}
 
-#if 0
-{
-	MPT_FRAME_HDR	*mf_chk;
+	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p)\n",
+			ioc->name, mf, mr, sc));
 
-	/* This, I imagine, is a costly check, but...
-	 *  If abort/reset active, check to see if this is a IO
-	 *  that completed while ABORT/RESET for it is waiting
-	 *  on our taskQ!
-	 */
-	if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
-		/* If ABORT for this IO is queued, zap it! */
-		mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
-		if (mf_chk != NULL) {
-			sc->result = DID_ABORT << 16;
-			spin_lock_irqsave(&io_request_lock, flags);
-			sc->scsi_done(sc);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-			return 1;
-		}
-	}
-}
-#endif
+	atomic_dec(&queue_depth);
 
-	if (r != NULL && sc != NULL) {
-		SCSIIOReply_t	*pScsiReply;
-		SCSIIORequest_t *pScsiReq;
-		u16		 status;
+	sc->result = DID_OK << 16;		/* Set default reply as OK */
+	pScsiReq = (SCSIIORequest_t *) mf;
+	pScsiReply = (SCSIIOReply_t *) mr;
+
+	if (pScsiReply == NULL) {
+		/* special context reply handling */
+
+		/* If regular Inquiry cmd - save inquiry data
+		 */
+		if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
+			int	 dlen;
 
-		pScsiReply = (SCSIIOReply_t *) r;
-		pScsiReq = (SCSIIORequest_t *) mf;
+			dlen = le32_to_cpu(pScsiReq->DataLength);
+			if (dlen >= SCSI_STD_INQUIRY_BYTES) {
+				mptscsih_initTarget(hd,
+						hd->port,
+						sc->target,
+						pScsiReq->LUN[1],
+						sc->buffer,
+						dlen);
+			}
+		}
+		clear_sense_flag(hd, pScsiReq);
+
+		if (hd->is_spi)
+			mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
+	} else {
+		u32	 xfer_cnt;
+		u16	 status;
+		u8	 scsi_state;
 
 		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+		scsi_state = pScsiReply->SCSIState;
 
-		dprintk((KERN_NOTICE MYNAM ": Uh-Oh!  (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+		dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
+				ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
+				mf, mr, sc));
 		dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
-				     ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
-				     status, pScsiReply->SCSIState, pScsiReply->SCSIStatus,
-				     le32_to_cpu(pScsiReply->IOCLogInfo)));
+				", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+				status, scsi_state, pScsiReply->SCSIStatus,
+				le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
+			copy_sense_data(sc, hd, mf, pScsiReply);
 
 		/*
 		 *  Look for + dump FCP ResponseInfo[]!
 		 */
-		if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
 			dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
 					     le32_to_cpu(pScsiReply->ResponseInfo)));
 		}
 
 		switch(status) {
 		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */
-			/*sc->result = DID_BUS_BUSY << 16;*/		/* YIKES! - Seems to
-									 * kill linux interrupt
-									 * handler
-									 */
-			sc->result = STS_BUSY;				/* Try SCSI BUSY! */
-			break;
-
-		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
-			/*  Not real sure here...  */
-			sc->result = DID_OK << 16;
+			/* CHECKME!
+			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
+			 * But not: DID_BUS_BUSY lest one risk
+			 * killing interrupt handler:-(
+			 */
+			sc->result = STS_BUSY;
 			break;
 
 		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */
@@ -299,10 +391,29 @@
 			break;
 
 		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
-			/*  Spoof to SCSI Selection Timeout!  */
+			/* Spoof to SCSI Selection Timeout! */
 			sc->result = DID_NO_CONNECT << 16;
 			break;
 
+		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
+#ifndef MPT_SCSI_USE_NEW_EH
+			search_taskQ_for_cmd(sc, hd);
+#endif
+			/* Linux handles an unsolicited DID_RESET better 
+			 * than an unsolicited DID_ABORT.
+			 */
+			sc->result = DID_RESET << 16;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
+		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
+#ifndef MPT_SCSI_USE_NEW_EH
+			search_taskQ_for_cmd(sc, hd);
+#endif
+			sc->result = DID_RESET << 16;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
 			/*
 			 *  YIKES!  I just discovered that SCSI IO which
@@ -312,78 +423,148 @@
 			 *  Do upfront check for valid SenseData and give it
 			 *  precedence!
 			 */
+			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+			clear_sense_flag(hd, pScsiReq);
 			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-				copy_sense_data(sc, hd, mf, pScsiReply);
-				sc->result = pScsiReply->SCSIStatus;
-				break;
+				/* Have already saved the status and sense data
+				 */
+				;
+			} else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+				/* What to do?
+				 */
+				sc->result = DID_SOFT_ERROR << 16;
+			}
+			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+				/*  Not real sure here either...  */
+				sc->result = DID_RESET << 16;
 			}
 
-			dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow));
-			dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount)));
+			/* Give report and update residual count.
+			 */
+			xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+			dprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+					sc->underflow));
+			dprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-			sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
-			dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid));
+			sc->resid = sc->request_bufflen - xfer_cnt;
+			dprintk((KERN_NOTICE "  SET sc->resid=%02xh\n", sc->resid));
 #endif
 
-			if (pScsiReq->CDB[0] == INQUIRY) {
-				sc->result = (DID_OK << 16);
-				break;
-			}
+			/* Report Queue Full
+			 */
+			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
 
-			/* workaround attempts... */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-			if (sc->resid >= 0x200) {
-				/* GRRRRR...
-				 *   //sc->result = DID_SOFT_ERROR << 16;
-				 * Try spoofing to BUSY
-				 */
-				sc->result = STS_BUSY;
-			} else {
-				sc->result = 0;
+			/* If regular Inquiry cmd and some data was transferred,
+			 * save inquiry data
+			 */
+			if (    pScsiReq->CDB[0] == INQUIRY
+			     && !(pScsiReq->CDB[1] & 0x3)
+			     && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
+			   ) {
+				mptscsih_initTarget(hd,
+						hd->port,
+						sc->target,
+						pScsiReq->LUN[1],
+						sc->buffer,
+						xfer_cnt);
 			}
-#else
-			sc->result = 0;
-#endif
-			break;
 
-		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
-			sc->result = DID_ABORT << 16;
-			break;
-
-		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
-		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
-			sc->result = DID_RESET << 16;
+			if (hd->is_spi)
+				mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
 			break;
 
+		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
-			sc->result = pScsiReply->SCSIStatus;
+			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+			clear_sense_flag(hd, pScsiReq);
 
 			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-				copy_sense_data(sc, hd, mf, pScsiReply);
-
-				/*  If running agains circa 200003dd 909 MPT f/w,
-				 *  may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
-				 *  (QUEUE_FULL) returned from device!	--> get 0x0000?128
-				 *  and with SenseBytes set to 0.
+				/*
+				 * If running agains circa 200003dd 909 MPT f/w,
+				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
+				 * (QUEUE_FULL) returned from device! --> get 0x0000?128
+				 * and with SenseBytes set to 0.
 				 */
 				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
 					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+				/* ADDED 20011120 -sralston
+				 * Scsi mid-layer (old_eh) doesn't seem to like it
+				 * when RAID returns SCSIStatus=02 (CHECK CONDITION),
+				 * SenseKey=01 (RECOVERED ERROR), ASC/ASCQ=95/01.
+				 * Seems to be * treating this as a IO error:-(
+				 *
+				 * So just lie about it altogether here.
+				 *
+				 * NOTE: It still gets reported to syslog via
+				 * mpt_ScsiHost_ErrorReport from copy_sense_data
+				 * call far above.
+				 */
+				if (    pScsiReply->SCSIStatus == STS_CHECK_CONDITION
+				     && SD_Sense_Key(sc->sense_buffer) == SK_RECOVERED_ERROR
+				   ) {
+					sc->result = 0;
+				}
+#endif
+
 			}
-			else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			else if (pScsiReply->SCSIState &
+			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
+			   ) {
 				/*
-				 *  What to do?
+				 * What to do?
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
 			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
-				sc->result = DID_ABORT << 16;
+				sc->result = DID_RESET << 16;
+			}
+			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+				/* Device Inq. data indicates that it supports
+				 * QTags, but rejects QTag messages.
+				 * This command completed OK.
+				 *
+				 * Not real sure here either so do nothing...  */
 			}
 
 			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
 				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
 
+			/* Add handling of:
+			 * Reservation Conflict, Busy,
+			 * Command Terminated, CHECK
+			 */
+
+			/* If regular Inquiry cmd - save inquiry data
+			 */
+			xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+			if (    sc->result == (DID_OK << 16)
+			     && pScsiReq->CDB[0] == INQUIRY
+			     && !(pScsiReq->CDB[1] & 0x3)
+			     && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
+			   ) {
+				mptscsih_initTarget(hd,
+						hd->port,
+						sc->target,
+						pScsiReq->LUN[1],
+						sc->buffer,
+						xfer_cnt);
+			}
+
+			if (hd->is_spi)
+				mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
+			break;
+
+		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
+			if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+				/*  Not real sure here either...  */
+				sc->result = DID_RESET << 16;
+			} else
+				sc->result = DID_SOFT_ERROR << 16;
 			break;
 
 		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */
@@ -395,50 +576,50 @@
 		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
 		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
 		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
-		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
-		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
 		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
 		default:
 			/*
-			 *  What to do?
+			 * What to do?
 			 */
 			sc->result = DID_SOFT_ERROR << 16;
 			break;
 
 		}	/* switch(status) */
 
-		dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result));
+		dprintk((KERN_NOTICE "  sc->result set to %08xh\n", sc->result));
+	} /* end of address reply case */
+
+	/* Unmap the DMA buffers, if any. */
+	if (sc->use_sg) {
+		pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
+			    sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction));
+	} else if (sc->request_bufflen) {
+		scPrivate	*my_priv;
+
+		my_priv = (scPrivate *) &sc->SCp;
+		pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
+			   sc->request_bufflen,
+			   scsi_to_pci_dma_dir(sc->sc_data_direction));
 	}
 
-	if (sc != NULL) {
-		unsigned long flags;
+	hd->ScsiLookup[req_idx] = NULL;
 
-		/* Unmap the DMA buffers, if any. */
-		if (sc->use_sg) {
-			pci_unmap_sg(ioc->pcidev,
-				     (struct scatterlist *) sc->request_buffer,
-				     sc->use_sg,
-				     scsi_to_pci_dma_dir(sc->sc_data_direction));
-		} else if (sc->request_bufflen) {
-			pci_unmap_single(ioc->pcidev,
-					 (dma_addr_t)((long)sc->SCp.ptr),
-					 sc->request_bufflen,
-					 scsi_to_pci_dma_dir(sc->sc_data_direction));
-		}
+	sc->host_scribble = NULL;	/* CHECKME! - Do we need to clear this??? */
 
-		spin_lock_irqsave(&io_request_lock, flags);
-		sc->scsi_done(sc);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-	}
+	spin_lock_irqsave(&io_request_lock, flags);
+	sc->scsi_done(sc);		/* Issue the command callback */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
+	/* Free Chain buffers */
+	mptscsih_freeChainBuffers(hd, req_idx);
 	return 1;
 }
 
-#ifndef MPT_SCSI_USE_NEW_EH
+#ifndef MPT_SCSI_USE_NEW_EH	/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	search_taskQ - Search SCSI task mgmt request queue for specific
- *			request type
+ *	request type.
  *	@remove: (Boolean) Should request be removed if found?
  *	@sc: Pointer to Scsi_Cmnd structure
  *	@task_type: Task type to search for
@@ -447,42 +628,55 @@
  *	was not found.
  */
 static MPT_FRAME_HDR *
-search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type)
+search_taskQ(int remove, Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, u8 task_type)
 {
 	MPT_FRAME_HDR *mf = NULL;
 	unsigned long flags;
 	int count = 0;
 	int list_sz;
 
-	dslprintk((KERN_INFO MYNAM ": spinlock#1\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	list_sz = mpt_scsih_taskQ_cnt;
-	if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
-		mf = mpt_scsih_taskQ.head;
+	dprintk((KERN_INFO MYNAM ": search_taskQ(%d,sc=%p,%d) called\n",
+			remove, sc, task_type));
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	list_sz = hd->taskQcnt;
+	if (! Q_IS_EMPTY(&hd->taskQ)) {
+		mf = hd->taskQ.head;
 		do {
 			count++;
 			if (mf->u.frame.linkage.argp1 == sc &&
 			    mf->u.frame.linkage.arg1 == task_type) {
 				if (remove) {
 					Q_DEL_ITEM(&mf->u.frame.linkage);
-					mpt_scsih_taskQ_cnt--;
+					hd->taskQcnt--;
+					atomic_dec(&mpt_taskQdepth);
+
+					/* Don't save mf into nextmf because
+					 * exit after command has been deleted.
+					 */
+
+					/* Place the MF back on the FreeQ */
+					Q_ADD_TAIL(&hd->ioc->FreeQ,
+						&mf->u.frame.linkage,
+						MPT_FRAME_HDR);
+#ifdef MFCNT
+					hd->ioc->mfcnt--;
+#endif
 				}
 				break;
 			}
-		} while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ);
-		if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) {
+		} while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
+		if (mf == (MPT_FRAME_HDR*)&hd->taskQ) {
 			mf = NULL;
 		}
 	}
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
 	if (list_sz) {
-		dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n",
-				   remove, sc, task_type,
+		dprintk((KERN_INFO "  Results=%p (%sFOUND%s)!\n",
 				   mf,
 				   mf ? "" : "NOT_",
 				   (mf && remove) ? "+REMOVED" : "" ));
-		dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n",
+		dprintk((KERN_INFO "  (searched thru %d of %d items on taskQ)\n",
 				   count,
 				   list_sz ));
 	}
@@ -490,2107 +684,6547 @@
 	return mf;
 }
 
-#endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-/*
- *  Hack!  I'd like to report if a device is returning QUEUE_FULL
- *  but maybe not each and every time...
- */
-static long last_queue_full = 0;
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
- *	from a SCSI target device.
- *	@sc: Pointer to Scsi_Cmnd structure
- *	@pScsiReply: Pointer to SCSIIOReply_t
- *	@pScsiReq: Pointer to original SCSI request
+ *	clean_taskQ - Clean the  SCSI task mgmt request for
+ *			this SCSI host instance.
+ *	@hd: MPT_SCSI_HOST pointer
  *
- *	This routine periodically reports QUEUE_FULL status returned from a
- *	SCSI target device.  It reports this to the console via kernel
- *	printk() API call, not more than once every 10 seconds.
+ *	Returns: None.
  */
 static void
-mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+clean_taskQ(MPT_SCSI_HOST *hd)
 {
-	long time = jiffies;
+	MPT_FRAME_HDR *mf = NULL;
+	MPT_FRAME_HDR *nextmf = NULL;
+	MPT_ADAPTER *ioc = hd->ioc;
+	unsigned long flags;
 
-	if (time - last_queue_full > 10 * HZ) {
-		printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL!  SCSI bus:target:lun = %d:%d:%d\n",
-				0, sc->target, sc->lun);
-		last_queue_full = time;
+	dprintk((KERN_INFO MYNAM ": clean_taskQ called\n"));
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+	if (! Q_IS_EMPTY(&hd->taskQ)) {
+		mf = hd->taskQ.head;
+		do {
+			Q_DEL_ITEM(&mf->u.frame.linkage);
+			hd->taskQcnt--;
+			atomic_dec(&mpt_taskQdepth);
+
+			nextmf = mf->u.frame.linkage.forw;
+
+			/* Place the MF back on the FreeQ */
+			Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage,
+				MPT_FRAME_HDR);
+#ifdef MFCNT
+			hd->ioc->mfcnt--;
+#endif
+		} while ((mf = nextmf) != (MPT_FRAME_HDR*)&hd->taskQ);
 	}
-}
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int BeenHereDoneThat = 0;
+	return;
+}
 
-/*  SCSI fops start here...  */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
- *	linux scsi mid-layer.
- *	@tpnt: Pointer to Scsi_Host_Template structure
- *
- *	(linux Scsi_Host_Template.detect routine)
+/*
+ *	search_taskQ_for_cmd - Search the  SCSI task mgmt request queue for
+ *			the specified command. If found, delete
+ *	@hd: MPT_SCSI_HOST pointer
  *
- *	Returns number of SCSI host adapters that were successfully
- *	registered with the linux scsi mid-layer via the scsi_register()
- *	API call.
+ *	Returns: None.
  */
-int
-mptscsih_detect(Scsi_Host_Template *tpnt)
+static void
+search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd)
 {
-	struct Scsi_Host	*sh = NULL;
-	MPT_SCSI_HOST		*hd = NULL;
-	MPT_ADAPTER		*this;
-	unsigned long		 flags;
-	int			 sz;
-	u8			*mem;
+	MPT_FRAME_HDR *mf = NULL;
+	unsigned long flags;
+	int count = 0;
 
-	if (! BeenHereDoneThat++) {
-		show_mptmod_ver(my_NAME, my_VERSION);
+	dprintk((KERN_INFO MYNAM ": search_taskQ_for_cmd(sc=%p) called\n", sc));
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (! Q_IS_EMPTY(&hd->taskQ)) {
+		mf = hd->taskQ.head;
+		do {
+			count++;
+			if (mf->u.frame.linkage.argp1 == sc) {
+				Q_DEL_ITEM(&mf->u.frame.linkage);
+				hd->taskQcnt--;
+				atomic_dec(&mpt_taskQdepth);
+				dprintk((KERN_INFO MYNAM
+					": Cmd %p found! Deleting.\n", sc));
 
-		if ((ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER)) <= 0) {
-			printk(KERN_ERR MYNAM ": Failed to register callback1 with MPT base driver\n");
-			return mpt_scsi_hosts;
-		}
-		if ((ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER)) <= 0) {
-			printk(KERN_ERR MYNAM ": Failed to register callback2 with MPT base driver\n");
-			return mpt_scsi_hosts;
-		}
+				/* Don't save mf into nextmf because
+				 * exit after command has been deleted.
+				 */
 
-#ifndef MPT_SCSI_USE_NEW_EH
-		Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
-		spin_lock_init(&mpt_scsih_taskQ_lock);
+				/* Place the MF back on the FreeQ */
+				Q_ADD_TAIL(&hd->ioc->FreeQ,
+					&mf->u.frame.linkage,
+					MPT_FRAME_HDR);
+#ifdef MFCNT
+				hd->ioc->mfcnt--;
 #endif
+				break;
+			}
+		} while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
+	}
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-		if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
-			dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
-		} else {
-			/* FIXME! */
-		}
+	return;
+}
 
-		if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {
-			dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
-		} else {
-			/* FIXME! */
-		}
-	}
+#endif		/* } MPT_SCSI_USE_NEW_EH */
 
-	dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
 
-	this = mpt_adapter_find_first();
-	while (this != NULL) {
-		/* FIXME!  Multi-port (aka FC929) support...
-		 * for (i = 0; i < this->facts.NumberOfPorts; i++)
-		 */
+/*
+ * Flush all commands on the doneQ.
+ * Lock Q when deleting/adding members
+ * Lock io_request_lock for OS callback.
+ */
+static void
+flush_doneQ(MPT_SCSI_HOST *hd)
+{
+	MPT_DONE_Q	*buffer;
+	Scsi_Cmnd	*SCpnt;
+	unsigned long	 flags;
 
-		/* 20010215 -sralston
-		 *  Added sanity check on SCSI Initiator-mode enabled
-		 *  for this MPT adapter.
-		 */
-		if (!(this->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
-			printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n",
-					this->name);
-			this = mpt_adapter_find_next(this);
-			continue;
+	/* Flush the doneQ.
+	 */
+	dprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
+	while (1) {
+		spin_lock_irqsave(&hd->freedoneQlock, flags);
+		if (Q_IS_EMPTY(&hd->doneQ)) {
+			spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			break;
 		}
 
-		/* 20010202 -sralston
-		 *  Added sanity check on readiness of the MPT adapter.
+		buffer = hd->doneQ.head;
+		/* Delete from Q
 		 */
-		if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
-			printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n",
-					this->name);
-			this = mpt_adapter_find_next(this);
-			continue;
-		}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-		tpnt->proc_dir = &proc_mpt_scsihost;
-#endif
-		sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
-		if (sh != NULL) {
-			save_flags(flags);
-			cli();
-			sh->io_port = 0;
-			sh->n_io_port = 0;
-			sh->irq = 0;
-
-			/* Yikes!  This is important!
-			 * Otherwise, by default, linux only scans target IDs 0-7!
-			 *
-			 * BUG FIX!  20010618 -sralston & pdelaney
-			 * FC919 testing was encountering "duplicate" FC devices,
-			 * as it turns out because the 919 was returning 512
-			 * for PortFacts.MaxDevices, causing a wraparound effect
-			 * in SCSI IO requests.  So instead of using:
-			 *     sh->max_id = this->pfacts[0].MaxDevices - 1
-			 * we'll use a definitive max here.
-			 */
-			sh->max_id = MPT_MAX_FC_DEVICES;
-
-			sh->this_id = this->pfacts[0].PortSCSIID;
-
-			restore_flags(flags);
-
-			hd = (MPT_SCSI_HOST *) sh->hostdata;
-			hd->ioc = this;
-			hd->port = 0;		/* FIXME! */
-
-			/* SCSI needs Scsi_Cmnd lookup table!
-			 * (with size equal to req_depth*PtrSz!)
-			 */
-			sz = hd->ioc->req_depth * sizeof(void *);
-			mem = kmalloc(sz, GFP_KERNEL);
-			if (mem == NULL)
-				return mpt_scsi_hosts;
-
-			memset(mem, 0, sz);
-			hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-			dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n",
-				 hd->ScsiLookup, sz));
-
-			/* SCSI also needs SG buckets/hunk management!
-			 * (with size equal to N * req_sz * req_depth!)
-			 * (where N is number of SG buckets per hunk)
-			 */
-			sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
-			mem = pci_alloc_consistent(hd->ioc->pcidev, sz,
-						   &hd->SgHunksDMA);
-			if (mem == NULL)
-				return mpt_scsi_hosts;
+		Q_DEL_ITEM(buffer);
 
-			memset(mem, 0, sz);
-			hd->SgHunks = (u8*)mem;
-
-			dprintk((KERN_INFO MYNAM ": SgHunks    @ %p(%08x), sz=%d\n",
-				 hd->SgHunks, hd->SgHunksDMA, sz));
+		/* Set the Scsi_Cmnd pointer
+		 */
+		SCpnt = (Scsi_Cmnd *) buffer->argp;
+		buffer->argp = NULL;
 
-			hd->qtag_tick = jiffies;
+		/* Add to the freeQ
+		 */
+		Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+		spin_unlock_irqrestore(&hd->freedoneQlock, flags);
 
-			this->sh = sh;
-			mpt_scsi_hosts++;
-		}
-		this = mpt_adapter_find_next(this);
+		/* Do the OS callback.
+		 */
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 	}
 
-	return mpt_scsi_hosts;
+	return;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-    static char *info_kbuf = NULL;
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_release - Unregister SCSI host from linux scsi mid-layer
- *	@host: Pointer to Scsi_Host structure
+/*
+ * Search the doneQ for a specific command. If found, delete from Q.
+ * Calling function will finish processing.
+ */
+static void
+search_doneQ_for_cmd(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt)
+{
+	unsigned long	 flags;
+	MPT_DONE_Q	*buffer;
+
+	spin_lock_irqsave(&hd->freedoneQlock, flags);
+	if (!Q_IS_EMPTY(&hd->doneQ)) {
+		buffer = hd->doneQ.head;
+		do {
+			Scsi_Cmnd *sc = (Scsi_Cmnd *) buffer->argp;
+			if (SCpnt == sc) {
+				Q_DEL_ITEM(buffer);
+				SCpnt->result = sc->result;
+
+				/* Set the Scsi_Cmnd pointer
+				 */
+				buffer->argp = NULL;
+
+				/* Add to the freeQ
+				 */
+				Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+				break;
+			}
+		} while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ);
+	}
+	spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+	return;
+}
+
+/*
+ *	mptscsih_flush_running_cmds - For each command found, search
+ *		Scsi_Host instance taskQ and reply to OS.
+ *		Called only if recovering from a FW reload.
+ *	@hd: Pointer to a SCSI HOST structure
  *
- *	(linux Scsi_Host_Template.release routine)
- *	This routine releases all resources associated with the SCSI host
- *	adapter.
+ *	Returns: None.
  *
- *	Returns 0 for success.
+ *	Must be called while new I/Os are being queued.
  */
-int
-mptscsih_release(struct Scsi_Host *host)
+static void
+mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 {
-	MPT_SCSI_HOST	*hd;
-#ifndef MPT_SCSI_USE_NEW_EH
+	Scsi_Cmnd	*SCpnt = NULL;
+	MPT_FRAME_HDR	*mf = NULL;
+	int		 ii;
+	int		 max = hd->ioc->req_depth;
 	unsigned long	 flags;
 
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	if (mpt_scsih_taskQ_bh_active) {
-		int count = 10 * HZ;
+	dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
+	for (ii= 0; ii < max; ii++) {
+		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
 
-		dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+			/* Command found.
+			 */
+
+#ifndef MPT_SCSI_USE_NEW_EH
+			/* Search taskQ, if found, delete.
+			 */
+			search_taskQ_for_cmd(SCpnt, hd);
+#endif
+
+			/* Search pendingQ, if found, 
+			 * delete from Q. If found, do not decrement
+			 * queue_depth, command never posted.
+			 */
+			if (mptscsih_search_pendingQ(hd, ii) == NULL)
+				atomic_dec(&queue_depth);
 
-		/* Zap the taskQ! */
-		Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
-		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+			/* Null ScsiLookup index
+			 */
+			hd->ScsiLookup[ii] = NULL;
 
-		while(mpt_scsih_taskQ_bh_active && --count) {
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(1);
+			mf = MPT_INDEX_2_MFPTR(hd->ioc, ii);
+			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
+					mf, SCpnt));
+
+			/* Set status
+			 * Do OS callback
+			 * Free chain buffers
+			 * Free message frame
+			 */
+			SCpnt->result = DID_RESET << 16;
+			SCpnt->host_scribble = NULL;
+			spin_lock_irqsave(&io_request_lock, flags);
+			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
+			spin_unlock_irqrestore(&io_request_lock, flags);
+
+			/* Free Chain buffers */
+			mptscsih_freeChainBuffers(hd, ii);
+
+			/* Free Message frames */
+			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		}
-		if (!count)
-			printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n");
 	}
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-#endif
+	return;
+}
 
-	hd = (MPT_SCSI_HOST *) host->hostdata;
-	if (hd != NULL) {
-		int sz1, sz2;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_initChainBuffers - Allocate memory for and initialize
+ *	chain buffers, chain buffer control arrays and spinlock.
+ *	@hd: Pointer to MPT_SCSI_HOST structure
+ *	@init: If set, initialize the spin lock.
+ */
+static int
+mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init)
+{
+	MPT_FRAME_HDR	*chain;
+	u8		*mem;
+	unsigned long	flags;
+	int		sz, ii, numChain;
 
-		sz1 = sz2 = 0;
-		if (hd->ScsiLookup != NULL) {
-			sz1 = hd->ioc->req_depth * sizeof(void *);
-			kfree(hd->ScsiLookup);
-			hd->ScsiLookup = NULL;
-		}
 
-		if (hd->SgHunks != NULL) {
+        /* Chain buffer allocations
+	 * Allocate and initialize tracker structures
+	 */
+	if (hd->ioc->req_sz <= 64)
+		numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth;
+	else if (hd->ioc->req_sz <= 96)
+		numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth;
+	else
+		numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth;
 
-			sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
-			pci_free_consistent(hd->ioc->pcidev, sz2,
-					    hd->SgHunks, hd->SgHunksDMA);
-			hd->SgHunks = NULL;
-		}
-		dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2));
+	sz = numChain * sizeof(int);
+
+	if (hd->ReqToChain == NULL) {
+		mem = kmalloc(sz, GFP_KERNEL);
+		if (mem == NULL)
+			return -1;
+
+		hd->ReqToChain = (int *) mem;
+	} else {
+		mem = (u8 *) hd->ReqToChain;
 	}
+	memset(mem, 0xFF, sz);
 
-	if (mpt_scsi_hosts) {
-		if (--mpt_scsi_hosts == 0) {
-#if 0
-			mptscsih_flush_pending();
-#endif
-			mpt_reset_deregister(ScsiDoneCtx);
-			dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+	if (hd->ChainToChain == NULL) {
+		mem = kmalloc(sz, GFP_KERNEL);
+		if (mem == NULL)
+			return -1;
 
-			mpt_event_deregister(ScsiDoneCtx);
-			dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+		hd->ChainToChain = (int *) mem;
+	} else {
+		mem = (u8 *) hd->ChainToChain;
+	}
+	memset(mem, 0xFF, sz);
 
-			mpt_deregister(ScsiDoneCtx);
-			mpt_deregister(ScsiTaskCtx);
+	if (hd->ChainBuffer == NULL) {
+		/* Allocate free chain buffer pool
+		 */
+		sz = numChain * hd->ioc->req_sz;
+		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
+		if (mem == NULL)
+			return -1;
 
-			if (info_kbuf != NULL)
-				kfree(info_kbuf);
-		}
+		hd->ChainBuffer = (u8*)mem;
+	} else {
+		mem = (u8 *) hd->ChainBuffer;
+	}
+	memset(mem, 0, sz);
+
+	dprintk((KERN_INFO "  ChainBuffer    @ %p(%p), sz=%d\n",
+		 hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz));
+
+	/* Initialize the free chain Q.
+	 */
+	if (init) {
+		spin_lock_init(&hd->FreeChainQlock);
 	}
 
+	spin_lock_irqsave (&hd->FreeChainQlock, flags);
+	Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR);
+
+	/* Post the chain buffers to the FreeChainQ.
+	 */
+	mem = (u8 *)hd->ChainBuffer;
+	for (ii=0; ii < numChain; ii++) {
+		chain = (MPT_FRAME_HDR *) mem;
+		Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
+		mem += hd->ioc->req_sz;
+	}
+	spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
+
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_info - Return information about MPT adapter
- *	@SChost: Pointer to Scsi_Host structure
- *
- *	(linux Scsi_Host_Template.info routine)
+/*
+ *  Hack! It might be nice to report if a device is returning QUEUE_FULL
+ *  but maybe not each and every time...
+ */
+static long last_queue_full = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_report_queue_full - Report QUEUE_FULL status returned
+ *	from a SCSI target device.
+ *	@sc: Pointer to Scsi_Cmnd structure
+ *	@pScsiReply: Pointer to SCSIIOReply_t
+ *	@pScsiReq: Pointer to original SCSI request
  *
- *	Returns pointer to buffer where information was written.
+ *	This routine periodically reports QUEUE_FULL status returned from a
+ *	SCSI target device.  It reports this to the console via kernel
+ *	printk() API call, not more than once every 10 seconds.
  */
-const char *
-mptscsih_info(struct Scsi_Host *SChost)
+static void
+mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
 {
-	MPT_SCSI_HOST *h;
-	int size = 0;
-
-	if (info_kbuf == NULL)
-		if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
-			return info_kbuf;
+	long time = jiffies;
 
-	h = (MPT_SCSI_HOST *)SChost->hostdata;
-	info_kbuf[0] = '\0';
-	mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
-	info_kbuf[size-1] = '\0';
+	if (time - last_queue_full > 10 * HZ) {
+		char *ioc_str = "ioc?";
 
-	return info_kbuf;
+		if (sc->host && sc->host->hostdata)
+			ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name;
+		printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+				ioc_str, 0, sc->target, sc->lun);
+		last_queue_full = time;
+	}
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-	static int max_qd = 1;
-#ifdef MPT_DEBUG
-	static int max_sges = 0;
-	static int max_xfer = 0;
-#endif
-#if 0
-	static int max_num_sges = 0;
-	static int max_sgent_len = 0;
-#endif
-#if 0
-static int index_log[128];
-static int index_ent = 0;
-static __inline__ void ADD_INDEX_LOG(int req_ent)
-{
-	int i = index_ent++;
+static int BeenHereDoneThat = 0;
 
-	index_log[i & (128 - 1)] = req_ent;
-}
-#else
-#define ADD_INDEX_LOG(req_ent)	do { } while(0)
-#endif
+/*  SCSI host fops start here...  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
- *	@SCpnt: Pointer to Scsi_Cmnd structure
- *	@done: Pointer SCSI mid-layer IO completion function
+ *	mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
+ *	linux scsi mid-layer.
+ *	@tpnt: Pointer to Scsi_Host_Template structure
  *
- *	(linux Scsi_Host_Template.queuecommand routine)
- *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
- *	from a linux Scsi_Cmnd request and send it to the IOC.
+ *	(linux Scsi_Host_Template.detect routine)
  *
- *	Returns 0. (rtn value discarded by linux scsi mid-layer)
+ *	Returns number of SCSI host adapters that were successfully
+ *	registered with the linux scsi mid-layer via the scsi_register()
+ *	API call.
  */
 int
-mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+mptscsih_detect(Scsi_Host_Template *tpnt)
 {
-	struct Scsi_Host	*host;
-	MPT_SCSI_HOST		*hd;
-	MPT_FRAME_HDR		*mf;
-	SCSIIORequest_t		*pScsiReq;
-	int	 datadir;
-	u32	 len;
-	u32	 sgdir;
-	u32	 scsictl;
-	u32	 scsidir;
-	u32	 qtag;
-	u32	*mptr;
-	int	 sge_spill1;
-	int	 frm_sz;
-	int	 sges_left;
-	u32	 chain_offset;
-	int	 my_idx;
-	int	 i;
+	struct Scsi_Host	*sh = NULL;
+	MPT_SCSI_HOST		*hd = NULL;
+	MPT_ADAPTER		*this;
+	MPT_DONE_Q		*freedoneQ;
+	unsigned long		 flags;
+	int			 sz, ii;
+	int			 numSGE = 0;
+	int			 scale;
+	u8			*mem;
 
-	dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n",
-		    SCpnt, done));
+	if (! BeenHereDoneThat++) {
+		show_mptmod_ver(my_NAME, my_VERSION);
 
-	host = SCpnt->host;
-	hd = (MPT_SCSI_HOST *) host->hostdata;
-	
-#if 0
-	if (host->host_busy >= 60) {
-		MPT_ADAPTER *ioc = hd->ioc;
-		u16 pci_command, pci_status;
-
-		/* The IOC is probably hung, investigate status. */
-		printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n",
-		       readl(&ioc->chip.fc9xx->DoorbellValue),
-		       readl(&ioc->chip.fc9xx->IntStatus),
-		       readl(&ioc->chip.fc9xx->ReplyFifo));
-		pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command);
-		pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status);
-		printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status);
-		{
-			/* DUMP req index logger. */
-			int begin, end;
+		ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
+		ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
+		ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER);
 
-			begin = (index_ent - 65) & (128 - 1);
-			end = index_ent & (128 - 1);
-			printk("MPI: REQ_INDEX_HIST[");
-			while (begin != end) {
-				printk("(%04x)", index_log[begin]);
-				begin = (begin + 1) & (128 - 1);
-			}
-			printk("\n");
-		}
-		sti();
-		while(1)
-			barrier();
-	}
+#ifndef MPT_SCSI_USE_NEW_EH
+		spin_lock_init(&mytaskQ_lock);
 #endif
 
-	SCpnt->scsi_done = done;
+		if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
+			dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
+		} else {
+			/* FIXME! */
+		}
 
-	/* 20000617 -sralston
-	 *  GRRRRR...  Shouldn't have to do this but...
-	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
-	 *  If yes, return cached SenseData.
-	 */
-#ifdef MPT_SCSI_CACHE_AUTOSENSE
-	{
-		MPT_SCSI_DEV	*mpt_sdev;
+		if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {
+			dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+		} else {
+			/* FIXME! */
+		}
+	}
+	dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
 
-		mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata;
-		if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) {
-			u8 *dest = NULL;
+#ifdef MODULE
+	/* Evaluate the command line arguments, if any */
+	if (mptscsih)
+		mptscsih_setup(mptscsih);
+#endif
+#ifndef MPT_SCSI_USE_NEW_EH
+	atomic_set(&mpt_taskQdepth, 0);
+#endif
 
-			if (!SCpnt->use_sg)
-				dest = SCpnt->request_buffer;
-			else {
-				struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-				if (sg)
-					dest = (u8 *) (unsigned long)sg_dma_address(sg);
+	this = mpt_adapter_find_first();
+	while (this != NULL) {
+		int	 portnum;
+		for (portnum=0; portnum < this->facts.NumberOfPorts; portnum++) {
+
+			/* 20010215 -sralston
+			 *  Added sanity check on SCSI Initiator-mode enabled
+			 *  for this MPT adapter.
+			 */
+			if (!(this->pfacts[portnum].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
+				printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n",
+						this->name);
+				continue;
 			}
 
-			if (dest && mpt_sdev->sense_sz) {
-				memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz);
-#ifdef MPT_DEBUG
-				{
-					int  i;
-					u8  *sb;
-
-					sb = mpt_sdev->CachedSense.data;
-					if (sb && ((sb[0] & 0x70) == 0x70)) {
-						printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n");
-						printk(KERN_WARNING " ");
-						for (i = 0; i < (8 + sb[7]); i++)
-							printk("%s%02x", i == 13 ? "-" : " ", sb[i]);
-						printk("\n");
-					}
-				}
-#endif
+			/* 20010202 -sralston
+			 *  Added sanity check on readiness of the MPT adapter.
+			 */
+			if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+				printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
+						this->name);
+				continue;
 			}
-			SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
-			SCpnt->result = 0;
-/*			spin_lock(&io_request_lock);	*/
-			SCpnt->scsi_done(SCpnt);
-/*			spin_unlock(&io_request_lock);	*/
-			return 0;
-		}
-	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+			tpnt->proc_dir = &proc_mpt_scsihost;
 #endif
+			sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
+			if (sh != NULL) {
+				save_flags(flags);
+				cli();
+				sh->io_port = 0;
+				sh->n_io_port = 0;
+				sh->irq = 0;
+
+				/* Yikes!  This is important!
+				 * Otherwise, by default, linux
+				 * only scans target IDs 0-7!
+				 * pfactsN->MaxDevices unreliable
+				 * (not supported in early
+				 *	versions of the FW).
+				 * max_id = 1 + actual max id,
+				 * max_lun = 1 + actual last lun,
+				 *	see hosts.h :o(
+				 */
+				if ((int)this->chip_type > (int)FC929)
+					sh->max_id = MPT_MAX_SCSI_DEVICES;
+				else {
+					/* For FC, increase the queue depth
+					 * from MPT_SCSI_CAN_QUEUE (31)
+					 * to MPT_FC_CAN_QUEUE (63).
+					 */
+					sh->can_queue = MPT_FC_CAN_QUEUE;
+					sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+				}
+				sh->max_lun = MPT_LAST_LUN + 1;
 
-	if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
-/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
-		SCpnt->result = STS_BUSY;
-		SCpnt->scsi_done(SCpnt);
-/*		return 1;				*/
-		return 0;
-	}
-	pScsiReq = (SCSIIORequest_t *) mf;
+				sh->this_id = this->pfacts[portnum].PortSCSIID;
 
-	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+				/* OS entry to allow host drivers to force
+				 * a queue depth on a per device basis.
+				 */
+				sh->select_queue_depths = mptscsih_select_queue_depths;
 
-	ADD_INDEX_LOG(my_idx);
+				/* Verify that we won't exceed the maximum
+				 * number of chain buffers
+				 * We can optimize:  ZZ = req_sz/sizeof(MptSge_t)
+				 * For 32bit SGE's:
+				 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+				 *               + (req_sz - 64)/sizeof(MptSge_t)
+				 * A slightly different algorithm is required for
+				 * 64bit SGEs.
+				 */
+				scale = this->req_sz/sizeof(MptSge_t);
+				if (sizeof(MptSge_t) == sizeof(SGESimple32_t)) {
+					numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+						(this->req_sz - 64) / (sizeof(MptSge_t));
+				} else if (sizeof(MptSge_t) == sizeof(SGESimple64_t)) {
+					numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+						(this->req_sz - 60) / (sizeof(MptSge_t));
+				}
 
-	/* Map the data portion, if any. */
-	sges_left = SCpnt->use_sg;
-	if (sges_left) {
-		sges_left = pci_map_sg(hd->ioc->pcidev,
-				       (struct scatterlist *) SCpnt->request_buffer,
-				       sges_left,
-				       scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
-	} else if (SCpnt->request_bufflen) {
-		dma_addr_t buf_dma_addr;
+				if (numSGE < sh->sg_tablesize) {
+					/* Reset this value */
+					dprintk((MYIOC_s_INFO_FMT
+						 "Resetting sg_tablesize to %d from %d\n",
+						 this->name, numSGE, sh->sg_tablesize));
+					sh->sg_tablesize = numSGE;
+				}
 
-		buf_dma_addr = pci_map_single(hd->ioc->pcidev,
-					      SCpnt->request_buffer,
-					      SCpnt->request_bufflen,
-					      scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+				restore_flags(flags);
 
-		/* We hide it here for later unmap. */
-		SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr;
-	}
+				hd = (MPT_SCSI_HOST *) sh->hostdata;
+				hd->ioc = this;
 
-	/*
-	 *  Put together a MPT SCSI request...
-	 */
+				if ((int)this->chip_type > (int)FC929)
+					hd->is_spi = 1;
 
-	/* Assume SimpleQ, NO DATA XFER for now */
+				if (DmpService &&
+				    (this->chip_type == FC919 || this->chip_type == FC929))
+					hd->is_multipath = 1;
 
-	len = SCpnt->request_bufflen;
-	sgdir = 0x00000000;		/* SGL IN  (host<--ioc) */
-	scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+				hd->port = 0;		/* FIXME! */
 
-	/*
-	 *  The scsi layer should be handling this stuff
-	 *  (In 2.3.x it does -DaveM)
-	 */
-
-	/*  BUG FIX!  19991030 -sralston
-	 *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
-	 *    Seems we may receive a buffer (len>0) even when there
-	 *    will be no data transfer!  GRRRRR...
-	 */
-	datadir = mptscsih_io_direction(SCpnt);
-	if (datadir < 0) {
-		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
-	} else if (datadir > 0) {
-		sgdir	= 0x04000000;			/* SGL OUT  (host-->ioc) */
-		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
-	} else {
-		len = 0;
-	}
-
-	qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
-
-	/*
-	 *  Attach tags to the devices
-	 */
-	if (SCpnt->device->tagged_supported) {
-		/*
-		 *  Some drives are too stupid to handle fairness issues
-		 *  with tagged queueing. We throw in the odd ordered
-		 *  tag to stop them starving themselves.
-		 */
-		if ((jiffies - hd->qtag_tick) > (5*HZ)) {
-			qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
-			hd->qtag_tick = jiffies;
+				/* SCSI needs Scsi_Cmnd lookup table!
+				 * (with size equal to req_depth*PtrSz!)
+				 */
+				sz = hd->ioc->req_depth * sizeof(void *);
+				mem = kmalloc(sz, GFP_KERNEL);
+				if (mem == NULL)
+					goto done;
 
-#if 0
-			/* These are ALWAYS zero!
-			 * (Because this is a place for the device driver to dynamically
-			 *  assign tag numbers any way it sees fit.  That's why -DaveM)
-			 */
-			dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n",
-					SCpnt->device->current_tag));
-			dprintk((KERN_DEBUG MYNAM ": sc->tag                 = %08x\n",
-					SCpnt->tag));
-#endif
-		}
-#if 0
-		else {
-			/* Hmmm...  I always see value of 0 here,
-			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
-			 * (Because this is a place for the device driver to dynamically
-			 *  assign tag numbers any way it sees fit.  That's why -DaveM)
-			 *
-			 * if (SCpnt->tag == HEAD_OF_QUEUE_TAG)
-			 */
-			if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG)
-				qtag = MPI_SCSIIO_CONTROL_HEADOFQ;
-			else if (SCpnt->tag == ORDERED_QUEUE_TAG)
-				qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
-		}
-#endif
-	}
+				memset(mem, 0, sz);
+				hd->ScsiLookup = (struct scsi_cmnd **) mem;
 
-	scsictl = scsidir | qtag;
+				dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+					 this->name, hd->ScsiLookup, sz));
 
-	frm_sz = hd->ioc->req_sz;
+				if (mptscsih_initChainBuffers(hd, 1) < 0)
+					goto done;
 
-	/* Ack!
-	 * sge_spill1 = 9;
-	 */
-	sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8;
-	/*  spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9
-	 *  spill1: for req_sz ==  96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5
-	 */
-	dsgprintk((KERN_INFO MYNAM ": SG: %x     spill1 = %d\n",
-		   my_idx, sge_spill1));
-
-#ifdef MPT_DEBUG
-	if (sges_left > max_sges) {
-		max_sges = sges_left;
-		dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges));
-	}
-#endif
-#if 0
-	if (sges_left > max_num_sges) {
-		max_num_sges = sges_left;
-		printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges);
-	}
-#endif
+				/* Allocate memory for free and doneQ's
+				 */
+				sz = sh->can_queue * sizeof(MPT_DONE_Q);
+				mem = kmalloc(sz, GFP_KERNEL);
+				if (mem == NULL)
+					goto done;
 
-	dsgprintk((KERN_INFO MYNAM ": SG: %x     sges_left = %d (initially)\n",
-		   my_idx, sges_left));
+				memset(mem, 0xFF, sz);
+				hd->memQ = mem;
 
-	chain_offset = 0;
-	if (sges_left > (sge_spill1+1)) {
-#if 0
-		chain_offset = 0x1E;
-#endif
-		chain_offset = (frm_sz - 8) / 4;
-	}
+				/* Initialize the free, done and pending Qs.
+				 */
+				Q_INIT(&hd->freeQ, MPT_DONE_Q);
+				Q_INIT(&hd->doneQ, MPT_DONE_Q);
+				Q_INIT(&hd->pendingQ, MPT_DONE_Q);
+				spin_lock_init(&hd->freedoneQlock);
+
+				mem = hd->memQ;
+				for (ii=0; ii < sh->can_queue; ii++) {
+					freedoneQ = (MPT_DONE_Q *) mem;
+					Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
+					mem += sizeof(MPT_DONE_Q);
+				}
 
-	pScsiReq->TargetID = SCpnt->target;
-	pScsiReq->Bus = hd->port;
-	pScsiReq->ChainOffset = chain_offset;
-	pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
-	pScsiReq->CDBLength = SCpnt->cmd_len;
+				/* Initialize this Scsi_Host
+				 * internal task Q.
+				 */
+				Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
+				hd->taskQcnt = 0;
 
-/* We have 256 bytes alloc'd per IO; let's use it. */
-/*	pScsiReq->SenseBufferLength = SNS_LEN(SCpnt);	*/
-	pScsiReq->SenseBufferLength = 255;
+				/* Allocate memory for the device structures.
+				 * A non-Null pointer at an offset
+				 * indicates a device exists.
+				 * max_id = 1 + maximum id (hosts.h)
+				 */
+				sz = sh->max_id * sizeof(void *);
+				mem = kmalloc(sz, GFP_KERNEL);
+				if (mem == NULL)
+					goto done;
 
-	pScsiReq->Reserved = 0;
-	pScsiReq->MsgFlags = 0;
-	pScsiReq->LUN[0] = 0;
-	pScsiReq->LUN[1] = SCpnt->lun;
-	pScsiReq->LUN[2] = 0;
-	pScsiReq->LUN[3] = 0;
-	pScsiReq->LUN[4] = 0;
-	pScsiReq->LUN[5] = 0;
-	pScsiReq->LUN[6] = 0;
-	pScsiReq->LUN[7] = 0;
-	pScsiReq->Control = cpu_to_le32(scsictl);
+				memset(mem, 0, sz);
+				hd->Targets = (VirtDevice **) mem;
 
-	/*
-	 *  Write SCSI CDB into the message
-	 */
-	for (i = 0; i < 12; i++)
-		pScsiReq->CDB[i] = SCpnt->cmnd[i];
-	for (i = 12; i < 16; i++)
-		pScsiReq->CDB[i] = 0;
+				dprintk((KERN_INFO "  Targets @ %p, sz=%d\n", hd->Targets, sz));
 
-	/* DataLength */
-	pScsiReq->DataLength = cpu_to_le32(len);
 
-	/* SenseBuffer low address */
-	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256));
+				/* Clear the TM flags
+				 */
+				hd->tmPending = 0;
+				hd->resetPending = 0;
+				hd->abortSCpnt = NULL;
+				hd->tmPtr = NULL;
+				hd->numTMrequests = 0;
+
+				/* Clear the pointer used to store
+				 * single-threaded commands, i.e., those
+				 * issued during a bus scan, dv and
+				 * configuration pages.
+				 */
+				hd->cmdPtr = NULL;
 
-	mptr = (u32 *) &pScsiReq->SGL;
+				/* Attach the SCSI Host to the IOC structure
+				 */
+				this->sh = sh;
 
-	/*
-	 *  Now fill in the SGList...
-	 *  NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's
-	 *  in the remaining request frame.  We -could- do unlimited chains
-	 *  but each chain buffer can only be req_sz bytes in size, and
-	 *  we lose one SGE whenever we chain.
-	 *  For 128 req_sz, we can hold up to 16 SGE's per chain buffer.
-	 *  For practical reasons, limit ourselves to 1 overflow chain buffer;
-	 *  giving us 9 + 16 == 25 SGE's max.
-	 *  At 4 Kb per SGE, that yields 100 Kb max transfer.
-	 *
-	 *  (This code needs to be completely changed when/if 64-bit DMA
-	 *   addressing is used, since we will be able to fit much less than
-	 *   10 embedded SG entries. -DaveM)
-	 */
-	if (sges_left) {
-		struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-		u32  v1, v2;
-		int  sge_spill2;
-		int  sge_cur_spill;
-		int  sgCnt;
-		u8  *pSgBucket;
-		int  chain_sz;
-
-		len = 0;
-
-		/*	sge_spill2 = 15;
-		 *  spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15
-		 *  spill2: for req_sz ==  96 ( 96/8==12 SGEs max, first time!), --> use 11
-		 */
-		sge_spill2 = frm_sz / 8 - 1;
-		dsgprintk((KERN_INFO MYNAM ": SG: %x     spill2 = %d\n",
-			   my_idx, sge_spill2));
-
-		pSgBucket = NULL;
-		sgCnt = 0;
-		sge_cur_spill = sge_spill1;
-		while (sges_left) {
-#if 0
-			if (sg_dma_len(sg) > max_sgent_len) {
-				max_sgent_len = sg_dma_len(sg);
-				printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len);
-			}
-#endif
-			/* Write one simple SGE */
-			v1 = sgdir | 0x10000000 | sg_dma_len(sg);
-			len += sg_dma_len(sg);
-			v2 = sg_dma_address(sg);
-			dsgprintk((KERN_INFO MYNAM ": SG: %x     Writing SGE @%p: %08x %08x, sges_left=%d\n",
-				   my_idx, mptr, v1, v2, sges_left));
-			*mptr++ = cpu_to_le32(v1);
-			*mptr++ = cpu_to_le32(v2);
-			sg++;
-			sgCnt++;
-
-			if (--sges_left == 0) {
-				/* re-write 1st word of previous SGE with SIMPLE,
-				 * LE, EOB, and EOL bits!
-				 */
-				v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1);
-				dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n",
-					   my_idx, mptr-2, v1));
-				*(mptr - 2) = cpu_to_le32(v1);
-			} else {
-				if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) {
-					dsgprintk((KERN_INFO MYNAM ": SG: %x     SG spill at modulo 0!\n",
-						   my_idx));
-
-					/* Fixup previous SGE with LE bit! */
-					v1 = sgdir | 0x90000000 | sg_dma_len(sg-1);
-					dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n",
-						   my_idx, mptr-2, v1));
-					*(mptr - 2) = cpu_to_le32(v1);
-
-					chain_offset = 0;
-					/* Going to need another chain? */
-					if (sges_left > (sge_spill2+1)) {
-#if 0
-						chain_offset = 0x1E;
+				/* Initialize this SCSI Hosts' timers
+				 * To use, set the timer expires field
+				 * and add_timer
+				 */
+				init_timer(&hd->timer);
+				hd->timer.data = (unsigned long) hd;
+				hd->timer.function = mptscsih_timer_expired;
+
+				init_timer(&hd->TMtimer);
+				hd->TMtimer.data = (unsigned long) hd;
+				hd->TMtimer.function = mptscsih_taskmgmt_timeout;
+				hd->qtag_tick = jiffies;
+
+				/* Moved Earlier Pam D */
+				/* this->sh = sh;	*/
+
+				if (hd->is_spi) {
+					/* Update with the driver setup
+					 * values.
+					 */
+					if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)
+						hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;
+					if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)
+						hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac;
+
+					if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
+						hd->ioc->spi_data.maxSyncOffset = 0;
+
+					hd->negoNvram = 0;
+#ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+					hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 #endif
-						chain_offset = (frm_sz - 8) / 4;
-						chain_sz = frm_sz;
-					} else {
-						chain_sz = sges_left * 8;
-					}
-
-					/* write chain SGE at mptr. */
-					v1 = 0x30000000 | chain_offset<<16 | chain_sz;
-					if (pSgBucket == NULL) {
-						pSgBucket = hd->SgHunks
-							+ (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK);
-					} else {
-						pSgBucket += frm_sz;
-					}
-					v2 = (hd->SgHunksDMA +
-					      ((u8 *)pSgBucket - (u8 *)hd->SgHunks));
-					dsgprintk((KERN_INFO MYNAM ": SG: %x     Writing SGE @%p: %08x %08x (CHAIN!)\n",
-						   my_idx, mptr, v1, v2));
-					*(mptr++) = cpu_to_le32(v1);
-					*(mptr) = cpu_to_le32(v2);
+					if (driver_setup.dv == 0)
+						hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 
-					mptr = (u32 *) pSgBucket;
-					sgCnt = 0;
-					sge_cur_spill = sge_spill2;
-				}
-			}
-		}
-	} else {
-		dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n",
-			   SCpnt, SCpnt->request_bufflen));
+					hd->ioc->spi_data.forceDv = 0;
+					for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+						hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
 
-		if (len > 0) {
-			dma_addr_t buf_dma_addr;
 
-			buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr;
-			*(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen);
-			*(mptr++) = cpu_to_le32(buf_dma_addr);
-		}
-	}
+					ddvprintk((MYIOC_s_INFO_FMT
+						"dv %x width %x factor %x \n",
+						hd->ioc->name, driver_setup.dv,
+						driver_setup.max_width,
+						driver_setup.min_sync_fac));
 
-#ifdef MPT_DEBUG
-	/* if (SCpnt->request_bufflen > max_xfer) */
-	if (len > max_xfer) {
-		max_xfer = len;
-		dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer));
-	}
-#endif
+				}
 
-	hd->ScsiLookup[my_idx] = SCpnt;
+				mpt_scsi_hosts++;
+			}
 
-	/* Main banana... */
-	mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+		}	/* for each adapter port */
 
-	atomic_inc(&queue_depth);
-	if (atomic_read(&queue_depth) > max_qd) {
-		max_qd = atomic_read(&queue_depth);
-		dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
+		this = mpt_adapter_find_next(this);
 	}
 
-	dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt));
+done:
+	if (mpt_scsi_hosts > 0)
+		register_reboot_notifier(&mptscsih_notifier);
 
-	return 0;
+	return mpt_scsi_hosts;
 }
 
-#ifdef MPT_SCSI_USE_NEW_EH		/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
-    mptscsih_abort
-    Returns: 0=SUCCESS, else FAILED
-*/
+    static char *info_kbuf = NULL;
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
- *	@SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *	mptscsih_release - Unregister SCSI host from linux scsi mid-layer
+ *	@host: Pointer to Scsi_Host structure
  *
- *	(linux Scsi_Host_Template.eh_abort_handler routine)
+ *	(linux Scsi_Host_Template.release routine)
+ *	This routine releases all resources associated with the SCSI host
+ *	adapter.
  *
- *	Returns SUCCESS or FAILED.  
+ *	Returns 0 for success.
  */
 int
-mptscsih_abort(Scsi_Cmnd * SCpnt)
+mptscsih_release(struct Scsi_Host *host)
 {
-	MPT_FRAME_HDR	*mf;
-	SCSITaskMgmt_t	*pScsiTm;
 	MPT_SCSI_HOST	*hd;
-	u32		*msg;
-	u32		 ctx2abort;
-	int		 i;
+	int 		 count;
 	unsigned long	 flags;
 
-	printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+	hd = (MPT_SCSI_HOST *) host->hostdata;
 
-	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+#ifndef MPT_SCSI_USE_NEW_EH
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+	spin_lock_irqsave(&dvtaskQ_lock, flags);
+	dvtaskQ_release = 1;
+	spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+#endif
 
-	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
-/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
-		SCpnt->result = STS_BUSY;
-		SCpnt->scsi_done(SCpnt);
-		return FAILED;
+	spin_lock_irqsave(&mytaskQ_lock, flags);
+	if (mytaskQ_bh_active) {
+		count = 10 * HZ;
+
+		spin_unlock_irqrestore(&mytaskQ_lock, flags);
+		dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+		clean_taskQ(hd);
+
+		while(mytaskQ_bh_active && --count) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+		if (!count)
+			printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");
 	}
+	spin_unlock_irqrestore(&mytaskQ_lock, flags);
+#endif
 
-	pScsiTm = (SCSITaskMgmt_t *) mf;
-	msg = (u32 *) mf;
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+	/* Check DV thread active */
+	count = 10 * HZ;
+	spin_lock_irqsave(&dvtaskQ_lock, flags);
+	while(dvtaskQ_active && --count) {
+		spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock_irqsave(&dvtaskQ_lock, flags);
+	}
+	spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+	if (!count)
+		printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+	else
+		printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
+#endif
+#endif
 
-	pScsiTm->TargetID = SCpnt->target;
-	pScsiTm->Bus = hd->port;
-	pScsiTm->ChainOffset = 0;
-	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+	unregister_reboot_notifier(&mptscsih_notifier);
 
-	pScsiTm->Reserved = 0;
-	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
-	pScsiTm->Reserved1 = 0;
-	pScsiTm->MsgFlags = 0;
+	if (hd != NULL) {
+		int sz1, sz2, sz3, sztarget=0;
+		int szchain = 0;
+		int szQ = 0;
+		int scale;
 
-	for (i = 0; i < 8; i++) {
-		u8 val = 0;
-		if (i == 1)
-			val = SCpnt->lun;
-		pScsiTm->LUN[i] = val;
-	}
+		/* Synchronize disk caches
+		 */
+		(void) mptscsih_synchronize_cache(hd, 0);
 
-	for (i = 0; i < 7; i++)
-		pScsiTm->Reserved2[i] = 0;
+		sz1 = sz2 = sz3 = 0;
 
-	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
-	 * (the IO to be ABORT'd)
-	 *
-	 * NOTE: Since we do not byteswap MsgContext, we do not
-	 *	 swap it here either.  It is an opaque cookie to
-	 *	 the controller, so it does not matter. -DaveM
-	 */
-	ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
-	if (ctx2abort == -1) {
-		printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#2) for SCpnt=%p\n", SCpnt);
-		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-	} else {
-		dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
-		pScsiTm->TaskMsgContext = ctx2abort;
+		if (hd->ioc->req_sz <= 64)
+			scale = MPT_SG_REQ_64_SCALE;
+		else if (hd->ioc->req_sz <= 96)
+			scale = MPT_SG_REQ_96_SCALE;
+		else
+			scale = MPT_SG_REQ_128_SCALE;
 
+		if (hd->ScsiLookup != NULL) {
+			sz1 = hd->ioc->req_depth * sizeof(void *);
+			kfree(hd->ScsiLookup);
+			hd->ScsiLookup = NULL;
+		}
 
-		/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-			mpt_put_msg_frame(hd->ioc->id, mf);
-		*/
-		if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-					sizeof(SCSITaskMgmt_t), msg))
-		    != 0) {
-			printk(KERN_WARNING MYNAM
-					": WARNING[2] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
-					i, mf, SCpnt);
-			SCpnt->result = DID_SOFT_ERROR << 16;
-			spin_lock_irqsave(&io_request_lock, flags);
-			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-			mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+		if (hd->ReqToChain != NULL) {
+			szchain += scale * hd->ioc->req_depth * sizeof(int);
+			kfree(hd->ReqToChain);
+			hd->ReqToChain = NULL;
 		}
-	}
 
-	//return SUCCESS;
-	return FAILED;
-}
+		if (hd->ChainToChain != NULL) {
+			szchain += scale * hd->ioc->req_depth * sizeof(int);
+			kfree(hd->ChainToChain);
+			hd->ChainToChain = NULL;
+		}
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
- *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
- *
- *	(linux Scsi_Host_Template.eh_dev_reset_handler routine)
- *
- *	Returns SUCCESS or FAILED.
- */
-int
-mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
-{
-	MPT_FRAME_HDR	*mf;
-	SCSITaskMgmt_t	*pScsiTm;
-	MPT_SCSI_HOST	*hd;
-	u32		*msg;
-	int		 i;
-	unsigned long	 flags;
+		if (hd->ChainBuffer != NULL) {
+			sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
+			szchain += sz2;
 
-	printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+			pci_free_consistent(hd->ioc->pcidev, sz2,
+				    hd->ChainBuffer, hd->ChainBufferDMA);
+			hd->ChainBuffer = NULL;
+		}
 
-	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+		if (hd->memQ != NULL) {
+			szQ = host->can_queue * sizeof(MPT_DONE_Q);
+			kfree(hd->memQ);
+			hd->memQ = NULL;
+		}
 
-	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
-/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
-		SCpnt->result = STS_BUSY;
-		SCpnt->scsi_done(SCpnt);
-		return FAILED;
-	}
+		if (hd->Targets != NULL) {
+			int max, ii;
 
-	pScsiTm = (SCSITaskMgmt_t *) mf;
-	msg = (u32*)mf;
+			/*
+			 * Free any target structures that were allocated.
+			 */
+			if (hd->is_spi) {
+				max = MPT_MAX_SCSI_DEVICES;
+			} else {
+				max = MPT_MAX_FC_DEVICES;
+			}
+			for (ii=0; ii < max; ii++) {
+				if (hd->Targets[ii]) {
+					kfree(hd->Targets[ii]);
+					hd->Targets[ii] = NULL;
+					sztarget += sizeof(VirtDevice);
+				}
+			}
 
-	pScsiTm->TargetID = SCpnt->target;
-	pScsiTm->Bus = hd->port;
-	pScsiTm->ChainOffset = 0;
-	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+			/*
+			 * Free pointer array.
+			 */
+			sz3 = max * sizeof(void *);
+			kfree(hd->Targets);
+			hd->Targets = NULL;
+		}
 
-	pScsiTm->Reserved = 0;
-	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-	pScsiTm->Reserved1 = 0;
-	pScsiTm->MsgFlags = 0;
+		dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
+				hd->ioc->name, sz1, szchain, sz3, sztarget));
+		dprintk(("Free'd done and free Q (%d) memory\n", szQ));
+	}
+	/* NULL the Scsi_Host pointer
+	 */
+	hd->ioc->sh = NULL;
+	scsi_unregister(host);
+
+	if (mpt_scsi_hosts) {
+		if (--mpt_scsi_hosts == 0) {
+			mpt_reset_deregister(ScsiDoneCtx);
+			dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
 
-	/* _TARGET_RESET goes to LUN 0 always! */
-	for (i = 0; i < 8; i++)
-		pScsiTm->LUN[i] = 0;
-
-	/* Control: No data direction, set task mgmt bit? */
-	for (i = 0; i < 7; i++)
-		pScsiTm->Reserved2[i] = 0;
+			mpt_event_deregister(ScsiDoneCtx);
+			dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
 
-	pScsiTm->TaskMsgContext = cpu_to_le32(0);
+			mpt_deregister(ScsiScanDvCtx);
+			mpt_deregister(ScsiTaskCtx);
+			mpt_deregister(ScsiDoneCtx);
 
-/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-	mpt_put_msg_frame(hd->ioc->id, mf);
-*/
-/* FIXME!  Check return status! */
-	if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-				sizeof(SCSITaskMgmt_t), msg))
-	    != 0) {
-		printk(KERN_WARNING MYNAM
-				": WARNING[3] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
-				i, mf, SCpnt);
-		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+			if (info_kbuf != NULL)
+				kfree(info_kbuf);
+		}
 	}
 
-	//return SUCCESS;
-	return FAILED;
+	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
- *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *	mptscsih_halt - Process the reboot notification
+ *	@nb: Pointer to a struct notifier_block (ignored)
+ *	@event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF)
+ *	@buf: Pointer to a data buffer (ignored)
  *
- *	(linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *	This routine called if a system shutdown or reboot is to occur.
  *
- *	Returns SUCCESS or FAILED.
+ *	Return NOTIFY_DONE if this is something other than a reboot message.
+ *		NOTIFY_OK if this is a reboot message.
  */
-int
-mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+static int
+mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
 {
-	MPT_FRAME_HDR	*mf;
-	SCSITaskMgmt_t	*pScsiTm;
-	MPT_SCSI_HOST	*hd;
-	u32		*msg;
-	int		 i;
-	unsigned long	 flags;
-
-	printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+	MPT_ADAPTER *ioc = NULL;
+	MPT_SCSI_HOST *hd = NULL;
 
-	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+	/* Ignore all messages other than reboot message
+	 */
+	if ((event != SYS_RESTART) && (event != SYS_HALT)
+		&& (event != SYS_POWER_OFF))
+		return (NOTIFY_DONE);
 
-	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
-/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
-		SCpnt->result = STS_BUSY;
-		SCpnt->scsi_done(SCpnt);
-		return FAILED;
+	for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc =	mpt_adapter_find_next(ioc)) {
+		/* Flush the cache of this adapter
+		 */
+		if (ioc->sh) {
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+			if (hd) {
+				mptscsih_synchronize_cache(hd, 0);
+			}
+		}
 	}
 
-	pScsiTm = (SCSITaskMgmt_t *) mf;
-	msg = (u32 *) mf;
-
-	pScsiTm->TargetID = SCpnt->target;
-	pScsiTm->Bus = hd->port;
-	pScsiTm->ChainOffset = 0;
-	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+	unregister_reboot_notifier(&mptscsih_notifier);
+	return NOTIFY_OK;
+}
 
-	pScsiTm->Reserved = 0;
-	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-	pScsiTm->Reserved1 = 0;
-	pScsiTm->MsgFlags = 0;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_info - Return information about MPT adapter
+ *	@SChost: Pointer to Scsi_Host structure
+ *
+ *	(linux Scsi_Host_Template.info routine)
+ *
+ *	Returns pointer to buffer where information was written.
+ */
+const char *
+mptscsih_info(struct Scsi_Host *SChost)
+{
+	MPT_SCSI_HOST *h;
+	int size = 0;
 
-	for (i = 0; i < 8; i++)
-		pScsiTm->LUN[i] = 0;
+	if (info_kbuf == NULL)
+		if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+			return info_kbuf;
 
-	/* Control: No data direction, set task mgmt bit? */
-	for (i = 0; i < 7; i++)
-		pScsiTm->Reserved2[i] = 0;
+	h = (MPT_SCSI_HOST *)SChost->hostdata;
+	info_kbuf[0] = '\0';
+	mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
+	info_kbuf[size-1] = '\0';
 
-	pScsiTm->TaskMsgContext = cpu_to_le32(0);
+	return info_kbuf;
+}
 
-/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-	mpt_put_msg_frame(hd->ioc->id, mf);
-*/
-/* FIXME!  Check return status! */
-	if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-				sizeof(SCSITaskMgmt_t), msg))
-	    != 0) {
-		printk(KERN_WARNING MYNAM
-				": WARNING[4] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
-				i, mf, SCpnt);
-		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-	}
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+	static int max_qd = 1;
+#if 0
+static int index_log[128];
+static int index_ent = 0;
+static __inline__ void ADD_INDEX_LOG(int req_ent)
+{
+	int i = index_ent++;
 
-	return SUCCESS;
+	index_log[i & (128 - 1)] = req_ent;
 }
+#else
+#define ADD_INDEX_LOG(req_ent)	do { } while(0)
+#endif
+
+#ifdef	DROP_TEST
+#define DROP_IOC	1	/* IOC to force failures */
+#define DROP_TARGET	3	/* Target ID to force failures */
+#define	DROP_THIS_CMD	10000	/* iteration to drop command */
+static int dropCounter = 0;
+static int dropTestOK = 0;	/* num did good */
+static int dropTestBad = 0;	/* num did bad */
+static int dropTestNum = 0;	/* total = good + bad + incomplete */
+static int numTotCmds = 0;
+static MPT_FRAME_HDR *dropMfPtr = NULL;
+static int numTMrequested = 0;
+#endif
 
-#if 0	/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_host_reset - Perform a SCSI host adapter RESET!
- *	new_eh variant
- *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+/*
+ *	mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
+ *	@context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) 
+ *	@id: IOC id number 
+ *	@mf: Pointer to message frame 
  *
- *	(linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *	Handles the call to mptbase for posting request and queue depth 
+ *	tracking.
  *
- *	Returns SUCCESS or FAILED.
+ *	Returns none.
  */
-int
-mptscsih_host_reset(Scsi_Cmnd * SCpnt)
+static void
+mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
 {
-	return FAILED;
+	/* Main banana... */
+	atomic_inc(&queue_depth);
+	if (atomic_read(&queue_depth) > max_qd) {
+		max_qd = atomic_read(&queue_depth);
+		dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
+	}
+
+	mpt_put_msg_frame(context, id, mf);
+
+	return;
 }
-#endif	/* } */
 
-#else		/* MPT_SCSI old EH stuff... */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mptscsih_old_abort - Abort linux Scsi_Cmnd routine
- *	@SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *	mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
+ *	@SCpnt: Pointer to Scsi_Cmnd structure
+ *	@done: Pointer SCSI mid-layer IO completion function
  *
- *	(linux Scsi_Host_Template.abort routine)
+ *	(linux Scsi_Host_Template.queuecommand routine)
+ *	This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
+ *	from a linux Scsi_Cmnd request and send it to the IOC.
  *
- *	Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ *	Returns 0. (rtn value discarded by linux scsi mid-layer)
  */
 int
-mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	SCSIIORequest_t		*pScsiReq;
+	VirtDevice		*pTarget;
+	MPT_DONE_Q		*buffer = NULL;
 	unsigned long		 flags;
+	int	 target;
+	int	 lun;
+	int	 datadir;
+	u32	 datalen;
+	u32	 scsictl;
+	u32	 scsidir;
+	u32	 qtag;
+	u32	 cmd_len;
+	int	 my_idx;
+	int	 ii;
+	int	 rc;
+	int	 did_errcode;
+	int	 issueCmd;
 
-	printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+	did_errcode = 0;
+	hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+	target = SCpnt->target;
+	lun = SCpnt->lun;
+	SCpnt->scsi_done = done;
 
-	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-		SCpnt->result = DID_ABORT << 16;
-		SCpnt->scsi_done(SCpnt);
-		return SCSI_ABORT_SUCCESS;
-	}
+	pTarget = hd->Targets[target];
 
-	/*
-	 *  Check to see if there's already an ABORT queued for this guy.
+	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
+			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+
+	/* 20000617 -sralston
+	 *  GRRRRR...  Shouldn't have to do this but...
+	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
+	 *  If yes, return cached SenseData.
 	 */
-	mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
-	if (mf != NULL) {
-		return SCSI_ABORT_PENDING;
+	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
+		u8 *dest = NULL;
+		int sz;
+
+		if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
+			pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;	//sjr-moved-here
+			if (!SCpnt->use_sg) {
+				dest = SCpnt->request_buffer;
+			} else {
+				struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+				if (sg)
+					dest = (u8 *)(ulong)sg_dma_address(sg);
+			}
+
+			if (dest) {
+				sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
+				memcpy(dest, pTarget->sense, sz);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+				SCpnt->resid = SCpnt->request_bufflen - sz;
+#endif
+				SCpnt->result = 0;
+				SCpnt->scsi_done(SCpnt);
+
+				//sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
+
+				return 0;
+			}
+		}
 	}
 
-	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
-/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
-		SCpnt->result = STS_BUSY;
-		SCpnt->scsi_done(SCpnt);
-		return SCSI_ABORT_BUSY;
+	if (hd->resetPending) {
+		/* Prevent new commands from being issued
+		 * while reloading the FW.
+		 */
+		did_errcode = 1;
+		goto did_error;
 	}
 
 	/*
-	 *  Add ourselves to (end of) mpt_scsih_taskQ.
-	 *  Check to see if our _bh is running.  If NOT, schedule it.
+	 *  Put together a MPT SCSI request...
 	 */
-	dslprintk((KERN_INFO MYNAM ": spinlock#2\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
-	mpt_scsih_taskQ_cnt++;
-	/* Yikes - linkage! */
-/*	SCpnt->host_scribble = (unsigned char *)mf;	*/
-	mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
-	mf->u.frame.linkage.argp1 = SCpnt;
-	if (! mpt_scsih_taskQ_bh_active) {
-		mpt_scsih_taskQ_bh_active = 1;
-		/*
-		 *  Oh how cute, no alloc/free/mgmt needed if we use
-		 *  (bottom/unused portion of) MPT request frame.
-		 */
-		ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
-
-		SCHEDULE_TASK(ptaskfoo);
+	if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+		dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+				hd->ioc->name));
+		did_errcode = 2;
+		goto did_error;
 	}
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-
-	return SCSI_ABORT_PENDING;
-}
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_old_reset - Perform a SCSI BUS_RESET!
- *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
- *	@reset_flags: (not used?)
- *
- *	(linux Scsi_Host_Template.reset routine)
- *
- *	Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
- */
-int
-mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
-{
-	MPT_SCSI_HOST		*hd;
-	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
-	unsigned long		 flags;
+	pScsiReq = (SCSIIORequest_t *) mf;
 
-	printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt);
-	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 
-	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
-		return SCSI_RESET_SUCCESS;
-	}
+	ADD_INDEX_LOG(my_idx);
 
 	/*
-	 *  Check to see if there's already a BUS_RESET queued for this guy.
+	 *  The scsi layer should be handling this stuff
+	 *  (In 2.3.x it does -DaveM)
 	 */
-	mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
-	if (mf != NULL) {
-		return SCSI_RESET_PENDING;
-	}
 
-	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
-/*		SCpnt->result = DID_SOFT_ERROR << 16;	*/
-		SCpnt->result = STS_BUSY;
-		SCpnt->scsi_done(SCpnt);
-		return SCSI_RESET_PUNT;
+	/*  BUG FIX!  19991030 -sralston
+	 *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+	 *    Seems we may receive a buffer (datalen>0) even when there
+	 *    will be no data transfer!  GRRRRR...
+	 */
+	datadir = mptscsih_io_direction(SCpnt);
+	if (datadir < 0) {
+		datalen = SCpnt->request_bufflen;
+		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */
+	} else if (datadir > 0) {
+		datalen = SCpnt->request_bufflen;
+		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */
+	} else {
+		datalen = 0;
+		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
 	}
 
-	/*
-	 *  Add ourselves to (end of) mpt_scsih_taskQ.
-	 *  Check to see if our _bh is running.  If NOT, schedule it.
+	/* Default to untagged. Once a target structure has been allocated,
+	 * use the Inquiry data to determine if device supports tagged.
 	 */
-	dslprintk((KERN_INFO MYNAM ": spinlock#3\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
-	mpt_scsih_taskQ_cnt++;
-	/* Yikes - linkage! */
-/*	SCpnt->host_scribble = (unsigned char *)mf;	*/
-	mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-	mf->u.frame.linkage.argp1 = SCpnt;
-	if (! mpt_scsih_taskQ_bh_active) {
-		mpt_scsih_taskQ_bh_active = 1;
+	qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
+	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+			&& (SCpnt->device->tagged_supported)) {
 		/*
-		 *  Oh how cute, no alloc/free/mgmt needed if we use
-		 *  (bottom/unused portion of) MPT request frame.
+		 *  Some drives are too stupid to handle fairness issues
+		 *  with tagged queueing. We throw in the odd ordered
+		 *  tag to stop them starving themselves.
 		 */
-		ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
-
-		SCHEDULE_TASK(ptaskfoo);
+		if ((jiffies - hd->qtag_tick) > (5*HZ)) {
+			qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+			hd->qtag_tick = jiffies;
+		}
+		else
+			qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
 	}
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+	scsictl = scsidir | qtag;
 
-	return SCSI_RESET_PENDING;
-}
+	/* Use the above information to set up the message frame
+	 */
+	pScsiReq->TargetID = target;
+	pScsiReq->Bus = hd->port;
+	pScsiReq->ChainOffset = 0;
+	pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+	pScsiReq->CDBLength = SCpnt->cmd_len;
+	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+	pScsiReq->Reserved = 0;
+	pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+	pScsiReq->LUN[0] = 0;
+	pScsiReq->LUN[1] = lun;
+	pScsiReq->LUN[2] = 0;
+	pScsiReq->LUN[3] = 0;
+	pScsiReq->LUN[4] = 0;
+	pScsiReq->LUN[5] = 0;
+	pScsiReq->LUN[6] = 0;
+	pScsiReq->LUN[7] = 0;
+	pScsiReq->Control = cpu_to_le32(scsictl);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
- *	@sc: (unused)
- *
- *	This routine (thread) is active whenever there are any outstanding
- *	SCSI task management requests for a SCSI host adapter.
- *	IMPORTANT!  This routine is scheduled therefore should never be
- *	running in ISR context.  i.e., it's safe to sleep here.
- */
-void
-mptscsih_taskmgmt_bh(void *sc)
-{
-	Scsi_Cmnd	*SCpnt;
-	MPT_FRAME_HDR	*mf;
-	SCSITaskMgmt_t	*pScsiTm;
-	MPT_SCSI_HOST	*hd;
-	u32		 ctx2abort = 0;
-	int		 i;
-	unsigned long	 flags;
-	u8		 task_type;
+	/*
+	 *  Write SCSI CDB into the message
+	 */
+	cmd_len = SCpnt->cmd_len;
+	for (ii=0; ii < cmd_len; ii++)
+		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
+	for (ii=cmd_len; ii < 16; ii++)
+		pScsiReq->CDB[ii] = 0;
 
-	dslprintk((KERN_INFO MYNAM ": spinlock#4\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	mpt_scsih_taskQ_bh_active = 1;
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+	/* DataLength */
+	pScsiReq->DataLength = cpu_to_le32(datalen);
 
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/4);
+	/* SenseBuffer low address */
+	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-		/*
-		 *  We MUST remove item from taskQ *before* we format the
-		 *  frame as a SCSITaskMgmt request and send it down to the IOC.
+	/* Now add the SG list
+	 * Always have a SGE even if null length.
+	 */
+	rc = SUCCESS;
+	if (datalen == 0) {
+		/* Add a NULL SGE */
+		mptscsih_AddNullSGE(pScsiReq);
+	} else {
+		/* Add a 32 or 64 bit SGE */
+		rc = mptscsih_Add32BitSGE(hd, SCpnt, pScsiReq, my_idx);
+	}
+
+
+	if (rc == SUCCESS) {
+		hd->ScsiLookup[my_idx] = SCpnt;
+		SCpnt->host_scribble = NULL;
+
+#ifdef	DROP_TEST
+		numTotCmds++;
+		/* If the IOC number and target match, increment
+		 * counter. If counter matches DROP_THIS, do not
+		 * issue command to FW to force a reset.
+		 * Save the MF pointer so we can free resources
+		 * when task mgmt completes.
 		 */
-		dslprintk((KERN_INFO MYNAM ": spinlock#5\n"));
-		spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-		if (Q_IS_EMPTY(&mpt_scsih_taskQ)) {
-			spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-			break;
-		}
-		mf = mpt_scsih_taskQ.head;
-		Q_DEL_ITEM(&mf->u.frame.linkage);
-		mpt_scsih_taskQ_cnt--;
-		mpt_scsih_active_taskmgmt_mf = mf;
-		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-
-		SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
-		if (SCpnt == NULL) {
-			printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt);
-			continue;
-		}
-		hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
-		pScsiTm = (SCSITaskMgmt_t *) mf;
+		if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
+			dropCounter++;
 
-		for (i = 0; i < 8; i++) {
-			pScsiTm->LUN[i] = 0;
-		}
+			if (dropCounter == DROP_THIS_CMD) {
+				dropCounter = 0;
 
-		task_type = mf->u.frame.linkage.arg1;
-		if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-			printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf=%p:sc=%p)\n",
-					mf, SCpnt);
-
-			/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
-			 * (the IO to be ABORT'd)
-			 *
-			 * NOTE: Since we do not byteswap MsgContext, we do not
-			 *	 swap it here either.  It is an opaque cookie to
-			 *	 the controller, so it does not matter. -DaveM
-			 */
-			ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
-			if (ctx2abort == -1) {
-				printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#1) for SCpnt=%p\n", SCpnt);
-				SCpnt->result = DID_SOFT_ERROR << 16;
-				spin_lock_irqsave(&io_request_lock, flags);
-				SCpnt->scsi_done(SCpnt);
-				spin_unlock_irqrestore(&io_request_lock, flags);
-				mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-				continue;
+				/* If global is set, then we are already
+				 * doing something - so keep issuing commands.
+				 */
+				if (dropMfPtr == NULL) {
+					dropTestNum++;
+					dropMfPtr = mf;
+					atomic_inc(&queue_depth);
+					printk(MYIOC_s_INFO_FMT
+						"Dropped SCSI cmd (%p)\n",
+						hd->ioc->name, SCpnt);
+					printk("mf (%p) req (%4x) tot cmds (%d)\n",
+						mf, my_idx, numTotCmds);
+
+					return 0;
+				}
 			}
-			pScsiTm->LUN[1] = SCpnt->lun;
 		}
-		else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
-		{
-			printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf=%p:sc=%p)\n", mf, SCpnt);
-		}
-#if 0
-		else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {}
-		else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {}
 #endif
 
-		printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+		/* SCSI specific processing */
+		issueCmd = 1;
+		if (hd->is_spi) {
+			int dvStatus = hd->ioc->spi_data.dvStatus[target];
+
+			if (dvStatus || hd->ioc->spi_data.forceDv) {
+
+				/* Write SDP1 on 1st I/O to this target */
+				if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
+					mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
+					dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
+					hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+				}
 
-		pScsiTm->TargetID = SCpnt->target;
-		pScsiTm->Bus = hd->port;
-		pScsiTm->ChainOffset = 0;
-		pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+				if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) {
+					unsigned long lflags;
+					/* Schedule DV if necessary */
+					spin_lock_irqsave(&dvtaskQ_lock, lflags);
+					if (!dvtaskQ_active) {
+						dvtaskQ_active = 1;
+						mptscsih_dvTask.sync = 0;
+						mptscsih_dvTask.routine = mptscsih_domainValidation;
+						mptscsih_dvTask.data = (void *) hd;
 
-		pScsiTm->Reserved = 0;
-		pScsiTm->TaskType = task_type;
-		pScsiTm->Reserved1 = 0;
-		pScsiTm->MsgFlags = 0;
+						SCHEDULE_TASK(&mptscsih_dvTask);
+					}
+					hd->ioc->spi_data.forceDv = 0;
+					spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+				}
 
-		for (i = 0; i < 7; i++)
-			pScsiTm->Reserved2[i] = 0;
+				/* Trying to do DV to this target, extend timeout.
+				 * Wait to issue intil flag is clear 
+				 */
+				if (dvStatus & MPT_SCSICFG_DV_PENDING) {
+					mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
+					issueCmd = 0;
+				}
+#endif
+			}
+		}
 
-		dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
-		pScsiTm->TaskMsgContext = ctx2abort;
+		if (issueCmd) {
+			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n",
+					hd->ioc->name, SCpnt));
+		} else {
+			ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n",
+					hd->ioc->name, SCpnt));
+			/* Place this command on the pendingQ if possible */
+			spin_lock_irqsave(&hd->freedoneQlock, flags);
+			if (!Q_IS_EMPTY(&hd->freeQ)) {
+				buffer = hd->freeQ.head;
+				Q_DEL_ITEM(buffer);
 
-		/* Control: No data direction, set task mgmt bit? */
+				/* Save the mf pointer
+				 */
+				buffer->argp = (void *)mf;
 
-		/*
-		 *  As of MPI v0.10 this request can NOT be sent (normally)
-		 *  via FIFOs.	So we can't:
-		 *		mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-		 *  SCSITaskMgmt requests MUST be sent ONLY via
-		 *  Doorbell/handshake now.   :-(
-		 */
-		if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-					sizeof(SCSITaskMgmt_t), (u32*) mf))
-		    != 0) {
-			printk(KERN_WARNING MYNAM ": WARNING[1] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt);
-			SCpnt->result = DID_SOFT_ERROR << 16;
-			spin_lock_irqsave(&io_request_lock, flags);
-			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-			mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-		} else {
-			/* Spin-Wait for TaskMgmt complete!!! */
-			while (mpt_scsih_active_taskmgmt_mf != NULL) {
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout(HZ/4);
+				/* Add to the pendingQ
+				 */
+				Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
+				spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			} else {
+				spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+				SCpnt->result = (DID_BUS_BUSY << 16);
+				SCpnt->scsi_done(SCpnt);
 			}
 		}
+	} else {
+		mptscsih_freeChainBuffers(hd, my_idx);
+		mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+		did_errcode = 3;
+		goto did_error;
 	}
 
-	dslprintk((KERN_INFO MYNAM ": spinlock#6\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	mpt_scsih_taskQ_bh_active = 0;
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+	return 0;
 
-	return;
-}
+did_error:
+	dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
+			hd->ioc->name, did_errcode, SCpnt));
+	/* Just wish OS to issue a retry */
+	SCpnt->result = (DID_BUS_BUSY << 16);
+	spin_lock_irqsave(&hd->freedoneQlock, flags);
+	if (!Q_IS_EMPTY(&hd->freeQ)) {
+		buffer = hd->freeQ.head;
+		Q_DEL_ITEM(buffer);
 
-#endif		/* } */
+		/* Set the Scsi_Cmnd pointer
+		 */
+		buffer->argp = (void *)SCpnt;
+
+		/* Add to the doneQ
+		 */
+		Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+		spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+	} else {
+		spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+		SCpnt->scsi_done(SCpnt);
+	}
+
+	return 0;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_taskmgmt_complete - Callback routine, gets registered to
- *	Fusion MPT base	driver
- *	@ioc: Pointer to MPT_ADAPTER structure
- *	@mf: Pointer to SCSI task mgmt request frame
- *	@r: Pointer to SCSI task mgmt reply frame
- *
- *	This routine is called from mptbase.c::mpt_interrupt() at the completion
- *	of any SCSI task management request.
- *	This routine is registered with the MPT (base) driver at driver
- *	load/init time via the mpt_register() API call.
+/*
+ *	mptscsih_Add32BitSGE - Add a 32Bit SGE (plus chain buffers) to the
+ *	SCSIIORequest_t Message Frame.
+ *	@hd: Pointer to MPT_SCSI_HOST structure
+ *	@SCpnt: Pointer to Scsi_Cmnd structure
+ *	@pReq: Pointer to SCSIIORequest_t structure
  *
- *	Returns 1 indicating alloc'd request frame ptr should be freed.
+ *	Returns ...
  */
 static int
-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+mptscsih_Add32BitSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+				 SCSIIORequest_t *pReq, int req_idx)
 {
-	SCSITaskMgmtReply_t	*pScsiTmReply;
-	SCSITaskMgmt_t		*pScsiTmReq;
-	u8			 tmType;
-#ifndef MPT_SCSI_USE_NEW_EH
-	unsigned long		 flags;
-#endif
+	MptSge_t *psge;
+	MptChain_t  *chainSge;
+	struct scatterlist *sg;
+	int	 frm_sz;
+	int	 sges_left, sg_done;
+	int	 chain_idx = MPT_HOST_NO_CHAIN;
+	int	 sgeOffset;
+	int	 numSgeSlots, numSgeThisFrame;
+	u32	 sgflags, sgdir, len, thisxfer = 0;
+	int	 offset;
+	int	 newIndex;
+	int	 ii;
+	dma_addr_t v2;
+
+	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
+	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
+		sgdir = MPT_TRANSFER_HOST_TO_IOC;
+	} else {
+		sgdir = MPT_TRANSFER_IOC_TO_HOST;
+	}
 
-	dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n",
-		 mf, r));
+	psge = (MptSge_t *) &pReq->SGL;
+	frm_sz = hd->ioc->req_sz;
 
-#ifndef MPT_SCSI_USE_NEW_EH
-	dslprintk((KERN_INFO MYNAM ": spinlock#7\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	/* It better be the active one! */
-	if (mf != mpt_scsih_active_taskmgmt_mf) {
-		printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf);
-		mpt_scsih_active_taskmgmt_mf = NULL;
-		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-		return 1;
+	/* Map the data portion, if any.
+	 * sges_left  = 0 if no data transfer.
+	 */
+	sges_left = SCpnt->use_sg;
+	if (SCpnt->use_sg) {
+		sges_left = pci_map_sg(hd->ioc->pcidev,
+			       (struct scatterlist *) SCpnt->request_buffer,
+			       SCpnt->use_sg,
+			       scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	} else if (SCpnt->request_bufflen) {
+		dma_addr_t	 buf_dma_addr;
+		scPrivate	*my_priv;
+
+		buf_dma_addr = pci_map_single(hd->ioc->pcidev,
+				      SCpnt->request_buffer,
+				      SCpnt->request_bufflen,
+				      scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+
+		/* We hide it here for later unmap. */
+		my_priv = (scPrivate *) &SCpnt->SCp;
+		my_priv->p1 = (void *)(ulong) buf_dma_addr;
+
+		dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
+				hd->ioc->name, SCpnt, SCpnt->request_bufflen));
+
+		/* 0xD1000000 = LAST | EOB | SIMPLE | EOL */
+		psge->FlagsLength = cpu_to_le32(
+				0xD1000000|sgdir|SCpnt->request_bufflen);
+		cpu_to_leXX(buf_dma_addr, psge->Address);
+
+		return SUCCESS;
 	}
 
-#ifdef MPT_DEBUG
-	if ((mf == NULL) ||
-	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-		printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf);
-		mpt_scsih_active_taskmgmt_mf = NULL;
-		spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-		return 1;
+	/* Handle the SG case.
+	 */
+	sg = (struct scatterlist *) SCpnt->request_buffer;
+	sg_done  = 0;
+	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
+	chainSge = NULL;
+
+	/* Prior to entering this loop - the following must be set
+	 * current MF:  sgeOffset (bytes)
+	 *              chainSge (Null if original MF is not a chain buffer)
+	 *              sg_done (num SGE done for this MF)
+	 */
+
+nextSGEset:
+	numSgeSlots = ((frm_sz - sgeOffset) / sizeof(MptSge_t));
+	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
+
+	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+
+	/* Get first (num - 1) SG elements
+	 * Skip any SG entries with a length of 0
+	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
+	 */
+	for (ii=0; ii < (numSgeThisFrame-1); ii++) {
+		thisxfer = sg_dma_len(sg);
+		if (thisxfer == 0) {
+			sg ++; /* Get next SG element from the OS */
+			sg_done++;
+			continue;
+		}
+
+		len += thisxfer;
+		psge->FlagsLength = cpu_to_le32( sgflags | thisxfer );
+		v2 = sg_dma_address(sg);
+		cpu_to_leXX(v2, psge->Address);
+
+		sg++;		/* Get next SG element from the OS */
+		psge++;		/* Point to next SG location in this MF */
+		sgeOffset += sizeof(MptSge_t);
+		sg_done++;
 	}
-#endif
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-#endif
 
-	if (r != NULL) {
-		pScsiTmReply = (SCSITaskMgmtReply_t*)r;
-		pScsiTmReq = (SCSITaskMgmt_t*)mf;
+	if (numSgeThisFrame == sges_left) {
+		/* Add last element, end of buffer and end of list flags.
+		 */
+		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
+				MPT_SGE_FLAGS_END_OF_BUFFER |
+				MPT_SGE_FLAGS_ADDRESSING |
+				MPT_SGE_FLAGS_END_OF_LIST;
 
-		/* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
-		tmType = pScsiTmReq->TaskType;
+		/* Add last SGE and set termination flags.
+		 * Note: Last SGE may have a length of 0 - which should be ok.
+		 */
+		thisxfer = sg_dma_len(sg);
+		len += thisxfer;
+
+		psge->FlagsLength = cpu_to_le32( sgflags | thisxfer );
+		v2 = sg_dma_address(sg);
+		cpu_to_leXX(v2, psge->Address);
+
+		sg_done++;
+
+		if (chainSge) {
+			/* The current buffer is a chain buffer,
+			 * but there is not another one.
+			 * Update the chain element
+			 * Offset and Length fields.
+			 */
+			chainSge->NextChainOffset = 0;
+			sgeOffset += sizeof(MptSge_t);
+			chainSge->Length = cpu_to_le16(sgeOffset);
+		} else {
+			/* The current buffer is the original MF
+			 * and there is no Chain buffer.
+			 */
+			pReq->ChainOffset = 0;
+		}
+	} else {
+		/* At least one chain buffer is needed.
+		 * Complete the first MF
+		 *  - last SGE element, set the LastElement bit
+		 *  - set ChainOffset (words) for orig MF
+		 *             (OR finish previous MF chain buffer)
+		 *  - update MFStructPtr ChainIndex
+		 *  - Populate chain element
+		 * Also
+		 * Loop until done.
+		 */
 
-		dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType));
-		dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n",
-			 le32_to_cpu(pScsiTmReply->TerminationCount)));
+		dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
+				hd->ioc->name, sg_done));
 
-		/* Error?  (anything non-zero?) */
-		if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
-			dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType));
-			dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n",
-				 le16_to_cpu(pScsiTmReply->IOCStatus)));
-			dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n",
-				 le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+		/* Set LAST_ELEMENT flag for last non-chain element
+		 * in the buffer. Since psge points at the NEXT
+		 * SGE element, go back one SGE element, update the flags
+		 * and reset the pointer. (Note: sgflags & thisxfer are already
+		 * set properly).
+		 */
+		if (sg_done) {
+			psge--;
+			sgflags = le32_to_cpu (psge->FlagsLength);
+			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
+			psge->FlagsLength = cpu_to_le32( sgflags );
+			psge++;
+		}
+
+		if (chainSge) {
+			/* The current buffer is a chain buffer.
+			 * chainSge points to the previous Chain Element.
+			 * Update its chain element Offset and Length (must
+			 * include chain element size) fields.
+			 * Old chain element is now complete.
+			 */
+			chainSge->NextChainOffset = (u8) (sgeOffset >> 2);
+			sgeOffset += sizeof(MptSge_t);
+			chainSge->Length = cpu_to_le16(sgeOffset);
 		} else {
-			dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType));
+			/* The original MF buffer requires a chain buffer -
+			 * set the offset.
+			 * Last element in this MF is a chain element.
+			 */
+			pReq->ChainOffset = (u8) (sgeOffset >> 2);
 		}
-	}
 
-#ifndef MPT_SCSI_USE_NEW_EH
-	/*
-	 *  Signal to _bh thread that we finished.
-	 */
-	dslprintk((KERN_INFO MYNAM ": spinlock#8\n"));
-	spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-	mpt_scsih_active_taskmgmt_mf = NULL;
-	spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-#endif
+		sges_left -= sg_done;
 
-	return 1;
+
+		/* NOTE: psge points to the beginning of the chain element
+		 * in current buffer. Get a chain buffer.
+		 */
+		if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
+			return FAILED;
+
+		/* Update the tracking arrays.
+		 * If chainSge == NULL, update ReqToChain, else ChainToChain
+		 */
+		if (chainSge) {
+			hd->ChainToChain[chain_idx] = newIndex;
+		} else {
+			hd->ReqToChain[req_idx] = newIndex;
+		}
+		chain_idx = newIndex;
+		offset = hd->ioc->req_sz * chain_idx;
+
+		/* Populate the chainSGE for the current buffer.
+		 * - Set chain buffer pointer to psge and fill
+		 *   out the Address and Flags fields.
+		 */
+		chainSge = (MptChain_t *) psge;
+		chainSge->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
+		cpu_to_leXX ((hd->ChainBufferDMA + offset), chainSge->Address);
+
+		dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
+				psge, req_idx));
+
+		/* Start the SGE for the next buffer
+		 */
+		psge = (MptSge_t *) (hd->ChainBuffer + offset);
+		sgeOffset = 0;
+		sg_done = 0;
+
+		dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
+				psge, chain_idx));
+
+		/* Start the SGE for the next buffer
+		 */
+
+		goto nextSGEset;
+	}
+
+	return SUCCESS;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	This is anyones guess quite frankly.
+ *	mptscsih_AddNullSGE - Add a NULL SGE to the SCSIIORequest_t
+ *	Message Frame.
+ *	@pReq: Pointer to SCSIIORequest_t structure
  */
-
-int
-mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+static void
+mptscsih_AddNullSGE(SCSIIORequest_t *pReq)
 {
-	int size;
+	MptSge_t *psge;
 
-	size = disk->capacity;
-	ip[0] = 64;				/* heads			*/
-	ip[1] = 32;				/* sectors			*/
-	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
-		ip[0] = 255;			/* heads			*/
-		ip[1] = 63;			/* sectors			*/
-		ip[2] = size / (255 * 63);	/* cylinders			*/
-	}
-	return 0;
+	psge = (MptSge_t *) &pReq->SGL;
+	psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | 0);
+
+	cpu_to_leXX( (dma_addr_t) -1, psge->Address);
+
+	return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  Private routines...
- */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* 19991030 -sralston
- *  Return absolute SCSI data direction:
- *     1 = _DATA_OUT
- *     0 = _DIR_NONE
- *    -1 = _DATA_IN
+ *	mptscsih_getFreeChainBuffes - Function to get a free chain
+ *	from the MPT_SCSI_HOST FreeChainQ.
+ *	@hd: Pointer to the MPT_SCSI_HOST instance
+ *	@req_idx: Index of the SCSI IO request frame. (output)
+ *
+ *	return SUCCESS or FAILED
  */
 static int
-mptscsih_io_direction(Scsi_Cmnd *cmd)
+mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
 {
-	switch (cmd->cmnd[0]) {
-	/*  _DATA_OUT commands	*/
-	case WRITE_6:		case WRITE_10:		case WRITE_12:
-	case WRITE_LONG:	case WRITE_SAME:	case WRITE_BUFFER:
-	case WRITE_VERIFY:	case WRITE_VERIFY_12:
-	case COMPARE:		case COPY:		case COPY_VERIFY:
-	case SEARCH_EQUAL:	case SEARCH_HIGH:	case SEARCH_LOW:
-	case SEARCH_EQUAL_12:	case SEARCH_HIGH_12:	case SEARCH_LOW_12:
-	case MODE_SELECT:	case MODE_SELECT_10:	case LOG_SELECT:
-	case SEND_DIAGNOSTIC:	case CHANGE_DEFINITION: case UPDATE_BLOCK:
-	case SET_WINDOW:	case MEDIUM_SCAN:	case SEND_VOLUME_TAG:
-	case REASSIGN_BLOCKS:
-	case PERSISTENT_RESERVE_OUT:
-	case 0xea:
-		return 1;
+	MPT_FRAME_HDR *chainBuf = NULL;
+	unsigned long flags;
+	int rc = FAILED;
+	int chain_idx = MPT_HOST_NO_CHAIN;
 
-	/*  No data transfer commands  */
-	case SEEK_6:		case SEEK_10:
-	case RESERVE:		case RELEASE:
-	case TEST_UNIT_READY:
-	case START_STOP:
-	case ALLOW_MEDIUM_REMOVAL:
-		return 0;
+	//spin_lock_irqsave(&hd->FreeChainQlock, flags);
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
 
-	/*  Conditional data transfer commands	*/
-	case FORMAT_UNIT:
-		if (cmd->cmnd[1] & 0x10)	/* FmtData (data out phase)? */
-			return 1;
-		else
-			return 0;
+		int offset;
 
-	case VERIFY:
-		if (cmd->cmnd[1] & 0x02)	/* VERIFY:BYTCHK (data out phase)? */
-			return 1;
-		else
-			return 0;
+		chainBuf = hd->FreeChainQ.head;
+		Q_DEL_ITEM(&chainBuf->u.frame.linkage);
+		offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
+		chain_idx = offset / hd->ioc->req_sz;
+		rc = SUCCESS;
+	}
+	//spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-	case RESERVE_10:
-		if (cmd->cmnd[1] & 0x03)	/* RESERSE:{LongID|Extent} (data out phase)? */
-			return 1;
-		else
-			return 0;
 
-#if 0
-	case REZERO_UNIT:	/* (or REWIND) */
-	case SPACE:
-	case ERASE:		case ERASE_10:
-	case SYNCHRONIZE_CACHE:
-	case LOCK_UNLOCK_CACHE:
-#endif
+	*retIndex = chain_idx;
 
-	/*  Must be data _IN!  */
-	default:
-		return -1;
-	}
+	dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
+			hd->ioc->name, *retIndex, chainBuf));
+
+	return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_freeChainBuffers - Function to free chain buffers associated
+ *	with a SCSI IO request
+ *	@hd: Pointer to the MPT_SCSI_HOST instance
+ *	@req_idx: Index of the SCSI IO request frame.
+ *
+ *	Called if SG chain buffer allocation fails and mptscsih callbacks.
+ *	No return.
+ */
 static void
-copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx)
 {
-	MPT_SCSI_DEV	*mpt_sdev = NULL;
-	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
-	char		 devFoo[32];
-	IO_Info_t	 thisIo;
-
-	if (sc && sc->device)
-		mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata;
-
-	if (sense_count) {
-		u8 *sense_data;
-		int req_index;
+	MPT_FRAME_HDR *chain = NULL;
+	unsigned long flags;
+	int chain_idx;
+	int next;
 
-		/* Copy the sense received into the scsi command block. */
-		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-		sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256));
-		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
-		/* Cache SenseData for this SCSI device! */
-		if (mpt_sdev) {
-			memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count);
-			mpt_sdev->sense_sz = sense_count;
-		}
-	} else {
-		dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n"));
-	}
+	/* Get the first chain index and reset
+	 * tracker state.
+	 */
+	chain_idx = hd->ReqToChain[req_idx];
+	hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
 
+	while (chain_idx != MPT_HOST_NO_CHAIN) {
 
-	thisIo.cdbPtr = sc->cmnd;
-	thisIo.sensePtr = sc->sense_buffer;
-	thisIo.SCSIStatus = pScsiReply->SCSIStatus;
-	thisIo.DoDisplay = 1;
-	sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun);
-	thisIo.DevIDStr = devFoo;
-/* fubar */
-	thisIo.dataPtr = NULL;
-	thisIo.inqPtr = NULL;
-	if (sc->device) {
-		thisIo.inqPtr = sc->device->vendor-8;		/* FIXME!!! */
-	}
-	(void) mpt_ScsiHost_ErrorReport(&thisIo);
+		/* Save the next chain buffer index */
+		next = hd->ChainToChain[chain_idx];
 
-	return;
-}
+		/* Free this chain buffer and reset
+		 * tracker
+		 */
+		hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static u32
-SCPNT_TO_MSGCTX(Scsi_Cmnd *sc)
-{
-	MPT_SCSI_HOST *hd;
-	MPT_FRAME_HDR *mf;
-	int i;
+		chain = (MPT_FRAME_HDR *) (hd->ChainBuffer
+					+ (chain_idx * hd->ioc->req_sz));
+		//spin_lock_irqsave(&hd->FreeChainQlock, flags);
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		Q_ADD_TAIL(&hd->FreeChainQ.head,
+					&chain->u.frame.linkage, MPT_FRAME_HDR);
+		//spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-	hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+		dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
+				hd->ioc->name, chain_idx));
 
-	for (i = 0; i < hd->ioc->req_depth; i++) {
-		if (hd->ScsiLookup[i] == sc) {
-			mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
-			return mf->u.frame.hwhdr.msgctxu.MsgContext;
-		}
+		/* handle next */
+		chain_idx = next;
 	}
-
-	return -1;
+	return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	Reset Handling
+ */
 
-/* see mptscsih.h */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_TMHandler - Generic handler for SCSI Task Management.
+ *	Fall through to mpt_HardResetHandler if: not operational, too many
+ *	failed TM requests or handshake failure.
+ *
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@type: Task Management type
+ *	@target: Logical Target ID for reset (if appropriate)
+ *	@lun: Logical Unit for reset (if appropriate)
+ *	@ctx2abort: Context for the task to be aborted (if appropriate)
+ *	@sleepFlag: If set, use udelay instead of schedule in handshake code.
+ *
+ *	Remark: Currently invoked from a non-interrupt thread (_bh).
+ *
+ *	Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
+ *	will be active.
+ *
+ *	Returns 0 for SUCCESS or -1 if FAILED.
+ */
+static int
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag)
+{
+	MPT_ADAPTER	*ioc = NULL;
+	int		 rc = -1;
+	int		 doTask = 1;
+	u32		 ioc_raw_state;
+	unsigned long	 flags;
 
-#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
-	static Scsi_Host_Template driver_template = MPT_SCSIHOST;
-#	include "../../scsi/scsi_module.c"
+	/* If FW is being reloaded currently, return success to
+	 * the calling function.
+	 */
+	if (!hd)
+		return 0;
+
+	ioc = hd->ioc;
+	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
+
+	if (ioc == NULL) {
+		printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
+		return 0;
+	}
+
+	// SJR - CHECKME - Can we avoid this here?
+	// (mpt_HardResetHandler has this check...)
+	spin_lock_irqsave(&ioc->diagLock, flags);
+	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
+		spin_unlock_irqrestore(&ioc->diagLock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+	/* Do not do a Task Management if there are
+	 * too many failed TMs on this adapter.
+	 */
+	if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM)
+		doTask = 0;
+
+	/* Is operational?
+	 */
+	ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
+
+#ifdef MPT_DEBUG_RESET
+	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+		printk(MYIOC_s_WARN_FMT 
+			"TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", 
+			hd->ioc->name, ioc_raw_state);
+	}
 #endif
 
+	if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
+				&& !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
+
+		/* Isse the Task Mgmt request.
+		 */
+		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
+		if (rc) {
+			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
+		} else {
+			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name);
+		}
+	}
+#ifdef DROP_TEST
+	numTMrequested++;
+	if (numTMrequested > 5) {
+		rc = 0;		/* set to 1 to force a hard reset */
+		numTMrequested = 0;
+	}
+#endif
+
+	if (rc) {
+		dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
+			 hd->ioc->name));
+		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
+	}
+
+	dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
+#ifndef MPT_SCSI_USE_NEW_EH
+	dtmprintk((MYIOC_s_INFO_FMT "TMHandler: _bh_handler state (%d) taskQ count (%d)\n",
+		ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+#endif
+
+	return rc;
+}
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
+ *	@hd: Pointer to MPT_SCSI_HOST structure
+ *	@type: Task Management type
+ *	@target: Logical Target ID for reset (if appropriate)
+ *	@lun: Logical Unit for reset (if appropriate)
+ *	@ctx2abort: Context for the task to be aborted (if appropriate)
+ *	@sleepFlag: If set, use udelay instead of schedule in handshake code.
+ *
+ *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *	or a non-interrupt thread.  In the former, must not call schedule().
+ *
+ *	Not all fields are meaningfull for all task types.
+ *
+ *	Returns 0 for SUCCESS, -999 for "no msg frames",
+ *	else other non-zero value returned.
+ */
 static int
-mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag)
 {
-	dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to SCSI host driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+	MPT_FRAME_HDR	*mf;
+	SCSITaskMgmt_t	*pScsiTm;
+	int		 ii;
+	int		 retval = 0;
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
-		/* FIXME! Do pre-reset cleanup */
-	} else {
-		/* FIXME! Do post-reset cleanup */
+	/* Return Fail to calling function if no message frames available.
+	 */
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+		dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+				hd->ioc->name));
+		//return FAILED;
+		return -999;
 	}
+	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+			hd->ioc->name, mf));
 
-	return 1;		/* currently means nothing really */
+	/* Format the Request
+	 */
+	pScsiTm = (SCSITaskMgmt_t *) mf;
+	pScsiTm->TargetID = target;
+	pScsiTm->Bus = hd->port;
+	pScsiTm->ChainOffset = 0;
+	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+	pScsiTm->Reserved = 0;
+	pScsiTm->TaskType = type;
+	pScsiTm->Reserved1 = 0;
+	pScsiTm->MsgFlags = 0;
+
+	for (ii= 0; ii < 8; ii++) {
+		pScsiTm->LUN[ii] = 0;
+	}
+	pScsiTm->LUN[1] = lun;
+
+	for (ii=0; ii < 7; ii++)
+		pScsiTm->Reserved2[ii] = 0;
+
+	pScsiTm->TaskMsgContext = ctx2abort;
+	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n",
+			hd->ioc->name, ctx2abort, type));
+
+	/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+		mpt_put_msg_frame(hd->ioc->id, mf);
+	* Save the MF pointer in case the request times out.
+	*/
+	hd->tmPtr = mf;
+	hd->numTMrequests++;
+	hd->TMtimer.expires = jiffies + HZ*20;  /* 20 seconds */
+	add_timer(&hd->TMtimer);
+
+	if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
+				sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag))
+	!= 0) {
+		dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"
+			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf));
+		hd->numTMrequests--;
+		hd->tmPtr = NULL;
+		del_timer(&hd->TMtimer);
+		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+		return ii;
+	}
+
+	return retval;
 }
 
+#ifdef MPT_SCSI_USE_NEW_EH		/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int
-mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+/**
+ *	mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *	(linux Scsi_Host_Template.eh_abort_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_abort(Scsi_Cmnd * SCpnt)
 {
-	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+	MPT_SCSI_HOST	*hd;
+	MPT_FRAME_HDR	*mf;
+	unsigned long	 flags;
+	u32		 ctx2abort;
+	int		 scpnt_idx;
+	u8		 type;
 
-	dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event));
+	printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO (=%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
 
-	switch (event) {
-	case MPI_EVENT_UNIT_ATTENTION:			/* 03 */
-		/* FIXME! */
-		break;
-	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
-		/* FIXME! */
-		break;
-	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
-		/* FIXME! */
-		break;
-	case MPI_EVENT_LOGOUT:				/* 09 */
-		/* FIXME! */
-		break;
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
 
-		/*
-		 *  CHECKME! Don't think we need to do
-		 *  anything for these, but...
+	/* Find this command
+	 */
+	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+		/* Cmd not found in ScsiLookup. If found in 
+		 * doneQ, delete from Q. Do OS callback.
 		 */
-	case MPI_EVENT_RESCAN:				/* 06 */
-	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
-	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
-		/*
-		 *  CHECKME!  Falling thru...
+		search_doneQ_for_cmd(hd, SCpnt);
+
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
+
+	/* If this command is pended, then timeout/hang occurred
+	 * during DV. Post command and flush pending Q 
+	 * and then following up with the reset request.
+	 */
+	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		post_pendingQ_commands(hd);
+	}
+
+	/* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+	 * (the IO to be ABORT'd)
+	 *
+	 * NOTE: Since we do not byteswap MsgContext, we do not
+	 *	 swap it here either.  It is an opaque cookie to
+	 *	 the controller, so it does not matter. -DaveM
+	 */
+	mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
+
+	/* This thread will not exit until tmPending is cleared
+	 * FIXME - must ensure single threaded....DV conflict possible
+	 */
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	hd->tmPending = 1;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	if (hd->is_spi)
+		type = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	else {
+		type = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+		hd->abortSCpnt = SCpnt;
+		printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (sc=%p)\n", SCpnt);
+	}
+
+	if (mptscsih_TMHandler(hd, type,
+			SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) < 0) {
+
+		/* The TM request failed and the subsequent FW-reload failed!
+		 * Fatal error case.
 		 */
+		printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
+				hd->ioc->name, SCpnt);
 
-	case MPI_EVENT_NONE:				/* 00 */
-	case MPI_EVENT_LOG_DATA:			/* 01 */
-	case MPI_EVENT_STATE_CHANGE:			/* 02 */
-	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
-	default:
-		dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event));
-		break;
+		/* If command not found, do not do callback,
+		 *  just return failed.  CHECKME 
+		 */
+		if (hd->ScsiLookup[scpnt_idx] != NULL) {
+			//atomic_dec(&queue_depth);
+			SCpnt->result = STS_BUSY;
+			spin_lock_irqsave(&io_request_lock, flags);
+			SCpnt->scsi_done(SCpnt);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+		}
+
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		hd->tmPending = 0;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 	}
 
-	return 1;		/* currently means nothing really */
+
+	/* Spin on tmPending until we get the interrupt for this TM request.
+	 */
+	while (1) {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		if (!hd->tmPending) {
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/4);
+	}
+
+	return FAILED;
 }
 
-#if 0		/* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+/**
+ *	mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
  *
- *	drivers/message/fusion/scsiherr.c
+ *	(linux Scsi_Host_Template.eh_dev_reset_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
  */
+int
+mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
+{
+	MPT_SCSI_HOST	*hd;
+	MPT_FRAME_HDR	*mf;
+	unsigned long	 flags;
+	int		 scpnt_idx;
+	u8		 type;
 
-//extern const char	**mpt_ScsiOpcodesPtr;	/* needed by mptscsih.c */
-//extern ASCQ_Table_t	 *mpt_ASCQ_TablePtr;
-//extern int		  mpt_ASCQ_TableSz;
+	printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
 
-/*  Lie!  */
-#define MYNAM	"mptscsih"
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
 
-#endif		/* } */
+	/* Find this command
+	 */
+	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+		/* Cmd not found in ScsiLookup. If found in 
+		 * doneQ, delete from Q. Do OS callback.
+		 */
+		search_doneQ_for_cmd(hd, SCpnt);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Private data...
- */
-static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
+
+	/* If this command is pended, then timeout/hang occurred
+	 * during DV. Force bus reset by posting command to F/W
+	 * and then following up with the reset request.
+	 */
+	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		post_pendingQ_commands(hd);
+	}
+
+	/* This thread will not exit until tmPending is cleared
+	 */
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	hd->tmPending = 1;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	if (hd->is_spi)
+		type = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	else {
+		type = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+		printk(KERN_WARNING MYNAM ": Attempting Target Reset! (sc=%p)\n", SCpnt);
+	}
+
+	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+				SCpnt->target, 0, 0, CAN_SLEEP) < 0) {
+		/* The TM request failed and the subsequent FW-reload failed!
+		 * Fatal error case.
+		 */
+		printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
+		 		hd->ioc->name, SCpnt);
+
+		/* If command not found, do not do callback,
+		 * just returned failed. CHECKME.
+		 */
+		if (hd->ScsiLookup[scpnt_idx] != NULL) {
+			//atomic_dec(&queue_depth);
+			SCpnt->result = STS_BUSY;
+			spin_lock_irqsave(&io_request_lock, flags);
+			SCpnt->scsi_done(SCpnt);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+		}
+
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		hd->tmPending = 0;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	}
+
+	/* Spin on tmPending until we get the interrupt for this TM request.
+	 */
+	while (1) {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		if (!hd->tmPending) {
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/4);
+	}
+
+	//return SUCCESS;
+	return FAILED;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* old symsense.c stuff... */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Private data...
- * To protect ourselves against those that would pass us bogus pointers
+/**
+ *	mptscsih_bus_reset - Perform a SCSI BUS_RESET!	new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *	(linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
  */
-static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
-    = { 0x1F, 0x00, 0x00, 0x00,
-	0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
-    = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00 };
-static u8 dummyCDB[16]
-    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static u8 dummyScsiData[16]
-    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+int
+mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+{
+	MPT_SCSI_HOST	*hd;
+	MPT_FRAME_HDR	*mf;
+	unsigned long	 flags;
+	int		 scpnt_idx;
 
-#if 0
-static const char *PeripheralDeviceTypeString[32] = {
-	"Direct-access",		/* 00h */
-	"Sequential-access",		/* 01h */
-	"Printer",			/* 02h */
-	"Processor",			/* 03h */
-			/*"Write-Once-Read-Multiple",*/	/* 04h */
-	"WORM",				/* 04h */
-	"CD-ROM",			/* 05h */
-	"Scanner",			/* 06h */
-	"Optical memory",		/* 07h */
-	"Media Changer",		/* 08h */
-	"Communications",		/* 09h */
-	"(Graphics arts pre-press)",	/* 0Ah */
-	"(Graphics arts pre-press)",	/* 0Bh */
-	"Array controller",		/* 0Ch */
-	"Enclosure services",		/* 0Dh */
-	"Simplified direct-access",	/* 0Eh */
-	"Reserved-0Fh",			/* 0Fh */
-	"Reserved-10h",			/* 10h */
-	"Reserved-11h",			/* 11h */
-	"Reserved-12h",			/* 12h */
-	"Reserved-13h",			/* 13h */
-	"Reserved-14h",			/* 14h */
-	"Reserved-15h",			/* 15h */
-	"Reserved-16h",			/* 16h */
-	"Reserved-17h",			/* 17h */
-	"Reserved-18h",			/* 18h */
-	"Reserved-19h",			/* 19h */
-	"Reserved-1Ah",			/* 1Ah */
-	"Reserved-1Bh",			/* 1Bh */
-	"Reserved-1Ch",			/* 1Ch */
-	"Reserved-1Dh",			/* 1Dh */
-	"Reserved-1Eh",			/* 1Eh */
-	"Unknown"			/* 1Fh */
-};
-#endif
+	printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
 
-static char *ScsiStatusString[] = {
-	"GOOD",					/* 00h */
-	NULL,					/* 01h */
-	"CHECK CONDITION",			/* 02h */
-	NULL,					/* 03h */
-	"CONDITION MET",			/* 04h */
-	NULL,					/* 05h */
-	NULL,					/* 06h */
-	NULL,					/* 07h */
-	"BUSY",					/* 08h */
-	NULL,					/* 09h */
-	NULL,					/* 0Ah */
-	NULL,					/* 0Bh */
-	NULL,					/* 0Ch */
-	NULL,					/* 0Dh */
-	NULL,					/* 0Eh */
-	NULL,					/* 0Fh */
-	"INTERMEDIATE",				/* 10h */
-	NULL,					/* 11h */
-	NULL,					/* 12h */
-	NULL,					/* 13h */
-	"INTERMEDIATE-CONDITION MET",		/* 14h */
-	NULL,					/* 15h */
-	NULL,					/* 16h */
-	NULL,					/* 17h */
-	"RESERVATION CONFLICT",			/* 18h */
-	NULL,					/* 19h */
-	NULL,					/* 1Ah */
-	NULL,					/* 1Bh */
-	NULL,					/* 1Ch */
-	NULL,					/* 1Dh */
-	NULL,					/* 1Eh */
-	NULL,					/* 1Fh */
-	NULL,					/* 20h */
-	NULL,					/* 21h */
-	"COMMAND TERMINATED",			/* 22h */
-	NULL,					/* 23h */
-	NULL,					/* 24h */
-	NULL,					/* 25h */
-	NULL,					/* 26h */
-	NULL,					/* 27h */
-	"TASK SET FULL",			/* 28h */
-	NULL,					/* 29h */
-	NULL,					/* 2Ah */
-	NULL,					/* 2Bh */
-	NULL,					/* 2Ch */
-	NULL,					/* 2Dh */
-	NULL,					/* 2Eh */
-	NULL,					/* 2Fh */
-	"ACA ACTIVE",				/* 30h */
-	NULL
-};
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
 
-static const char *ScsiCommonOpString[] = {
-	"TEST UNIT READY",			/* 00h */
-	"REZERO UNIT (REWIND)",			/* 01h */
-	NULL,					/* 02h */
-	"REQUEST_SENSE",			/* 03h */
-	"FORMAT UNIT (MEDIUM)",			/* 04h */
-	"READ BLOCK LIMITS",			/* 05h */
-	NULL,					/* 06h */
-	"REASSIGN BLOCKS",			/* 07h */
-	"READ(6)",				/* 08h */
-	NULL,					/* 09h */
-	"WRITE(6)",				/* 0Ah */
-	"SEEK(6)",				/* 0Bh */
-	NULL,					/* 0Ch */
-	NULL,					/* 0Dh */
-	NULL,					/* 0Eh */
-	"READ REVERSE",				/* 0Fh */
-	"WRITE_FILEMARKS",			/* 10h */
-	"SPACE(6)",				/* 11h */
-	"INQUIRY",				/* 12h */
-	NULL
-};
+	/* Find this command
+	 */
+	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+		/* Cmd not found in ScsiLookup. If found in 
+		 * doneQ, delete from Q. Do OS callback.
+		 */
+		search_doneQ_for_cmd(hd, SCpnt);
 
-static const char *SenseKeyString[] = {
-	"NO SENSE",				/* 0h */
-	"RECOVERED ERROR",			/* 1h */
-	"NOT READY",				/* 2h */
-	"MEDIUM ERROR",				/* 3h */
-	"HARDWARE ERROR",			/* 4h */
-	"ILLEGAL REQUEST",			/* 5h */
-	"UNIT ATTENTION",			/* 6h */
-	"DATA PROTECT",				/* 7h */
-	"BLANK CHECK",				/* 8h */
-	"VENDOR-SPECIFIC",			/* 9h */
-	"ABORTED COPY",				/* Ah */
-	"ABORTED COMMAND",			/* Bh */
-	"EQUAL (obsolete)",			/* Ch */
-	"VOLUME OVERFLOW",			/* Dh */
-	"MISCOMPARE",				/* Eh */
-	"RESERVED",				/* Fh */
-	NULL
-};
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
 
-#define SPECIAL_ASCQ(c,q) \
-	(((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+	/* If this command is pended, then timeout/hang occurred
+	 * during DV. Force bus reset by posting command to F/W
+	 * and then following up with the reset request.
+	 */
+	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		post_pendingQ_commands(hd);
+	}
+
+	/* This thread will not exit until tmPending is cleared
+	 */
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	hd->tmPending = 1;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+						0, 0, 0, CAN_SLEEP) < 0) {
+
+		/* The TM request failed and the subsequent FW-reload failed!
+		 * Fatal error case.
+		 */
+		printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
+		 		hd->ioc->name, SCpnt);
+
+		/* If command not found, do not do callback,
+		 * just returned failed. CHECKME.
+		 */
+		if (hd->ScsiLookup[scpnt_idx] != NULL) {
+			//atomic_dec(&queue_depth);
+			SCpnt->result = STS_BUSY;
+			spin_lock_irqsave(&io_request_lock, flags);
+			SCpnt->scsi_done(SCpnt);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+		}
+
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		hd->tmPending = 0;
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+		return FAILED;
+	}
+
+	/* Spin on tmPending until we get the interrupt for this TM request.
+	 */
+	while (1) {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		if (!hd->tmPending) {
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/4);
+	}
+
+	return SUCCESS;
+}
 
 #if 0
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
- *			   then print additional information via
- *			   a call to SDMS_SystemAlert().
+/**
+ *	mptscsih_host_reset - Perform a SCSI host adapter RESET!
+ *	new_eh variant
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
  *
- *  Return: nothing
+ *	(linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *
+ *	Returns SUCCESS or FAILED.
  */
-static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+int
+mptscsih_host_reset(Scsi_Cmnd *SCpnt)
 {
-	u8	*sd;
-	u8	 BadValue;
-	u8	 SenseKey;
-	int	 Offset;
-	int	 len = strlen(msg1);
+	MPT_SCSI_HOST	*hd;
+	MPT_FRAME_HDR	*mf;
 
-	sd = ioop->sensePtr;
-	if (SD_Additional_Sense_Length(sd) < 8)
-		return;
+	printk(KERN_WARNING MYNAM ": Attempting HOST_RESET (%p)\n", SCpnt);
+	printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
 
-	SenseKey = SD_Sense_Key(sd);
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	}
+
+	/* If this command is pended, then timeout/hang occurred
+	 * during DV. Force bus reset by posting command to F/W
+	 * and then following up with the reset request.
+	 */
+	if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		post_pendingQ_commands(hd);
+	}
+
+	/* This thread will not exit until tmPending is cleared
+	 */
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	hd->tmPending = 1;
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
+		SCpnt->result = STS_BUSY;
+		spin_lock_irqsave(&io_request_lock, flags);		// sjr-added
+		SCpnt->scsi_done(SCpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);	// sjr-added
+		return FAILED;
+	}
+
+	/* Spin on tmPending until we get the interrupt for this TM request.
+	 */
+	while (1) {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		if (!hd->tmPending) {
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/4);
+	}
+
+	return SUCCESS;
+}
+#endif
+
+#else		/* MPT_SCSI old EH stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_old_abort - Abort linux Scsi_Cmnd routine
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *	(linux Scsi_Host_Template.abort routine)
+ *
+ *	Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ */
+int
+mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+{
+	MPT_SCSI_HOST		*hd;
+	MPT_FRAME_HDR		*mf;
+	struct tq_struct	*ptaskfoo;
+	unsigned long		 flags;
+	int			 scpnt_idx;
+
+	printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", SCpnt);
+	printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		printk(KERN_WARNING "  WARNING - OldAbort, NULL hostdata ptr!!\n");
+		SCpnt->result = DID_ERROR << 16;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_ABORT_NOT_RUNNING;
+	}
+
+	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+		/* Cmd not found in ScsiLookup.
+		 * If found in doneQ, delete from Q.
+		 * Do OS callback.
+		 */
+		search_doneQ_for_cmd(hd, SCpnt);
+
+		SCpnt->result = DID_RESET << 16;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_ABORT_SUCCESS;
+	} else {
+		/* If this command is pended, then timeout/hang occurred
+		 * during DV. Force bus reset by posting command to F/W
+		 * and then following up with the reset request.
+		 */
+		if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+			post_pendingQ_commands(hd);
+		}
+	}
+
+	/*
+	 *  Check to see if there's already an ABORT queued for this guy.
+	 */
+	mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+	if (mf != NULL) {
+		dtmprintk((MYIOC_s_INFO_FMT "OldAbort:Abort Task PENDING cmd (%p) taskQ depth (%d)\n",
+			hd->ioc->name, SCpnt, hd->taskQcnt));
+		return SCSI_ABORT_PENDING;
+	}
+
+	// SJR - CHECKME - Can we avoid this here?
+	// (mpt_HardResetHandler has this check...)
+	/* If IOC is reloading FW, return PENDING.
+	 */
+	spin_lock_irqsave(&hd->ioc->diagLock, flags);
+	if (hd->ioc->diagPending) {
+		spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+		return SCSI_ABORT_PENDING;
+	}
+	spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+
+	/* If there are no message frames what should we do?
+	 */
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+		printk((KERN_WARNING "  WARNING - OldAbort, no msg frames!!\n"));
+		/* We are out of message frames!
+		 * Call the reset handler to do a FW reload.
+		 */
+		printk((KERN_WARNING " Reloading Firmware!!\n"));
+		if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+			printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+		}
+		return SCSI_ABORT_PENDING;
+	}
+
+	/*
+	 *  Add ourselves to (end of) taskQ .
+	 *  Check to see if our _bh is running.  If NOT, schedule it.
+	 */
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+	hd->taskQcnt++;
+	atomic_inc(&mpt_taskQdepth);
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	spin_lock_irqsave(&mytaskQ_lock, flags);
+
+	/* Save the original SCpnt mf pointer
+	 */
+	SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
+
+	/* For the time being, force bus reset on any abort
+	 * requests for the 1030 FW.
+	 */
+	if (hd->is_spi)
+		mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	else
+		mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+
+	mf->u.frame.linkage.argp1 = SCpnt;
+	mf->u.frame.linkage.argp2 = (void *) hd;
+
+	dtmprintk((MYIOC_s_INFO_FMT "OldAbort:_bh_handler state (%d) taskQ count (%d)\n",
+		hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+	if (! mytaskQ_bh_active) {
+		mytaskQ_bh_active = 1;
+		/*
+		 *  Oh how cute, no alloc/free/mgmt needed if we use
+		 *  (bottom/unused portion of) MPT request frame.
+		 */
+		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
+		ptaskfoo->sync = 0;
+		ptaskfoo->routine = mptscsih_taskmgmt_bh;
+		ptaskfoo->data = SCpnt;
+
+		SCHEDULE_TASK(ptaskfoo);
+	}
+	spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+	return SCSI_ABORT_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_old_reset - Perform a SCSI BUS_RESET!
+ *	@SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *	@reset_flags: (not used?)
+ *
+ *	(linux Scsi_Host_Template.reset routine)
+ *
+ *	Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
+ */
+int
+mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+	MPT_SCSI_HOST		*hd;
+	MPT_FRAME_HDR		*mf;
+	struct tq_struct	*ptaskfoo;
+	unsigned long		 flags;
+	int			 scpnt_idx;
+
+	printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", SCpnt);
+	printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+		SCpnt->result = DID_RESET << 16;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_RESET_SUCCESS;
+	}
+
+	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+		/* Cmd not found in ScsiLookup.
+		 * If found in doneQ, delete from Q.
+		 * Do OS callback.
+		 */
+		search_doneQ_for_cmd(hd, SCpnt);
+
+		SCpnt->result = DID_RESET << 16;
+		SCpnt->scsi_done(SCpnt);
+		return SCSI_RESET_SUCCESS;
+	} else {
+		/* If this command is pended, then timeout/hang occurred
+		 * during DV. Force bus reset by posting command to F/W
+		 * and then following up with the reset request.
+		 */
+		if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+			post_pendingQ_commands(hd);
+		}
+	}
+
+	/*
+	 *  Check to see if there's an ABORT_TASK queued for this guy.
+	 *  If so, delete.
+	 */
+	search_taskQ(1, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+
+	/*
+	 *  Check to see if there's already a BUS_RESET queued for this guy.
+	 */
+	mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
+	if (mf != NULL) {
+		dtmprintk((MYIOC_s_INFO_FMT "OldReset:Reset Task PENDING cmd (%p) taskQ depth (%d)\n",
+			hd->ioc->name, SCpnt, hd->taskQcnt));
+		return SCSI_RESET_PENDING;
+	}
+
+	// SJR - CHECKME - Can we avoid this here?
+	// (mpt_HardResetHandler has this check...)
+	/* If IOC is reloading FW, return PENDING.
+	 */
+	spin_lock_irqsave(&hd->ioc->diagLock, flags);
+	if (hd->ioc->diagPending) {
+		spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+		return SCSI_RESET_PENDING;
+	}
+	spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+
+	if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+		/* We are out of message frames!
+		 * Call the reset handler to do a FW reload.
+		 */
+		printk((KERN_WARNING " Reloading Firmware!!\n"));
+		if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+			printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+		}
+		return SCSI_RESET_PENDING;
+	}
+
+	/*
+	 *  Add ourselves to (end of) taskQ.
+	 *  Check to see if our _bh is running.  If NOT, schedule it.
+	 */
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+	hd->taskQcnt++;
+	atomic_inc(&mpt_taskQdepth);
+	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+	spin_lock_irqsave(&mytaskQ_lock, flags);
+
+	/* Save the original SCpnt mf pointer
+	 */
+	SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
+
+	mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+	mf->u.frame.linkage.argp1 = SCpnt;
+	mf->u.frame.linkage.argp2 = (void *) hd;
+
+	dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n",
+		hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+	if (! mytaskQ_bh_active) {
+		mytaskQ_bh_active = 1;
+		/*
+		 *  Oh how cute, no alloc/free/mgmt needed if we use
+		 *  (bottom/unused portion of) MPT request frame.
+		 */
+		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
+		ptaskfoo->sync = 0;
+		ptaskfoo->routine = mptscsih_taskmgmt_bh;
+		ptaskfoo->data = SCpnt;
+
+		SCHEDULE_TASK(ptaskfoo);
+	}
+	spin_unlock_irqrestore(&mytaskQ_lock, flags);
+	return SCSI_RESET_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
+ *	@sc: (unused)
+ *
+ *	This routine (thread) is active whenever there are any outstanding
+ *	SCSI task management requests for a SCSI host adapter.
+ *	IMPORTANT!  This routine is scheduled therefore should never be
+ *	running in ISR context.  i.e., it's safe to sleep here.
+ */
+void
+mptscsih_taskmgmt_bh(void *sc)
+{
+	MPT_ADAPTER	*ioc;
+	Scsi_Cmnd	*SCpnt;
+	MPT_FRAME_HDR	*mf = NULL;
+	MPT_SCSI_HOST	*hd;
+	u32		 ctx2abort = 0;
+	unsigned long	 flags;
+	int		 scpnt_idx;
+	int		 did;
+	u8		 task_type;
+
+	spin_lock_irqsave(&mytaskQ_lock, flags);
+	mytaskQ_bh_active = 1;
+	spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/4);
+		did = 0;
+
+		for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+			if (ioc->sh) {
+				hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+				if (hd == NULL) {
+					printk(KERN_ERR MYNAM
+							": ERROR - TaskMgmt NULL SCSI Host!"
+							"(ioc=%p, sh=%p hd=%p)\n",
+							ioc, ioc->sh, hd);
+					continue;
+				}
+
+				spin_lock_irqsave(&ioc->FreeQlock, flags);
+				if (Q_IS_EMPTY(&hd->taskQ)) {
+					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+					continue;
+				}
+
+				/* If we ever find a non-empty queue,
+				 * keep the handler alive
+				 */
+				did++;
+
+				/* tmPending is SMP lock-protected */
+				if (hd->tmPending || hd->tmPtr) {
+					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+					continue;
+				}
+				hd->tmPending = 1;
+
+				/* Process this request
+				 */
+                                mf = hd->taskQ.head;
+				Q_DEL_ITEM(&mf->u.frame.linkage);
+				hd->taskQcnt--;
+				atomic_dec(&mpt_taskQdepth);
+				spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+				SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
+				if (SCpnt == NULL) {
+					printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (mf=%p:sc=%p)\n",
+							mf, SCpnt);
+					mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+					spin_lock_irqsave(&ioc->FreeQlock, flags);
+					hd->tmPending = 0;
+					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+					continue;
+				}
+
+				/* Get the ScsiLookup index pointer
+				 * from the SC pointer.
+				 */
+				if (!SCpnt->host_scribble || ((MPT_SCSI_HOST *)SCpnt->host->hostdata != hd)) {
+					/* The command associated with the
+					 * abort/reset request must have
+					 * completed and this is a stale
+					 * request. We are done.
+					 * Free the current MF and continue.
+					 */
+					mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+					spin_lock_irqsave(&ioc->FreeQlock, flags);
+					hd->tmPending = 0;
+					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+					continue;
+				}
+
+				scpnt_idx = MFPTR_2_MPT_INDEX(hd->ioc, SCpnt->host_scribble);
+				if (scpnt_idx != SCPNT_TO_LOOKUP_IDX(SCpnt)) {
+					/* Error! this should never happen!!
+					 */
+					mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+					spin_lock_irqsave(&ioc->FreeQlock, flags);
+					hd->tmPending = 0;
+					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+					continue;
+				}
+
+				task_type = mf->u.frame.linkage.arg1;
+				ctx2abort = 0;
+				if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+					MPT_FRAME_HDR	*SCpntMf;
+
+					/*
+					 * Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+					 * (the IO to be ABORT'd)
+					 *
+					 * NOTE: Since we do not byteswap MsgContext, we do not
+					 *	 swap it here either.  It is an opaque cookie to
+					 *	 the controller, so it does not matter. -DaveM
+					 */
+					SCpntMf = (MPT_FRAME_HDR *) SCpnt->host_scribble;
+					ctx2abort = SCpntMf->u.frame.hwhdr.msgctxu.MsgContext;
+
+					hd->abortSCpnt = SCpnt;
+					printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (mf=%p:sc=%p)\n",
+							mf, SCpnt);
+				}
+
+				/* The TM handler will allocate a new mf,
+				 * so free the current mf.
+				 */
+				mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+				mf = NULL;
+
+				if (mptscsih_TMHandler(hd, task_type, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) < 0) {
+
+					/* The TM request failed and the subsequent FW-reload failed!
+					 * Fatal error case.
+					 */
+					printk(KERN_WARNING MYNAM
+						": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", SCpnt);
+
+					if (hd->ScsiLookup[scpnt_idx] != NULL) {
+						atomic_dec(&queue_depth);
+						SCpnt->result = DID_SOFT_ERROR << 16;
+						spin_lock_irqsave(&io_request_lock, flags);
+						SCpnt->scsi_done(SCpnt);
+						spin_unlock_irqrestore(&io_request_lock, flags);
+						mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+					}
+					spin_lock_irqsave(&ioc->FreeQlock, flags);
+					hd->tmPending = 0;
+					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+					hd->abortSCpnt = NULL;
+				}
+			}
+		}
+		if (atomic_read(&mpt_taskQdepth) > 0)
+			did++;
+
+	} while ( did );
+
+	spin_lock_irqsave(&mytaskQ_lock, flags);
+	mytaskQ_bh_active = 0;
+	spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+	return;
+}
+#endif		/* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mf: Pointer to SCSI task mgmt request frame
+ *	@mr: Pointer to SCSI task mgmt reply frame
+ *
+ *	This routine is called from mptbase.c::mpt_interrupt() at the completion
+ *	of any SCSI task management request.
+ *	This routine is registered with the MPT (base) driver at driver
+ *	load/init time via the mpt_register() API call.
+ *
+ *	Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+	SCSITaskMgmtReply_t	*pScsiTmReply;
+	SCSITaskMgmt_t		*pScsiTmReq;
+	MPT_SCSI_HOST		*hd = NULL;
+	unsigned long		 flags;
+	u8			 tmType = 0;
+
+	dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n",
+			ioc->name, mf, mr));
+	if (ioc->sh) {
+		/* Depending on the thread, a timer is activated for
+		 * the TM request.  Delete this timer on completion of TM.
+		 * Decrement count of outstanding TM requests.
+		 */
+		hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+		if (hd->tmPtr) {
+			del_timer(&hd->TMtimer);
+		}
+		dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n",
+			ioc->name, hd->taskQcnt));
+	} else {
+		dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
+			ioc->name));
+		return 1;
+	}
+
+	if (mr == NULL) {
+		dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
+			ioc->name, mf));
+		return 1;
+	} else {
+		pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
+		pScsiTmReq = (SCSITaskMgmt_t*)mf;
+
+		/* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
+		tmType = pScsiTmReq->TaskType;
+
+		dtmprintk((KERN_INFO "  TaskType = %d, TerminationCount=%d\n",
+				tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+		/* Error?  (anything non-zero?) */
+		if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
+			u16	 iocstatus;
+
+			iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+			dtmprintk((KERN_INFO "  SCSI TaskMgmt (%d) - Oops!\n", tmType));
+			dtmprintk((KERN_INFO "  IOCStatus = %04xh\n", iocstatus));
+			dtmprintk((KERN_INFO "  IOCLogInfo = %08xh\n",
+				 le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+
+			/* clear flags and continue.
+			 */
+			if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+				hd->abortSCpnt = NULL;
+#ifdef	DROP_TEST
+			if (dropMfPtr)
+				dropTestBad++;
+#endif
+			/* If an internal command is present
+			 * or the TM failed - reload the FW.
+			 * FC FW may respond FAILED to an ABORT
+			 */
+			if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+				if ((hd->cmdPtr) ||
+				    (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
+					if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+						printk((KERN_WARNING
+							" Firmware Reload FAILED!!\n"));
+					}
+				}
+			}
+		} else {
+			dtmprintk((KERN_INFO "  SCSI TaskMgmt SUCCESS!\n"));
+
+#ifndef MPT_SCSI_USE_NEW_EH
+			if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+				/* clean taskQ - remove tasks associated with
+				 * completed commands.
+				 */
+				clean_taskQ(hd);
+			} else if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+				/* If taskQ contains another request
+				 * for this SCpnt, delete this request.
+				 */
+				search_taskQ_for_cmd(hd->abortSCpnt, hd);
+			}
+#endif
+			hd->numTMrequests--;
+			hd->abortSCpnt = NULL;
+			flush_doneQ(hd);
+
+#ifdef	DROP_TEST
+			if (dropMfPtr)
+				dropTestOK++;
+#endif
+		}
+	}
+
+#ifdef	DROP_TEST
+	{
+		Scsi_Cmnd	*sc;
+		unsigned long	 flags;
+		u16		 req_idx;
+
+		/* Free resources for the drop test MF and chain buffers.
+		 */
+		if (dropMfPtr) {
+			req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
+			sc = hd->ScsiLookup[req_idx];
+			if (sc == NULL) {
+				printk(MYIOC_s_ERR_FMT
+					"Drop Test: NULL ScsiCmd ptr!\n",
+					ioc->name);
+			} else {
+				sc->host_scribble = NULL;
+				if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+					sc->result = DID_RESET << 16;
+				else
+					sc->result = DID_ABORT << 16;
+
+				hd->ScsiLookup[req_idx] = NULL;
+				atomic_dec(&queue_depth);
+				spin_lock_irqsave(&io_request_lock, flags);
+				sc->scsi_done(sc);	/* Issue callback */
+				spin_unlock_irqrestore(&io_request_lock, flags);
+
+				mptscsih_freeChainBuffers(hd, req_idx);
+				mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
+
+				printk(MYIOC_s_INFO_FMT
+						"Free'd Dropped cmd (%p)\n",
+						hd->ioc->name, sc);
+				printk(MYIOC_s_INFO_FMT
+						"mf (%p) reqidx (%4x)\n",
+						hd->ioc->name, dropMfPtr,
+						req_idx);
+				printk(MYIOC_s_INFO_FMT
+					"Num Tot (%d) Good (%d) Bad (%d) \n",
+					hd->ioc->name, dropTestNum,
+					dropTestOK, dropTestBad);
+			}
+			dropMfPtr = NULL;
+		}
+	}
+#endif
+
+#ifndef MPT_SCSI_USE_NEW_EH
+	/*
+	 *  Signal to _bh thread that we finished.
+	 *  This IOC can now process another TM command.
+	 */
+	dtmprintk((MYIOC_s_INFO_FMT "taskmgmt_complete: (=%p) done! Num Failed(%d) Task Count (%d)\n",
+			ioc->name, mf, hd->numTMrequests, hd->taskQcnt));
+#endif
+	hd->tmPtr = NULL;
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+	hd->tmPending = 0;
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+	return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	This is anyones guess quite frankly.
+ */
+
+int
+mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+	int size;
+
+	size = disk->capacity;
+	ip[0] = 64;				/* heads			*/
+	ip[1] = 32;				/* sectors			*/
+	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
+		ip[0] = 255;			/* heads			*/
+		ip[1] = 63;			/* sectors			*/
+		ip[2] = size / (255 * 63);	/* cylinders			*/
+	}
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	OS entry point to adjust the queue_depths on a per-device basis.
+ *	Called once per device the bus scan. Use it to force the queue_depth
+ *	member to 1 if a device does not support Q tags.
+ */
+void
+mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
+{
+	struct scsi_device	*device;
+	VirtDevice		*pTarget;
+	MPT_SCSI_HOST		*hd;
+	int			 ii, max;
+
+	for (device = sdList; device; device = device->next) {
+
+		if (device->host != sh)
+			continue;
+
+		hd = (MPT_SCSI_HOST *) sh->hostdata;
+		if (!hd)
+			continue;
+
+		if (hd->Targets) {
+			if (hd->is_spi)
+				max = MPT_MAX_SCSI_DEVICES;
+			else
+				max = MPT_MAX_FC_DEVICES;
+
+			for (ii=0; ii < max; ii++) {
+				pTarget = hd->Targets[ii];
+				if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
+					device->queue_depth = 1;
+				}
+			}
+		}
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ *  Return absolute SCSI data direction:
+ *     1 = _DATA_OUT
+ *     0 = _DIR_NONE
+ *    -1 = _DATA_IN
+ */
+static int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) {
+	/*  _DATA_OUT commands	*/
+	case WRITE_6:		case WRITE_10:		case WRITE_12:
+	case WRITE_LONG:	case WRITE_SAME:	case WRITE_BUFFER:
+	case WRITE_VERIFY:	case WRITE_VERIFY_12:
+	case COMPARE:		case COPY:		case COPY_VERIFY:
+	case SEARCH_EQUAL:	case SEARCH_HIGH:	case SEARCH_LOW:
+	case SEARCH_EQUAL_12:	case SEARCH_HIGH_12:	case SEARCH_LOW_12:
+	case MODE_SELECT:	case MODE_SELECT_10:	case LOG_SELECT:
+	case SEND_DIAGNOSTIC:	case CHANGE_DEFINITION: case UPDATE_BLOCK:
+	case SET_WINDOW:	case MEDIUM_SCAN:	case SEND_VOLUME_TAG:
+	case REASSIGN_BLOCKS:
+	case PERSISTENT_RESERVE_OUT:
+	case 0xea:
+	case 0xa3:
+		return 1;
+
+	/*  No data transfer commands  */
+	case SEEK_6:		case SEEK_10:
+	case RESERVE:		case RELEASE:
+	case TEST_UNIT_READY:
+	case START_STOP:
+	case ALLOW_MEDIUM_REMOVAL:
+		return 0;
+
+	/*  Conditional data transfer commands	*/
+	case FORMAT_UNIT:
+		if (cmd->cmnd[1] & 0x10)	/* FmtData (data out phase)? */
+			return 1;
+		else
+			return 0;
+
+	case VERIFY:
+		if (cmd->cmnd[1] & 0x02)	/* VERIFY:BYTCHK (data out phase)? */
+			return 1;
+		else
+			return 0;
+
+	case RESERVE_10:
+		if (cmd->cmnd[1] & 0x03)	/* RESERVE:{LongID|Extent} (data out phase)? */
+			return 1;
+		else
+			return 0;
+
+#if 0
+	case REZERO_UNIT:	/* (or REWIND) */
+	case SPACE:
+	case ERASE:		case ERASE_10:
+	case SYNCHRONIZE_CACHE:
+	case LOCK_UNLOCK_CACHE:
+#endif
+
+	/*  Must be data _IN!  */
+	default:
+		return -1;
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Utility function to copy sense data from the scsi_cmnd buffer
+ * to the FC and SCSI target structures.
+ *
+ */
+static void
+copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+{
+	VirtDevice	*target;
+	SCSIIORequest_t	*pReq;
+	u32		 sense_count = le32_to_cpu(pScsiReply->SenseCount);
+	int		 index;
+	char		 devFoo[96];
+	IO_Info_t	 thisIo;
+
+	/* Get target structure
+	 */
+	pReq = (SCSIIORequest_t *) mf;
+	index = (int) pReq->TargetID;
+	target = hd->Targets[index];
+	if (hd->is_multipath && sc->device->hostdata)
+		target = (VirtDevice *) sc->device->hostdata;
+
+	if (sense_count) {
+		u8 *sense_data;
+		int req_index;
+
+		/* Copy the sense received into the scsi command block. */
+		req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+		sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+
+		/* save sense data to the target device
+		 */
+		if (target) {
+			int sz;
+
+			sz = MIN(pReq->SenseBufferLength, sense_count);
+			if (sz > SCSI_STD_SENSE_BYTES)
+				sz =  SCSI_STD_SENSE_BYTES;
+			memcpy(target->sense, sense_data, sz);
+			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+		}
+
+		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
+		 */
+		if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
+			if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
+				int idx;
+				MPT_ADAPTER *ioc = hd->ioc;
+
+				idx = ioc->eventContext % ioc->eventLogSize;
+				ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
+				ioc->events[idx].eventContext = ioc->eventContext;
+
+				ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
+					(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
+					(pReq->Bus << 8) || pReq->TargetID;
+
+				ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
+
+				ioc->eventContext++;
+			}
+		}
+
+		/* Print an error report for the user.
+		 */
+		thisIo.cdbPtr = sc->cmnd;
+		thisIo.sensePtr = sc->sense_buffer;
+		thisIo.SCSIStatus = pScsiReply->SCSIStatus;
+		thisIo.DoDisplay = 1;
+		if (hd->is_multipath)
+			sprintf(devFoo, "%d:%d:%d \"%s\"",
+					hd->ioc->id,
+					pReq->TargetID,
+					pReq->LUN[1],
+					target->dev_vol_name);
+		else
+			sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->target, sc->lun);
+		thisIo.DevIDStr = devFoo;
+/* fubar */
+		thisIo.dataPtr = NULL;
+		thisIo.inqPtr = NULL;
+		if (sc->device) {
+			thisIo.inqPtr = sc->device->vendor-8;	/* FIXME!!! */
+		}
+		(void) mpt_ScsiHost_ErrorReport(&thisIo);
+
+	} else {
+		dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
+				hd->ioc->name));
+	}
+
+	return;
+}
+
+static u32
+SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc)
+{
+	MPT_SCSI_HOST *hd;
+	int i;
+
+	hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+
+	for (i = 0; i < hd->ioc->req_depth; i++) {
+		if (hd->ScsiLookup[i] == sc) {
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* see mptscsih.h */
+
+#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+	static Scsi_Host_Template driver_template = MPT_SCSIHOST;
+#	include "../../scsi/scsi_module.c"
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Search the pendingQ for a command with specific index.
+ * If found, delete and return mf pointer  
+ * If not found, return NULL
+ */
+static MPT_FRAME_HDR *
+mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx)
+{
+	unsigned long	 flags;
+	MPT_DONE_Q	*buffer;
+	MPT_FRAME_HDR	*mf = NULL;
+	MPT_FRAME_HDR	*cmdMfPtr = NULL;
+
+	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ called...", hd->ioc->name));
+	cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+	spin_lock_irqsave(&hd->freedoneQlock, flags);
+	if (!Q_IS_EMPTY(&hd->pendingQ)) {
+		buffer = hd->pendingQ.head;
+		do {
+			mf = (MPT_FRAME_HDR *) buffer->argp;
+			if (mf == cmdMfPtr) {
+				Q_DEL_ITEM(buffer);
+
+				/* clear the arg pointer
+				 */
+				buffer->argp = NULL;
+
+				/* Add to the freeQ
+				 */
+				Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+				break;
+			}
+			mf = NULL;
+		} while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ);
+	}
+	spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+	ddvtprintk((" ...return %p\n", mf));
+	return mf;
+}
+
+/* Post all commands on the pendingQ to the FW.
+ * Lock Q when deleting/adding members
+ * Lock io_request_lock for OS callback.
+ */
+static void
+post_pendingQ_commands(MPT_SCSI_HOST *hd)
+{
+	MPT_FRAME_HDR	*mf;
+	MPT_DONE_Q	*buffer;
+	unsigned long	 flags;
+
+	/* Flush the pendingQ.
+	 */
+	ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands called\n", hd->ioc->name));
+	while (1) {
+		spin_lock_irqsave(&hd->freedoneQlock, flags);
+		if (Q_IS_EMPTY(&hd->pendingQ)) {
+			spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			break;
+		}
+
+		buffer = hd->pendingQ.head;
+		/* Delete from Q
+		 */
+		Q_DEL_ITEM(buffer);
+
+		mf = (MPT_FRAME_HDR *) buffer->argp;
+		if (!mf) {
+			/* This should never happen */
+			printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, mf);
+			spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			continue;
+		}
+
+		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+		ddvtprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (mf=%p)\n",
+				hd->ioc->name, mf));
+
+		buffer->argp = NULL;
+
+		/* Add to the freeQ
+		 */
+		Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+		spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+	}
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+	MPT_SCSI_HOST	*hd = NULL;
+	unsigned long	 flags;
+
+	dtmprintk((KERN_WARNING MYNAM
+			": IOC %s_reset routed to SCSI host driver!\n",
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+	/* If a FW reload request arrives after base installed but
+	 * before all scsi hosts have been attached, then an alt_ioc
+	 * may have a NULL sh pointer.
+	 */
+	if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+		return 0;
+	else
+		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+	if (reset_phase == MPT_IOC_PRE_RESET) {
+		dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n",
+			ioc->name));
+
+		/* Clean Up:
+		 * 1. Set Hard Reset Pending Flag
+		 * All new commands go to doneQ
+		 */
+		hd->resetPending = 1;
+
+		/* 2. Flush running commands
+		 *	Clean drop test code - if compiled
+		 *	Clean ScsiLookup (and associated memory)
+		 *	AND clean mytaskQ
+		 */
+
+		/* 2a. Drop Test Command.
+		 */
+#ifdef	DROP_TEST
+		{
+			Scsi_Cmnd	*sc;
+			unsigned long	 flags;
+			u16		 req_idx;
+
+			/* Free resources for the drop test MF
+			 * and chain buffers.
+			 */
+			if (dropMfPtr) {
+				req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
+				sc = hd->ScsiLookup[req_idx];
+				if (sc == NULL) {
+					printk(MYIOC_s_ERR_FMT
+					"Drop Test: NULL ScsiCmd ptr!\n",
+					ioc->name);
+				} else {
+					sc->host_scribble = NULL;
+					sc->result = DID_RESET << 16;
+					hd->ScsiLookup[req_idx] = NULL;
+					atomic_dec(&queue_depth);
+					spin_lock_irqsave(&io_request_lock, flags);
+					sc->scsi_done(sc);	/* Issue callback */
+					spin_unlock_irqrestore(&io_request_lock, flags);
+				}
+
+				mptscsih_freeChainBuffers(hd, req_idx);
+				mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
+				printk(MYIOC_s_INFO_FMT
+						"Free'd: mf (%p) reqidx (%4x)\n",
+						hd->ioc->name, dropMfPtr,
+						req_idx);
+			}
+			dropMfPtr = NULL;
+		}
+#endif
+
+		/* 2b. Reply to OS all known outstanding I/O commands.
+		 */
+		mptscsih_flush_running_cmds(hd);
+
+		/* 2c. If there was an internal command that
+		 * has not completed, configuration or io request,
+		 * free these resources.
+		 */
+		if (hd->cmdPtr) {
+			del_timer(&hd->timer);
+			mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr);
+			atomic_dec(&queue_depth);
+		}
+
+		/* 2d. If a task management has not completed,
+		 * free resources associated with this request.
+		 */
+		if (hd->tmPtr) {
+			del_timer(&hd->TMtimer);
+			mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr);
+		}
+
+#ifndef MPT_SCSI_USE_NEW_EH
+		/* 2e. Delete all commands on taskQ
+		 * Should be superfluous - as this taskQ should
+		 * be empty.
+		 */
+		clean_taskQ(hd);
+#endif
+		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n",
+			ioc->name));
+
+	} else {
+		dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n",
+			ioc->name));
+
+		/* Once a FW reload begins, all new OS commands are
+		 * redirected to the doneQ w/ a reset status.
+		 * Init all control structures.
+		 */
+
+		/* ScsiLookup initialization
+		 */
+		{
+			int ii;
+			for (ii=0; ii < hd->ioc->req_depth; ii++)
+				hd->ScsiLookup[ii] = NULL;
+		}
+
+		/* 2. Chain Buffer initialization
+		 */
+		mptscsih_initChainBuffers(hd, 0);
+
+		/* 3. tmPtr clear
+		 */
+		if (hd->tmPtr) {
+			hd->tmPtr = NULL;
+		}
+
+		/* 4. Renegotiate to all devices, if SCSI
+		 */
+		if (hd->is_spi)
+			mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
+
+		/* 5. Enable new commands to be posted
+		 */
+		spin_lock_irqsave(&ioc->FreeQlock, flags);
+		hd->tmPending = 0;
+		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+		hd->resetPending = 0;
+		hd->numTMrequests = 0;
+
+		/* 6. If there was an internal command,
+		 * wake this process up.
+		 */
+		if (hd->cmdPtr) {
+			/*
+			 * Wake up the original calling thread
+			 */
+			hd->pLocal = &hd->localReply;
+			hd->pLocal->completion = MPT_SCANDV_DID_RESET;
+			scandv_wait_done = 1;
+			wake_up(&scandv_waitq);
+			hd->cmdPtr = NULL;
+		}
+
+		/* 7. Flush doneQ
+		 */
+		flush_doneQ(hd);
+
+		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
+			ioc->name));
+	}
+
+	return 1;		/* currently means nothing really */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+	MPT_SCSI_HOST *hd;
+	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+	dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+			ioc->name, event));
+
+	switch (event) {
+	case MPI_EVENT_UNIT_ATTENTION:			/* 03 */
+		/* FIXME! */
+		break;
+	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
+		/* FIXME! */
+		break;
+	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
+		/* FIXME! */
+		break;
+	case MPI_EVENT_LOGOUT:				/* 09 */
+		/* FIXME! */
+		break;
+
+		/*
+		 *  CHECKME! Don't think we need to do
+		 *  anything for these, but...
+		 */
+	case MPI_EVENT_RESCAN:				/* 06 */
+	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
+	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
+		/*
+		 *  CHECKME!  Falling thru...
+		 */
+
+	case MPI_EVENT_INTEGRATED_RAID:			/* 0B */
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+		/* negoNvram set to 0 if DV enabled and to USE_NVRAM if 
+		 * if DV disabled
+		 */
+		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+		if (hd->negoNvram == 0) {
+			ScsiCfgData	*pSpi;
+			Ioc3PhysDisk_t	*pPDisk;
+			int		 numPDisk;
+			u8		 reason;
+			u8		 physDiskNum;
+			
+			reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
+			if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
+				/* New or replaced disk. 
+				 * Set DV flag and schedule DV.
+				 */
+				pSpi = &ioc->spi_data;
+				physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
+				if (pSpi->pIocPg3) {
+					pPDisk =  pSpi->pIocPg3->PhysDisk;
+					numPDisk =pSpi->pIocPg3->NumPhysDisks;
+
+					while (numPDisk) {
+						if (physDiskNum == pPDisk->PhysDiskNum) {
+							pSpi->dvStatus[pPDisk->PhysDiskID] = MPT_SCSICFG_NEED_DV;
+							pSpi->forceDv = MPT_SCSICFG_NEED_DV;
+							ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+							break;
+						}
+						pPDisk++;
+						numPDisk--;
+					}
+				}
+			}
+		}
+#endif
+
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+		printk("Raid Event RF: ");
+		{
+			u32 *m = (u32 *)pEvReply;
+			int ii;
+			int n = (int)pEvReply->MsgLength;
+			for (ii=6; ii < n; ii++)
+				printk(" %08x", le32_to_cpu(m[ii]));
+			printk("\n");
+		}
+#endif
+		break;
+
+	case MPI_EVENT_NONE:				/* 00 */
+	case MPI_EVENT_LOG_DATA:			/* 01 */
+	case MPI_EVENT_STATE_CHANGE:			/* 02 */
+	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
+	default:
+		dprintk((KERN_INFO "  Ignoring event (=%02Xh)\n", event));
+		break;
+	}
+
+	return 1;		/* currently means nothing really */
+}
+
+#if 0		/* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+ *
+ *	drivers/message/fusion/scsiherr.c
+ */
+
+//extern const char	**mpt_ScsiOpcodesPtr;	/* needed by mptscsih.c */
+//extern ASCQ_Table_t	 *mpt_ASCQ_TablePtr;
+//extern int		  mpt_ASCQ_TableSz;
+
+#define MYNAM	"mptscsih"
+
+#endif		/* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* old symsense.c stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ * To protect ourselves against those that would pass us bogus pointers
+ */
+static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
+    = { 0x1F, 0x00, 0x00, 0x00,
+	0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
+    = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00 };
+static u8 dummyCDB[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummyScsiData[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#if 0
+static const char *PeripheralDeviceTypeString[32] = {
+	"Direct-access",		/* 00h */
+	"Sequential-access",		/* 01h */
+	"Printer",			/* 02h */
+	"Processor",			/* 03h */
+			/*"Write-Once-Read-Multiple",*/	/* 04h */
+	"WORM",				/* 04h */
+	"CD-ROM",			/* 05h */
+	"Scanner",			/* 06h */
+	"Optical memory",		/* 07h */
+	"Media Changer",		/* 08h */
+	"Communications",		/* 09h */
+	"(Graphics arts pre-press)",	/* 0Ah */
+	"(Graphics arts pre-press)",	/* 0Bh */
+	"Array controller",		/* 0Ch */
+	"Enclosure services",		/* 0Dh */
+	"Simplified direct-access",	/* 0Eh */
+	"Reserved-0Fh",			/* 0Fh */
+	"Reserved-10h",			/* 10h */
+	"Reserved-11h",			/* 11h */
+	"Reserved-12h",			/* 12h */
+	"Reserved-13h",			/* 13h */
+	"Reserved-14h",			/* 14h */
+	"Reserved-15h",			/* 15h */
+	"Reserved-16h",			/* 16h */
+	"Reserved-17h",			/* 17h */
+	"Reserved-18h",			/* 18h */
+	"Reserved-19h",			/* 19h */
+	"Reserved-1Ah",			/* 1Ah */
+	"Reserved-1Bh",			/* 1Bh */
+	"Reserved-1Ch",			/* 1Ch */
+	"Reserved-1Dh",			/* 1Dh */
+	"Reserved-1Eh",			/* 1Eh */
+	"Unknown"			/* 1Fh */
+};
+#endif
+
+static char *ScsiStatusString[] = {
+	"GOOD",					/* 00h */
+	NULL,					/* 01h */
+	"CHECK CONDITION",			/* 02h */
+	NULL,					/* 03h */
+	"CONDITION MET",			/* 04h */
+	NULL,					/* 05h */
+	NULL,					/* 06h */
+	NULL,					/* 07h */
+	"BUSY",					/* 08h */
+	NULL,					/* 09h */
+	NULL,					/* 0Ah */
+	NULL,					/* 0Bh */
+	NULL,					/* 0Ch */
+	NULL,					/* 0Dh */
+	NULL,					/* 0Eh */
+	NULL,					/* 0Fh */
+	"INTERMEDIATE",				/* 10h */
+	NULL,					/* 11h */
+	NULL,					/* 12h */
+	NULL,					/* 13h */
+	"INTERMEDIATE-CONDITION MET",		/* 14h */
+	NULL,					/* 15h */
+	NULL,					/* 16h */
+	NULL,					/* 17h */
+	"RESERVATION CONFLICT",			/* 18h */
+	NULL,					/* 19h */
+	NULL,					/* 1Ah */
+	NULL,					/* 1Bh */
+	NULL,					/* 1Ch */
+	NULL,					/* 1Dh */
+	NULL,					/* 1Eh */
+	NULL,					/* 1Fh */
+	NULL,					/* 20h */
+	NULL,					/* 21h */
+	"COMMAND TERMINATED",			/* 22h */
+	NULL,					/* 23h */
+	NULL,					/* 24h */
+	NULL,					/* 25h */
+	NULL,					/* 26h */
+	NULL,					/* 27h */
+	"TASK SET FULL",			/* 28h */
+	NULL,					/* 29h */
+	NULL,					/* 2Ah */
+	NULL,					/* 2Bh */
+	NULL,					/* 2Ch */
+	NULL,					/* 2Dh */
+	NULL,					/* 2Eh */
+	NULL,					/* 2Fh */
+	"ACA ACTIVE",				/* 30h */
+	NULL
+};
+
+static const char *ScsiCommonOpString[] = {
+	"TEST UNIT READY",			/* 00h */
+	"REZERO UNIT (REWIND)",			/* 01h */
+	NULL,					/* 02h */
+	"REQUEST_SENSE",			/* 03h */
+	"FORMAT UNIT (MEDIUM)",			/* 04h */
+	"READ BLOCK LIMITS",			/* 05h */
+	NULL,					/* 06h */
+	"REASSIGN BLOCKS",			/* 07h */
+	"READ(6)",				/* 08h */
+	NULL,					/* 09h */
+	"WRITE(6)",				/* 0Ah */
+	"SEEK(6)",				/* 0Bh */
+	NULL,					/* 0Ch */
+	NULL,					/* 0Dh */
+	NULL,					/* 0Eh */
+	"READ REVERSE",				/* 0Fh */
+	"WRITE_FILEMARKS",			/* 10h */
+	"SPACE(6)",				/* 11h */
+	"INQUIRY",				/* 12h */
+	NULL
+};
+
+static const char *SenseKeyString[] = {
+	"NO SENSE",				/* 0h */
+	"RECOVERED ERROR",			/* 1h */
+	"NOT READY",				/* 2h */
+	"MEDIUM ERROR",				/* 3h */
+	"HARDWARE ERROR",			/* 4h */
+	"ILLEGAL REQUEST",			/* 5h */
+	"UNIT ATTENTION",			/* 6h */
+	"DATA PROTECT",				/* 7h */
+	"BLANK CHECK",				/* 8h */
+	"VENDOR-SPECIFIC",			/* 9h */
+	"ABORTED COPY",				/* Ah */
+	"ABORTED COMMAND",			/* Bh */
+	"EQUAL (obsolete)",			/* Ch */
+	"VOLUME OVERFLOW",			/* Dh */
+	"MISCOMPARE",				/* Eh */
+	"RESERVED",				/* Fh */
+	NULL
+};
+
+#define SPECIAL_ASCQ(c,q) \
+	(((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
+ *			   then print additional information via
+ *			   a call to SDMS_SystemAlert().
+ */
+static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+{
+	u8	*sd;
+	u8	 BadValue;
+	u8	 SenseKey;
+	int	 Offset;
+	int	 len = strlen(msg1);
+
+	sd = ioop->sensePtr;
+	if (SD_Additional_Sense_Length(sd) < 8)
+		return;
+
+	SenseKey = SD_Sense_Key(sd);
+
+	if (SD_Sense_Key_Specific_Valid(sd)) {
+		if (SenseKey == SK_ILLEGAL_REQUEST) {
+			Offset = SD_Bad_Byte(sd);
+			if (SD_Was_Illegal_Request(sd)) {
+				BadValue = ioop->cdbPtr[Offset];
+				len += sprintf(msg1+len, "\n  Illegal CDB value=%02Xh found at CDB ",
+						BadValue);
+		} else {
+			BadValue = ioop->dataPtr[Offset];
+			len += sprintf(msg1+len, "\n  Illegal DATA value=%02Xh found at DATA ",
+					BadValue);
+		}
+		len += sprintf(msg1+len, "byte=%02Xh", Offset);
+		if (SD_SKS_Bit_Pointer_Valid(sd))
+			len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
+		} else if ((SenseKey == SK_RECOVERED_ERROR) ||
+			   (SenseKey == SK_HARDWARE_ERROR) ||
+			   (SenseKey == SK_MEDIUM_ERROR)) {
+			len += sprintf(msg1+len, "\n  Recovery algorithm Actual_Retry_Count=%02Xh",
+			SD_Actual_Retry_Count(sd));
+		}
+	}
+}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_cdb(char *foo, unsigned char *cdb)
+{
+	int i, grpCode, cdbLen;
+	int l = 0;
+
+	grpCode = cdb[0] >> 5;
+	if (grpCode < 1)
+		cdbLen = 6;
+	else if (grpCode < 3)
+		cdbLen = 10;
+	else if (grpCode == 5)
+		cdbLen = 12;
+	else
+		cdbLen = 16;
+
+	for (i=0; i < cdbLen; i++)
+		l += sprintf(foo+l, " %02X", cdb[i]);
+
+	return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_sd(char *foo, unsigned char *sd)
+{
+	int snsLen = 8 + SD_Additional_Sense_Length(sd);
+	int l = 0;
+	int i;
+
+	for (i=0; i < MIN(snsLen,18); i++)
+		l += sprintf(foo+l, " %02X", sd[i]);
+	l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+
+	return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
+static const char * ascq_set_strings_4max(
+		u8 ASC, u8 ASCQ,
+		const char **s1, const char **s2, const char **s3, const char **s4)
+{
+	static const char *asc_04_part1_string = "LOGICAL UNIT ";
+	static const char *asc_04_part2a_string = "NOT READY, ";
+	static const char *asc_04_part2b_string = "IS ";
+	static const char *asc_04_ascq_NN_part3_strings[] = {	/* ASC ASCQ (hex) */
+	  "CAUSE NOT REPORTABLE",				/* 04 00 */
+	  "IN PROCESS OF BECOMING READY",			/* 04 01 */
+	  "INITIALIZING CMD. REQUIRED",				/* 04 02 */
+	  "MANUAL INTERVENTION REQUIRED",			/* 04 03 */
+	  /* Add	" IN PROGRESS" to all the following... */
+	  "FORMAT",						/* 04 04 */
+	  "REBUILD",						/* 04 05 */
+	  "RECALCULATION",					/* 04 06 */
+	  "OPERATION",						/* 04 07 */
+	  "LONG WRITE",						/* 04 08 */
+	  "SELF-TEST",						/* 04 09 */
+	  NULL
+	};
+	static char *asc_04_part4_string = " IN PROGRESS";
+
+	static char *asc_29_ascq_NN_strings[] = {		/* ASC ASCQ (hex) */
+	  "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",	/* 29 00 */
+	  "POWER ON OCCURRED",					/* 29 01 */
+	  "SCSI BUS RESET OCCURRED",				/* 29 02 */
+	  "BUS DEVICE RESET FUNCTION OCCURRED",			/* 29 03 */
+	  "DEVICE INTERNAL RESET",				/* 29 04 */
+	  "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED",		/* 29 05 */
+	  "TRANSCEIVER MODE CHANGED TO LVD",			/* 29 06 */
+	  NULL
+	};
+	static char *ascq_vendor_uniq = "(Vendor Unique)";
+	static char *ascq_noone = "(no matching ASC/ASCQ description found)";
+	int idx;
+
+	*s1 = *s2 = *s3 = *s4 = "";		/* set'em all to the empty "" string */
+
+	/* CHECKME! Need lock/sem?
+	 *  Update and examine for isense module presense.
+	 */
+	mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+
+	if (mptscsih_ASCQ_TablePtr == NULL) {
+		/* 2nd chances... */
+		if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
+			*s1 = asc_04_part1_string;
+			*s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
+			*s3 = asc_04_ascq_NN_part3_strings[ASCQ];
+			/* check for " IN PROGRESS" ones */
+			if (ASCQ >= 0x04)
+				*s4 = asc_04_part4_string;
+		} else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
+			*s1 = asc_29_ascq_NN_strings[ASCQ];
+		/*
+		 *	Else { leave all *s[1-4] values pointing to the empty "" string }
+		 */
+		return *s1;
+	}
+
+	/*
+	 * Need to check ASC here; if it is "special," then
+	 * the ASCQ is variable, and indicates failed component number.
+	 * We must treat the ASCQ as a "dont care" while searching the
+	 * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
+	 * on when we actually need to identify the failed component.
+	 */
+	if (SPECIAL_ASCQ(ASC,ASCQ))
+		ASCQ = 0xFF;
+
+	/* OK, now search mptscsih_ASCQ_Table[] for a matching entry */
+	for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
+		if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) {
+			*s1 = mptscsih_ASCQ_TablePtr[idx].Description;
+			return *s1;
+		}
+
+	if ((ASC >= 0x80) || (ASCQ >= 0x80))
+		*s1 = ascq_vendor_uniq;
+	else
+		*s1 = ascq_noone;
+
+	return *s1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Error Report; desired output format...
+ *---
+SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
+  SCSI_Status=02h (CHECK CONDITION)
+  Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
+  SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
+  SenseKey=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+ *---
+ */
+
+int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
+{
+	char		 foo[512];
+	char		 buf2[32];
+	char		*statstr;
+	const char	*opstr;
+	int		 sk		= SD_Sense_Key(ioop->sensePtr);
+	const char	*skstr		= SenseKeyString[sk];
+	unsigned char	 asc		= SD_ASC(ioop->sensePtr);
+	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
+	int		 l;
+
+	/*
+	 *  More quiet mode.
+	 *  Filter out common, repetitive, warning-type errors...  like:
+	 *    POWER ON (06,29/00 or 06,29/01),
+	 *    SPINNING UP (02,04/01),
+	 *    LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
+	 */
+	if (sk == SK_NO_SENSE) {
+		return 0;
+	}
+	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
+	     || (sk==SK_NOT_READY	&& asc==0x04 && ascq==0x01)
+	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
+	   )
+	{
+		/* Do nothing! */
+		return 0;
+	}
+
+	/*
+	 *  Protect ourselves...
+	 */
+	if (ioop->cdbPtr == NULL)
+		ioop->cdbPtr = dummyCDB;
+	if (ioop->sensePtr == NULL)
+		ioop->sensePtr = dummySenseData;
+	if (ioop->inqPtr == NULL)
+		ioop->inqPtr = dummyInqData;
+	if (ioop->dataPtr == NULL)
+		ioop->dataPtr = dummyScsiData;
+
+	statstr = NULL;
+	if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
+	    ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
+		(void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
+		statstr = buf2;
+	}
+
+	opstr = NULL;
+	if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
+		opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
+	else if (mpt_ScsiOpcodesPtr)
+		opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
+
+	l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
+	  "  SCSI_Status=%02Xh (%s)\n"
+	  "  Original_CDB[]:",
+			ioop->DevIDStr,
+			ioop->SCSIStatus,
+			statstr);
+	l += dump_cdb(foo+l, ioop->cdbPtr);
+	if (opstr)
+		l += sprintf(foo+l, " - \"%s\"", opstr);
+	l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
+	l += dump_sd(foo+l, ioop->sensePtr);
+	l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
+			sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
+
+	{
+		const char	*x1, *x2, *x3, *x4;
+		x1 = x2 = x3 = x4 = "";
+		x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
+		if (x1 != NULL) {
+			if (x1[0] != '(')
+				l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
+			else
+				l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
+		}
+	}
+
+#if 0
+	if (SPECIAL_ASCQ(asc,ascq))
+		l += sprintf(foo+l, " (%02Xh)", ascq);
+#endif
+
+	PrintF(("%s\n", foo));
+
+	return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_initTarget - Target, LUN alloc/free functionality.
+ *	@hd: Pointer to MPT_SCSI_HOST structure
+ *	@bus_id: Bus number (?)
+ *	@target_id: SCSI target id
+ *	@lun: SCSI LUN id
+ *	@data: Pointer to data
+ *	@dlen: Number of INQUIRY bytes
+ *
+ *	NOTE: It's only SAFE to call this routine if data points to
+ *	sane & valid STANDARD INQUIRY data!
+ *
+ *	Allocate and initialize memory for this target.
+ *	Save inquiry data.
+ *
+ *	Returns pointer to VirtDevice structure.
+ */
+static VirtDevice *
+mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
+{
+	VirtDevice	*vdev;
+	int		 sz;
+
+	dprintk((MYIOC_s_INFO_FMT "initTarget (%d,%d,%d) called, hd=%p\n",
+			hd->ioc->name, bus_id, target_id, lun, hd));
+
+	if ((vdev = hd->Targets[target_id]) == NULL) {
+		if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
+			printk(MYIOC_s_ERR_FMT "initTarget kmalloc(%d) FAILED!\n",
+					hd->ioc->name, (int)sizeof(VirtDevice));
+		} else {
+			memset(vdev, 0, sizeof(VirtDevice));
+			rwlock_init(&vdev->VdevLock);
+			Q_INIT(&vdev->WaitQ, void);
+			Q_INIT(&vdev->SentQ, void);
+			Q_INIT(&vdev->DoneQ, void);
+			vdev->tflags = 0;
+			vdev->ioc_id = hd->ioc->id;
+			vdev->target_id = target_id;
+			vdev->bus_id = bus_id;
+
+			hd->Targets[target_id] = vdev;
+			dprintk((KERN_INFO "  *NEW* Target structure (id %d) @ %p\n",
+					target_id, vdev));
+		}
+	}
+
+	if (vdev && data) {
+		if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+
+			/* Copy the inquiry data  - if we haven't yet.
+			*/
+			sz = MIN(dlen, SCSI_STD_INQUIRY_BYTES);
+
+			memcpy (vdev->inq_data, data, sz);
+			vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+
+			/* Update the target capabilities
+			 */
+			mptscsih_setTargetNegoParms(hd, vdev);
+		}
+
+		/* Is LUN supported? If so, upper 3 bits will be 0
+		 * in first byte of inquiry data.
+		 */
+		if ((*data & 0xe0) == 0)
+			vdev->luns |= (1 << lun);
+	}
+
+	if (vdev) {
+		if (hd->ioc->spi_data.isRaid & (1 << target_id))
+			vdev->raidVolume = 1;
+		else
+			vdev->raidVolume = 0;
+	}
+
+	dprintk((KERN_INFO "  target = %p\n", vdev));
+	return vdev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Update the target negotiation parameters based on the
+ *  the Inquiry data, adapter capabilities, and NVRAM settings.
+ *
+ */
+void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target)
+{
+	int  id = (int) target->target_id;
+	int  nvram;
+	char canQ = 0;
+	u8 width = MPT_NARROW;
+	u8 factor = MPT_ASYNC;
+	u8 offset = 0;
+	u8 version, nfactor;
+	ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+
+	/* Set flags based on Inquiry data
+	 */
+	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+		version = target->inq_data[2] & 0x03;
+		if (version < 2) {
+			width = 0;
+			factor = MPT_ULTRA2;
+			offset = pspi_data->maxSyncOffset;
+		} else {
+			if (target->inq_data[7] & 0x20) {
+				width = 1;
+			}
+
+			if (target->inq_data[7] & 0x10) {
+				if (version == 2)
+					factor = MPT_ULTRA2;
+				else
+					factor = MPT_ULTRA320;
+
+				offset = pspi_data->maxSyncOffset;
+			} else {
+				factor = MPT_ASYNC;
+				offset = 0;
+			}
+		}
+
+		if (target->inq_data[7] & 0x02) {
+			canQ = 1;
+		}
+
+		/* Update tflags based on NVRAM settings. (SCSI only)
+		 */
+		if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+			nvram = pspi_data->nvram[id];
+			nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+
+			if (width)
+				width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+			if (offset > 0) {
+				/* Ensure factor is set to the
+				 * maximum of: adapter, nvram, inquiry
+				 */
+				if (nfactor) {
+					if (nfactor < pspi_data->minSyncFactor )
+						nfactor = pspi_data->minSyncFactor;
+
+					factor = MAX (factor, nfactor);
+					if (factor == MPT_ASYNC)
+						offset = 0;
+				} else {
+					offset = 0;
+					factor = MPT_ASYNC;
+				}
+			} else {
+				factor = MPT_ASYNC;
+			}
+		}
+
+		/* Make sure data is consistent
+		 */
+		if ((!width) && (factor < MPT_ULTRA2)) {
+			factor = MPT_ULTRA2;
+		}
+
+		/* Save the data to the target structure.
+		 */
+		target->minSyncFactor = factor;
+		target->maxOffset = offset;
+		target->maxWidth = width;
+		if (canQ) {
+			target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+		}
+
+		target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
+
+		/* Disable all wide (sync) extended messages
+		 * if device is narrow (async).
+		 */
+		target->negoFlags = 0;
+		if (!width)
+			target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+		if (!offset)
+			target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+	}
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Clear sense valid flag.
+ */
+static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
+{
+	VirtDevice	*target;
+	int		 index = (int) pReq->TargetID;
+
+	if ((target = hd->Targets[index])) {
+		target->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
+	}
+
+	return;
+}
+
+/* 
+ * If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
+ * Else set the NEED_DV flag after Read Capacity Issued (disks) 
+ * or Mode Sense (cdroms). Tapes, key off of Inquiry command.
+ */
+static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data)
+{
+	u8 cmd = pReq->CDB[0];
+	
+	if (pReq->LUN[1] != 0)
+		return;
+
+	if (hd->negoNvram != 0)
+		return;
+
+	if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE) || 
+		((cmd == INQUIRY) && ((data[0] & 0x1F) == 0x01))) {
+		u8 dvStatus = hd->ioc->spi_data.dvStatus[pReq->TargetID];
+		if (!(dvStatus & MPT_SCSICFG_DV_DONE)) {
+			ScsiCfgData *pSpi = &hd->ioc->spi_data;
+			if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
+				/* Set NEED_DV for all hidden disks
+				 */
+				Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
+				int		numPDisk = pSpi->pIocPg3->NumPhysDisks;
+				
+				while (numPDisk) {
+					pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+					ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+					pPDisk++;
+					numPDisk--;
+				}
+			}
+			pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
+			ddvtprintk(("NEED_DV set for visible disk id %d\n", 
+					pReq->TargetID));
+		};
+	}
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Config Page functionality ...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_setDevicePage1Flags  - add Requested and Configuration fields flags
+ *	based on width, factor and offset parameters.
+ *	@width: bus width
+ *	@factor: sync factor
+ *	@offset: sync offset
+ *	@requestedPtr: pointer to requested values (updated)
+ *	@configurationPtr: pointer to configuration values (updated)
+ *	@flags: flags to block WDTR or SDTR negotiation
+ *
+ *	Return: None.
+ *
+ *	Remark: Called by writeSDP1 and _dv_params
+ */
+static void
+mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
+{
+	u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
+	u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
+
+	*configurationPtr = 0;
+	*requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
+	*requestedPtr |= (offset << 16) | (factor << 8);
+
+	if (width && offset && !nowide && !nosync) {
+		if (factor < MPT_ULTRA160) {
+			*requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT +
+						MPI_SCSIDEVPAGE1_RP_QAS);
+		} else if (factor < MPT_ULTRA2) {
+			*requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
+		}
+	}
+
+	if (nowide)
+		*configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
+
+	if (nosync)
+		*configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_writeSDP1  - write SCSI Device Page 1
+ *	@hd: Pointer to a SCSI Host Strucutre
+ *	@portnum: IOC port number
+ *	@target_id: writeSDP1 for single ID
+ *	@flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM
+ *
+ *	Return: -EFAULT if read of config page header fails
+ *		or 0 if success.
+ *
+ *	Remark: If a target has been found, the settings from the
+ *		target structure are used, else the device is set
+ *		to async/narrow.
+ *
+ *	Remark: Called during init and after a FW reload.
+ *	Remark: We do not wait for a return, write pages sequentially.
+ */
+static int
+mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
+{
+	MPT_ADAPTER		*ioc = hd->ioc;
+	Config_t		*pReq = NULL;
+	SCSIDevicePage1_t	*pData = NULL;
+	VirtDevice		*pTarget = NULL;
+	MPT_FRAME_HDR		*mf;
+	MptSge_t		*psge;
+	dma_addr_t		 dataDma;
+	u16			 req_idx;
+	u32			 frameOffset;
+	u32			 requested, configuration, flagsLength;
+	int			 ii, nvram;
+	int			 id = 0, maxid = 0;
+	u8			 width;
+	u8			 factor;
+	u8			 offset;
+	u8			 bus = 0;
+	u8			 negoFlags;
+
+	if (ioc->spi_data.sdp1length == 0)
+		return 0;
+
+	if (flags & MPT_SCSICFG_ALL_IDS) {
+		id = 0;
+		maxid = ioc->sh->max_id - 1;
+	} else if (ioc->sh) {
+		id = target_id;
+		maxid = MIN(id, ioc->sh->max_id - 1);
+	}
+
+	for (; id <= maxid; id++) {
+		if (id == ioc->pfacts[portnum].PortSCSIID)
+			continue;
+
+		if (flags & MPT_SCSICFG_USE_NVRAM) {
+			/* Use NVRAM, adapter maximums and target settings.
+			 * Data over-riden by target structure information, if present
+			 */
+			width = ioc->spi_data.maxBusWidth;
+			offset = ioc->spi_data.maxSyncOffset;
+			factor = ioc->spi_data.minSyncFactor;
+			if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+				nvram = ioc->spi_data.nvram[id];
+
+				if (width)
+					width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+				if (offset > 0) {
+					factor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+					if (factor == 0) {
+						/* Key for async */
+						factor = MPT_ASYNC;
+						offset = 0;
+					} else if (factor < ioc->spi_data.minSyncFactor) {
+						factor = ioc->spi_data.minSyncFactor;
+					}
+				} else
+					factor = MPT_ASYNC;
+			}
+
+			/* Set the negotiation flags.
+			 */
+			negoFlags = 0;
+			if (!width)
+				negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+	
+			if (!offset)
+				negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+		} else {
+			width = 0;
+			factor = MPT_ASYNC;
+			offset = 0;
+			negoFlags = MPT_TARGET_NO_NEGO_SYNC;
+		}
+
+		/* If id is not a raid volume, get the updated
+		 * transmission settings from the target structure.
+		 */
+		if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
+			width = pTarget->maxWidth;
+			factor = pTarget->minSyncFactor;
+			offset = pTarget->maxOffset;
+			negoFlags = pTarget->negoFlags;
+			pTarget = NULL;
+		}
+		mptscsih_setDevicePage1Flags(width, factor, offset,
+					&requested, &configuration, negoFlags);
+
+
+		if (negoFlags == (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC))
+			continue;
+
+		/* Get a MF for this command.
+		 */
+		if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
+			dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
+						ioc->name));
+			return -EAGAIN;
+		}
+
+		/* Set the request and the data pointers.
+		 * Request takes: 36 bytes (32 bit SGE)
+		 * SCSI Device Page 1 requires 16 bytes
+		 * 40 + 16 <= size of SCSI IO Request = 56 bytes
+		 * and MF size >= 64 bytes.
+		 * Place data at end of MF.
+		 */
+		pReq = (Config_t *)mf;
+
+		req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+		frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
+
+		pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
+		dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
+
+		/* Complete the request frame (same for all requests).
+		 */
+		pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+		pReq->Reserved = 0;
+		pReq->ChainOffset = 0;
+		pReq->Function = MPI_FUNCTION_CONFIG;
+		pReq->Reserved1[0] = 0;
+		pReq->Reserved1[1] = 0;
+		pReq->Reserved1[2] = 0;
+		pReq->MsgFlags = 0;
+		for (ii=0; ii < 8; ii++) {
+			pReq->Reserved2[ii] = 0;
+		}
+		pReq->Header.PageVersion = ioc->spi_data.sdp1version;
+		pReq->Header.PageLength = ioc->spi_data.sdp1length;
+		pReq->Header.PageNumber = 1;
+		pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+		pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
+
+		/* Add a SGE to the config request.
+		 */
+		flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
+
+		psge = (MptSge_t *) &pReq->PageBufferSGE;
+		psge->FlagsLength = cpu_to_le32(flagsLength);
+		cpu_to_leXX(dataDma, psge->Address);
+
+		/* Set up the common data portion
+		 */
+		pData->Header.PageVersion = pReq->Header.PageVersion;
+		pData->Header.PageLength = pReq->Header.PageLength;
+		pData->Header.PageNumber = pReq->Header.PageNumber;
+		pData->Header.PageType = pReq->Header.PageType;
+		pData->RequestedParameters = cpu_to_le32(requested);
+		pData->Reserved = 0;
+		pData->Configuration = cpu_to_le32(configuration);
+
+		dprintk((MYIOC_s_INFO_FMT 
+			"write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
+				ioc->name, id, (id | (bus<<8)), 
+				requested, configuration));
+
+		mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
+	}
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_taskmgmt_timeout - Call back for timeout on a
+ *	task management request.
+ *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ *
+ */
+static void mptscsih_taskmgmt_timeout(unsigned long data)
+{
+	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+
+	dprintk((MYIOC_s_WARN_FMT "TM request timed out!\n", hd->ioc->name));
+	/* Delete the timer that triggered this callback.
+	 * Remark: del_timer checks to make sure timer is active
+	 * before deleting.
+	 */
+	del_timer(&hd->TMtimer);
+
+	/* Call the reset handler. Already had a TM request
+	 * timeout - so issue a diagnostic reset
+	 */
+	if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+		printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+	}
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Bus Scan and Domain Validation functionality ...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptscsih_scandv_complete - Scan and DV callback routine registered
+ *	to Fustion MPT (base) driver.
+ *
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@mf: Pointer to original MPT request frame
+ *	@mr: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *	This routine is called from mpt.c::mpt_interrupt() at the completion
+ *	of any SCSI IO request.
+ *	This routine is registered with the Fusion MPT (base) driver at driver
+ *	load/init time via the mpt_register() API call.
+ *
+ *	Returns 1 indicating alloc'd request frame ptr should be freed.
+ *
+ *	Remark: Sets a completion code and (possibly) saves sense data
+ *	in the IOC member localReply structure.
+ *	Used ONLY for bus scan, DV and other internal commands.
+ */
+static int
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+	MPT_SCSI_HOST	*hd;
+	SCSIIORequest_t *pReq;
+	int		 completionCode;
+	u16		 req_idx;
+
+	if ((mf == NULL) ||
+	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+		printk(MYIOC_s_ERR_FMT
+			"ScanDvComplete, %s req frame ptr! (=%p)\n",
+				ioc->name, mf?"BAD":"NULL", mf);
+		goto wakeup;
+	}
+
+	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+	del_timer(&hd->timer);
+	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+	hd->ScsiLookup[req_idx] = NULL;
+	pReq = (SCSIIORequest_t *) mf;
+
+	if (mf != hd->cmdPtr) {
+		printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p)\n",
+				hd->ioc->name, mf, hd->cmdPtr);
+	}
+	hd->cmdPtr = NULL;
+
+	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p)\n",
+			hd->ioc->name, mf, mr));
+
+	atomic_dec(&queue_depth);
+
+	hd->pLocal = &hd->localReply;
+
+	/* If target struct exists, clear sense valid flag.
+	 */
+	clear_sense_flag(hd, pReq);
+
+	if (mr == NULL) {
+		completionCode = MPT_SCANDV_GOOD;
+	} else {
+		SCSIIOReply_t	*pReply;
+		u16		 status;
+
+		pReply = (SCSIIOReply_t *) mr;
+
+		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+		ddvprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+			     status, pReply->SCSIState, pReply->SCSIStatus,
+			     le32_to_cpu(pReply->IOCLogInfo)));
+
+		switch(status) {
+
+		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
+			completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
+		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */
+		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
+		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
+			completionCode = MPT_SCANDV_DID_RESET;
+			break;
+
+		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
+		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
+		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
+			if (pReply->Function == MPI_FUNCTION_CONFIG) {
+				ConfigReply_t *pr = (ConfigReply_t *)mr;
+				completionCode = MPT_SCANDV_GOOD;
+				hd->pLocal->header.PageVersion = pr->Header.PageVersion;
+				hd->pLocal->header.PageLength = pr->Header.PageLength;
+				hd->pLocal->header.PageNumber = pr->Header.PageNumber;
+				hd->pLocal->header.PageType = pr->Header.PageType;
+
+			} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+				/* If the RAID Volume request is successful,
+				 * return GOOD, else indicate that
+				 * some type of error occurred.
+				 */
+				MpiRaidActionReply_t	*pr = (MpiRaidActionReply_t *)mr;
+				if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+					completionCode = MPT_SCANDV_GOOD;
+				else
+					completionCode = MPT_SCANDV_SOME_ERROR;
+
+			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+				VirtDevice	*target;
+				u8		*sense_data;
+				int		 sz;
+
+				/* save sense data in global & target structure
+				 */
+				completionCode = MPT_SCANDV_SENSE;
+				hd->pLocal->scsiStatus = pReply->SCSIStatus;
+				sense_data = ((u8 *)hd->ioc->sense_buf_pool +
+					(req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+				sz = MIN (pReq->SenseBufferLength,
+							SCSI_STD_SENSE_BYTES);
+				memcpy(hd->pLocal->sense, sense_data, sz);
+
+				target = hd->Targets[pReq->TargetID];
+				if (target) {
+					memcpy(target->sense, sense_data, sz);
+					target->tflags
+						|= MPT_TARGET_FLAGS_VALID_SENSE;
+				}
+
+				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
+						sense_data));
+			} else if (pReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED |
+							MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+				completionCode = MPT_SCANDV_DID_RESET;
+			} else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+				completionCode = MPT_SCANDV_DID_RESET;
+			} else {
+				/* If no error, this will be equivalent
+				 * to MPT_SCANDV_GOOD
+				 */
+				completionCode = (int) pReply->SCSIStatus;
+			}
+			break;
+
+		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */
+			if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+				completionCode = MPT_SCANDV_DID_RESET;
+			else
+				completionCode = MPT_SCANDV_SOME_ERROR;
+			break;
+
+		default:
+			completionCode = MPT_SCANDV_SOME_ERROR;
+			break;
+
+		}	/* switch(status) */
+
+		ddvprintk((KERN_NOTICE "  completionCode set to %08xh\n",
+				completionCode));
+	} /* end of address reply case */
+
+	hd->pLocal->completion = completionCode;
+
+	/* MF and RF are freed in mpt_interrupt
+	 */
+wakeup:
+	/* Free Chain buffers (will never chain) in scan or dv */
+	//mptscsih_freeChainBuffers(hd, req_idx);
+
+	/*
+	 * Wake up the original calling thread
+	 */
+	scandv_wait_done = 1;
+	wake_up(&scandv_waitq);
+
+	return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_timer_expired - Call back for timer process.
+ *	Used only for dv functionality.
+ *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ *
+ */
+static void mptscsih_timer_expired(unsigned long data)
+{
+	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+#ifndef MPT_SCSI_USE_NEW_EH
+	unsigned long  flags;
+#endif
+
+
+	ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+
+	if (hd->cmdPtr) {
+		MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
+
+		if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+			/* Desire to issue a task management request here.
+			 * TM requests MUST be single threaded.
+			 * If old eh code and no TM current, issue request.
+			 * If new eh code, do nothing. Wait for OS cmd timeout
+			 *	for bus reset.
+			 */
+#ifndef MPT_SCSI_USE_NEW_EH
+			spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+			if (hd->tmPending) {
+				spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+				return;
+			} else 
+				hd->tmPending = 1;
+			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+			if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+							0, 0, 0, NO_SLEEP) < 0) {
+				printk(MYIOC_s_WARN_FMT "TM FAILED!\n", hd->ioc->name);
+			}
+#else
+			ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
+#endif
+		} else {
+			/* Perform a FW reload */
+			if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+				printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
+			}
+		}
+	} else {
+		/* This should NEVER happen */
+		printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
+	}
+
+	/* No more processing.
+	 * TM call will generate an interrupt for SCSI TM Management.
+	 * The FW will reply to all outstanding commands, callback will finish cleanup.
+	 * Hard reset clean-up will free all resources.
+	 */
+	ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
+
+	return;
+}
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_do_raid - Format and Issue a RAID volume request message.
+ *	@hd: Pointer to scsi host structure
+ *	@action: What do be done.
+ *	@id: Logical target id.
+ *	@bus: Target locations bus.
+ *
+ *	Returns: < 0 on a fatal error
+ *		0 on success
+ *
+ *	Remark: Wait to return until reply processed by the ISR.
+ */
+static int
+mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
+{
+	MpiRaidActionRequest_t	*pReq;
+	MPT_FRAME_HDR		*mf;
+	MptSge_t		*psge;
+	int			flagsLength;
+	int			in_isr;
+
+	in_isr = in_interrupt();
+	if (in_isr) {
+		dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
+       				hd->ioc->name));
+		return -EPERM;
+	}
+
+	/* Get and Populate a free Frame
+	 */
+	if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
+		ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+					hd->ioc->name));
+		return -EAGAIN;
+	}
+	pReq = (MpiRaidActionRequest_t *)mf;
+	pReq->Action = action;
+	pReq->Reserved1 = 0;
+	pReq->ChainOffset = 0;
+	pReq->Function = MPI_FUNCTION_RAID_ACTION;
+	pReq->VolumeID = io->id;
+	pReq->VolumeBus = io->bus;
+	pReq->PhysDiskNum = io->physDiskNum;
+	pReq->MsgFlags = 0;
+	pReq->Reserved2 = 0;
+	pReq->ActionDataWord = 0; /* Reserved for this action */
+	//pReq->ActionDataSGE = 0;
+
+	psge = (MptSge_t *) &pReq->ActionDataSGE;
+
+	/* Add a SGE to the config request.
+	 */
+	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 0;
+
+	psge->FlagsLength = cpu_to_le32(flagsLength);
+	cpu_to_leXX( (dma_addr_t) -1, psge->Address);
+
+	ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
+			hd->ioc->name, action, io->id));
+
+	hd->pLocal = NULL;
+	hd->timer.expires = jiffies + HZ*2; /* 2 second timeout */
+	scandv_wait_done = 0;
+
+	/* Save cmd pointer, for resource free if timeout or
+	 * FW reload occurs
+	 */
+	hd->cmdPtr = mf;
+
+	add_timer(&hd->timer);
+	mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+	wait_event(scandv_waitq, scandv_wait_done);
+
+	if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
+		return -1;
+
+	return 0;
+}
+#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_do_cmd - Do internal command.
+ *	@hd: MPT_SCSI_HOST pointer
+ *	@io: INTERNAL_CMD pointer.
+ *
+ *	Issue the specified internally generated command and do command
+ *	specific cleanup. For bus scan / DV only.
+ *	NOTES: If command is Inquiry and status is good,
+ *	initialize a target structure, save the data
+ *
+ *	Remark: Single threaded access only.
+ *
+ *	Return:
+ *		< 0 if an illegal command or no resources
+ *
+ *		   0 if good
+ *
+ *		 > 0 if command complete but some type of completion error.
+ */
+static int
+mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
+{
+	MPT_FRAME_HDR	*mf;
+	MptSge_t	*mpisge;
+	SCSIIORequest_t	*pScsiReq;
+	SCSIIORequest_t	 ReqCopy;
+	int		 my_idx, ii, dir;
+	int		 rc, cmdTimeout;
+	int		in_isr;
+	char		 cmdLen;
+	char		 CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+	char		 cmd = io->cmd;
+
+	in_isr = in_interrupt();
+	if (in_isr) {
+		dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+       				hd->ioc->name));
+		return -EPERM;
+	}
+
+
+	/* Set command specific information
+	 */
+	switch (cmd) {
+	case CMD_Inquiry:
+		cmdLen = 6;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		CDB[0] = cmd;
+		CDB[4] = io->size;
+		cmdTimeout = 10;
+		break;
+
+	case CMD_TestUnitReady:
+		cmdLen = 6;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		cmdTimeout = 10;
+		break;
+
+	case CMD_StartStopUnit:
+		cmdLen = 6;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		CDB[0] = cmd;
+		CDB[4] = 1;	/*Spin up the disk */
+		cmdTimeout = 15;
+		break;
+
+	case CMD_ReadBuffer:
+		cmdLen = 10;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		CDB[0] = cmd;
+		if (io->flags & MPT_ICFLAG_ECHO) {
+			CDB[1] = 0x0A;
+		} else {
+			CDB[1] = 0x02;
+		}
+
+		if (io->flags & MPT_ICFLAG_BUF_CAP) {
+			CDB[1] |= 0x01;
+		}
+		CDB[6] = (io->size >> 16) & 0xFF;
+		CDB[7] = (io->size >>  8) & 0xFF;
+		CDB[8] = io->size & 0xFF;
+		cmdTimeout = 10;
+		break;
+
+	case CMD_WriteBuffer:
+		cmdLen = 10;
+		dir = MPI_SCSIIO_CONTROL_WRITE;
+		CDB[0] = cmd;
+		if (io->flags & MPT_ICFLAG_ECHO) {
+			CDB[1] = 0x0A;
+		} else {
+			CDB[1] = 0x02;
+		}
+		CDB[6] = (io->size >> 16) & 0xFF;
+		CDB[7] = (io->size >>  8) & 0xFF;
+		CDB[8] = io->size & 0xFF;
+		cmdTimeout = 10;
+		break;
+
+	case CMD_Reserve6:
+		cmdLen = 6;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		CDB[0] = cmd;
+		cmdTimeout = 10;
+		break;
+
+	case CMD_Release6:
+		cmdLen = 6;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		CDB[0] = cmd;
+		cmdTimeout = 10;
+		break;
+
+	case CMD_SynchronizeCache:
+		cmdLen = 10;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		CDB[0] = cmd;
+//		CDB[1] = 0x02;	/* set immediate bit */
+		cmdTimeout = 10;
+		break;
+
+	default:
+		/* Error Case */
+		return -EFAULT;
+	}
+
+	/* Get and Populate a free Frame
+	 */
+	if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
+		ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
+					hd->ioc->name));
+		return -EBUSY;
+	}
+
+	pScsiReq = (SCSIIORequest_t *) mf;
+
+	/* Get the request index */
+	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+	ADD_INDEX_LOG(my_idx); /* for debug */
+
+	if (io->flags & MPT_ICFLAG_PHYS_DISK) {
+		pScsiReq->TargetID = io->physDiskNum;
+		pScsiReq->Bus = 0;
+		pScsiReq->ChainOffset = 0;
+		pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
+	} else {
+		pScsiReq->TargetID = io->id;
+		pScsiReq->Bus = io->bus;
+		pScsiReq->ChainOffset = 0;
+		pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+	}
+
+	pScsiReq->CDBLength = cmdLen;
+	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+	pScsiReq->Reserved = 0;
+
+	pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS;
+	/* MsgContext set in mpt_get_msg_fram call  */
+
+	for (ii=0; ii < 8; ii++)
+		pScsiReq->LUN[ii] = 0;
+	pScsiReq->LUN[1] = io->lun;
+
+	if (io->flags & MPT_ICFLAG_TAGGED_CMD)
+		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
+	else
+		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+
+	for (ii=0; ii < 16; ii++)
+		pScsiReq->CDB[ii] = CDB[ii];
+
+	pScsiReq->DataLength = cpu_to_le32(io->size);
+	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+
+	ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+			hd->ioc->name, cmd, io->bus, io->id, io->lun));
+
+	/* 32 bit SG only */
+	mpisge = (MptSge_t *) &pScsiReq->SGL;
+
+	if (dir == MPI_SCSIIO_CONTROL_READ) {
+		mpisge->FlagsLength = cpu_to_le32(
+			MPT_SGE_FLAGS_SSIMPLE_READ | io->size);
+	} else {
+		mpisge->FlagsLength = cpu_to_le32(
+			MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size);
+	}
+
+	/* data_dma defaults to -1
+	 */
+	cpu_to_leXX(io->data_dma, mpisge->Address);
+
+	/* The ISR will free the request frame, but we need
+	 * the information to initialize the target. Duplicate.
+	 */
+	memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
+
+	/* Issue this command after:
+	 *	finish init
+	 *	add timer
+	 * Wait until the reply has been received
+	 *  ScsiScanDvCtx callback function will
+	 *	set hd->pLocal;
+	 *	set scandv_wait_done and call wake_up
+	 */
+	hd->pLocal = NULL;
+	hd->timer.expires = jiffies + HZ*cmdTimeout;
+	scandv_wait_done = 0;
+
+	/* Save cmd pointer, for resource free if timeout or
+	 * FW reload occurs
+	 */
+	hd->cmdPtr = mf;
+
+	add_timer(&hd->timer);
+	mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+	wait_event(scandv_waitq, scandv_wait_done);
+
+	if (hd->pLocal) {
+		rc = hd->pLocal->completion;
+		hd->pLocal->skip = 0;
+
+		/* Always set fatal error codes in some cases.
+		 */
+		if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
+			rc = -ENXIO;
+		else if (rc == MPT_SCANDV_SOME_ERROR)
+			rc =  -rc;
+	} else {
+		rc = -EFAULT;
+		/* This should never happen. */
+		ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
+				hd->ioc->name));
+	}
+
+	return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
+ *	@hd: Pointer to MPT_SCSI_HOST structure
+ *	@portnum: IOC port number
+ *
+ *	Uses the ISR, but with special processing.
+ *	MUST be single-threaded.
+ *
+ *	Return: 0 on completion
+ */
+static int
+mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
+{
+	MPT_ADAPTER		*ioc= hd->ioc;
+	VirtDevice		*pTarget = NULL;
+	SCSIDevicePage1_t	*pcfg1Data = NULL;
+	INTERNAL_CMD		 iocmd;
+	CONFIGPARMS		 cfg;
+	dma_addr_t		 cfg1_dma_addr = -1;
+	ConfigPageHeader_t	 header1;
+	int			 bus = 0;
+	int			 id = 0;
+	int			 lun = 0;
+	int			 hostId = ioc->pfacts[portnum].PortSCSIID;
+	int			 max_id;
+	int			 requested, configuration, data;
+	int			 doConfig = 0;
+	u8			 flags, factor;
+
+	max_id = ioc->sh->max_id - 1;
+
+	/* Following parameters will not change
+	 * in this routine.
+	 */
+	iocmd.cmd = CMD_SynchronizeCache;
+	iocmd.flags = 0;
+	iocmd.physDiskNum = -1;
+	iocmd.data = NULL;
+	iocmd.data_dma = -1;
+	iocmd.size = 0;
+	iocmd.rsvd = iocmd.rsvd2 = 0;
+
+	/* No SCSI hosts
+	 */
+	if (hd->Targets == NULL)
+		return 0;
+
+	/* Skip the host
+	 */
+	if (id == hostId)
+		id++;
+
+	/* Write SDP1 for all SCSI devices 
+	 * Alloc memory and set up config buffer
+	 */
+	if (hd->is_spi) {
+		if (ioc->spi_data.sdp1length > 0) {
+			pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
+					 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
+	
+			if (pcfg1Data != NULL) {
+				doConfig = 1;
+				header1.PageVersion = ioc->spi_data.sdp1version;
+				header1.PageLength = ioc->spi_data.sdp1length;
+				header1.PageNumber = 1;
+				header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+				cfg.hdr = &header1;
+				cfg.physAddr = cfg1_dma_addr;
+				cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+				cfg.dir = 1;
+				cfg.timeout = 0;
+			}
+		}
+	}
+
+	/* loop through all devices on this port
+	 */
+	while (bus < MPT_MAX_BUS) {
+		iocmd.bus = bus;
+		iocmd.id = id;
+		pTarget = hd->Targets[(int)id];
+
+		if (doConfig) {
+
+			/* Set the negotiation flags */
+			if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
+				flags = pTarget->negoFlags;
+			} else {
+				flags = 0;
+				if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+					data = hd->ioc->spi_data.nvram[id];
+	
+					if (data & MPT_NVRAM_WIDE_DISABLE)
+						flags |= MPT_TARGET_NO_NEGO_WIDE;
+
+					factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+					if ((factor == 0) || (factor == MPT_ASYNC))
+						flags |= MPT_TARGET_NO_NEGO_SYNC;
+				}
+			}
+	
+			/* Force to async, narrow */
+			mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
+					&configuration, flags);
+			pcfg1Data->RequestedParameters = le32_to_cpu(requested);
+			pcfg1Data->Reserved = 0;
+			pcfg1Data->Configuration = le32_to_cpu(configuration);
+			cfg.pageAddr = (bus<<8) | id;
+			mpt_config(hd->ioc, &cfg);
+		}
+
+		/* If target Ptr NULL or if this target is NOT a disk, skip.
+		 */
+	//	if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
+		if (pTarget) {
+			for (lun=0; lun <= MPT_LAST_LUN; lun++) {
+				/* If LUN present, issue the command
+				 */
+				if (pTarget->luns & (1<<lun)) {
+					iocmd.lun = lun;
+					(void) mptscsih_do_cmd(hd, &iocmd);
+				}
+			}
+		}
+
+		/* get next relevant device */
+		id++;
+
+		if (id == hostId)
+			id++;
+
+		if (id > max_id) {
+			id = 0;
+			bus++;
+		}
+	}
+
+	if (pcfg1Data) {
+		pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
+	}
+
+	return 0;
+}
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_domainValidation - Top level handler for domain validation.
+ *	@hd: Pointer to MPT_SCSI_HOST structure.
+ *
+ *	Uses the ISR, but with special processing.
+ *	Called from schedule, should not be in interrupt mode.
+ *	While thread alive, do dv for all devices needing dv
+ *
+ *	Return: None.
+ */
+static void
+mptscsih_domainValidation(void *arg)
+{
+	MPT_SCSI_HOST		*hd = NULL;
+	MPT_ADAPTER		*ioc = NULL;
+	unsigned long		 flags;
+	int 			 id, maxid, dvStatus, did;
+	int			 ii, isPhysDisk;
+
+	spin_lock_irqsave(&dvtaskQ_lock, flags);
+	dvtaskQ_active = 1;
+	if (dvtaskQ_release) {
+		dvtaskQ_active = 0;
+		spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+	/* For this ioc, loop through all devices and do dv to each device.
+	 * When complete with this ioc, search through the ioc list, and 
+	 * for each scsi ioc found, do dv for all devices. Exit when no
+	 * device needs dv.
+	 */
+	did = 1;
+	while (did) {
+		did = 0;
+		for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+			spin_lock_irqsave(&dvtaskQ_lock, flags);
+			if (dvtaskQ_release) {
+				dvtaskQ_active = 0;
+				spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+				return;
+			}
+			spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ/4);
+
+			/* DV only to SCSI adapters */
+			if ((int)ioc->chip_type <= (int)FC929)
+				continue;
+			
+			/* Make sure everything looks ok */
+			if (ioc->sh == NULL)
+				continue;
+
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+			if (hd == NULL)
+				continue;
+
+			maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
+
+			for (id = 0; id < maxid; id++) {
+				spin_lock_irqsave(&dvtaskQ_lock, flags);
+				if (dvtaskQ_release) {
+					dvtaskQ_active = 0;
+					spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+					return;
+				}
+				spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+				dvStatus = hd->ioc->spi_data.dvStatus[id];
+
+				if (dvStatus & MPT_SCSICFG_NEED_DV) {
+
+					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
+
+					set_current_state(TASK_INTERRUPTIBLE);
+					schedule_timeout(HZ/4);
+
+					/* If hidden phys disk, block IO's to all
+					 *	raid volumes
+					 * else, process normally
+					 */
+					isPhysDisk = 0;
+					if (ioc->spi_data.pIocPg3) {
+						/* Search IOC page 3 to determine if
+						 * this is hidden physical disk
+						 */
+						Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+						int		numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+						
+						while (numPDisk) {
+							if (pPDisk->PhysDiskID == id) {
+								isPhysDisk = 1;
+								break;
+							}
+							pPDisk++;
+							numPDisk--;
+						}
+					}
+
+					if (isPhysDisk) {
+						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+							if (hd->ioc->spi_data.isRaid & (1 << ii)) {
+								hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
+							}
+						}
+					}
+
+					mptscsih_doDv(hd, 0, id);
+					did++;
+					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_DONE;
+					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+
+					if (isPhysDisk) {
+						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+							if (hd->ioc->spi_data.isRaid & (1 << ii)) {
+								hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
+							}
+						}
+					}
+
+					/* Post OS IOs that were pended while
+					 * DV running.
+					 */
+					post_pendingQ_commands(hd);
+				}
+			}
+		}
+	}
+
+	spin_lock_irqsave(&dvtaskQ_lock, flags);
+	dvtaskQ_active = 0;
+	spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+	return;
+}
+
+
+#define MPT_GET_NVRAM_VALS	0x01
+#define MPT_UPDATE_MAX		0x02
+#define MPT_SET_MAX		0x04
+#define MPT_SET_MIN		0x08
+#define MPT_FALLBACK		0x10
+#define MPT_SAVE		0x20
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_doDv - Perform domain validation to a target.
+ *	@hd: Pointer to MPT_SCSI_HOST structure.
+ *	@portnum: IOC port number.
+ *	@target: Physical ID of this target
+ *
+ *	Uses the ISR, but with special processing.
+ *	MUST be single-threaded.
+ *	Test will exit if target is at async & narrow.
+ *
+ *	Return: None.
+ */
+static void
+mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
+{
+	MPT_ADAPTER		*ioc = hd->ioc;
+	VirtDevice		*pTarget = NULL;
+	u8			*pbuf1 = NULL;
+	u8			*pbuf2 = NULL;
+	dma_addr_t		 buf1_dma = -1;
+	dma_addr_t		 buf2_dma = -1;
+	ConfigPageHeader_t	 header1;
+	SCSIDevicePage1_t	*pcfg1Data = NULL;
+	dma_addr_t		 cfg1_dma_addr = -1;
+	ConfigPageHeader_t	 header0;
+	SCSIDevicePage0_t	*pcfg0Data = NULL;
+	dma_addr_t		 cfg0_dma_addr = -1;
+	DVPARAMETERS		 dv;
+	INTERNAL_CMD		 iocmd;
+	CONFIGPARMS		 cfg;
+	int			 rc, sz = 0;
+	int			 bufsize = 0;
+	int			 dataBufSize = 0;
+	int			 echoBufSize = 0;
+	int			 notDone;
+	int			 patt;
+	int			 repeat;
+	char			 firstPass = 1;
+	char			 doFallback = 0;
+	char			 readPage0;
+	char			 bus, lun;
+
+	if (ioc->spi_data.sdp1length == 0)
+		return;
+
+	if (ioc->spi_data.sdp0length == 0)
+		return;
+
+	if (id == ioc->pfacts[portnum].PortSCSIID)
+		return;
+
+	lun = 0;
+	bus = 0;
+	ddvtprintk((MYIOC_s_NOTE_FMT 
+			"DV started: numIOs %d bus=%d, id %d dv @ %p\n",
+			ioc->name, atomic_read(&queue_depth), bus, id, &dv));
+
+	/* Prep DV structure
+	 */
+	memset (&dv, 0, sizeof(DVPARAMETERS));
+	dv.id = id;
+
+	/* Populate tmax with the current maximum
+	 * transfer parameters for this target.
+	 * Exit if narrow and async.
+	 */
+	dv.cmd = MPT_GET_NVRAM_VALS;
+	mptscsih_dv_parms(hd, &dv, NULL);
+	if ((!dv.max.width) && (!dv.max.offset))
+		return;
+
+	/* Prep SCSI IO structure
+	 */
+	iocmd.id = id;
+	iocmd.bus = bus;
+	iocmd.lun = lun;
+	iocmd.flags = 0;
+	iocmd.physDiskNum = -1;
+	iocmd.rsvd = iocmd.rsvd2 = 0;
+
+	/* Use tagged commands if possible.
+	 */
+	pTarget = hd->Targets[id];
+	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+		iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+
+	/* Prep cfg structure
+	 */
+	cfg.pageAddr = (bus<<8) | id;
+	cfg.hdr = NULL;
+
+	/* Prep SDP0 header
+	 */
+	header0.PageVersion = ioc->spi_data.sdp0version;
+	header0.PageLength = ioc->spi_data.sdp0length;
+	header0.PageNumber = 0;
+	header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+	pcfg0Data = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev,
+				 header0.PageLength * 4, &cfg0_dma_addr);
+	if (!pcfg0Data)
+		return;
+
+	/* Prep SDP1 header
+	 */
+	header1.PageVersion = ioc->spi_data.sdp1version;
+	header1.PageLength = ioc->spi_data.sdp1length;
+	header1.PageNumber = 1;
+	header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+	pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
+				 header1.PageLength * 4, &cfg1_dma_addr);
+	if (!pcfg1Data)
+		goto target_done;
+
+	/* Skip this ID? Set cfg.hdr to force config page write
+	 */
+	if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) &&
+			(!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { 
+
+		ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
+			ioc->name, bus, id, lun));
+
+		dv.cmd = MPT_SET_MAX;
+		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+		cfg.hdr = &header1;
+		goto target_done;
+	}
+
+	/* Finish iocmd inititialization - hidden or visible disk? */
+	if (ioc->spi_data.pIocPg3) {
+		/* Searc IOC page 3 for matching id
+		 */
+		Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+		int		numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+		while (numPDisk) {
+			if (pPDisk->PhysDiskID == id) {
+				/* match */
+				iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
+				iocmd.physDiskNum = pPDisk->PhysDiskNum;
+
+				/* Quiesce the IM
+				 */
+				if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
+					ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+					goto target_done;
+				}
+				break;
+			}
+			pPDisk++;
+			numPDisk--;
+		}
+	}
+
+	/* RAID Volume ID's may double for a physical device. If RAID but
+	 * not a physical ID as well, skip DV.
+	 */
+	if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
+		goto target_done;
+
+
+	/* Basic Test.
+	 * Async & Narrow - Inquiry
+	 * Async & Narrow - Inquiry
+	 * Maximum transfer rate - Inquiry
+	 * Compare buffers:
+	 *	If compare, test complete.
+	 *	If miscompare and first pass, repeat
+	 *	If miscompare and not first pass, fall back and repeat
+	 */
+	hd->pLocal = NULL;
+	readPage0 = 0;
+	sz = SCSI_STD_INQUIRY_BYTES;
+	pbuf1 = pci_alloc_consistent(ioc->pcidev, sz, &buf1_dma);
+	pbuf2 = pci_alloc_consistent(ioc->pcidev, sz, &buf2_dma);
+	if (!pbuf1 || !pbuf2)
+		goto target_done;
+
+	while (1) {
+		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+		dv.cmd = MPT_SET_MIN;
+		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+		cfg.hdr = &header1;
+		cfg.physAddr = cfg1_dma_addr;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+		cfg.dir = 1;
+		if (mpt_config(hd->ioc, &cfg) != 0)
+			goto target_done;
+
+		iocmd.cmd = CMD_Inquiry;
+		iocmd.data_dma = buf1_dma;
+		iocmd.data = pbuf1;
+		iocmd.size = sz;
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			goto target_done;
+
+		/* Another GEM workaround. Check peripheral device type,
+		 * if PROCESSOR, quit DV.
+		 */
+		if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08))
+			goto target_done;
+
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			goto target_done;
+
+		if (doFallback)
+			dv.cmd = MPT_FALLBACK;
+		else
+			dv.cmd = MPT_SET_MAX;
+
+		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+		if (mpt_config(hd->ioc, &cfg) != 0)
+			goto target_done;
+
+		if ((!dv.now.width) && (!dv.now.offset))
+			goto target_done;
+
+		iocmd.cmd = CMD_Inquiry;
+		iocmd.data_dma = buf2_dma;
+		iocmd.data = pbuf2;
+		iocmd.size = sz;
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			goto target_done;
+		else if (hd->pLocal == NULL)
+			goto target_done;
+		else {
+			/* Save the return code.
+			 * If this is the first pass,
+			 * read SCSI Device Page 0
+			 * and update the target max parameters.
+			 */
+			rc = hd->pLocal->completion;
+			doFallback = 0;
+			if (rc == MPT_SCANDV_GOOD) {
+				if (!readPage0) {
+					u32 sdp0_info;
+					u32 sdp0_nego;
+
+					cfg.hdr = &header0;
+					cfg.physAddr = cfg0_dma_addr;
+					cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+					cfg.dir = 0;
+					if (mpt_config(hd->ioc, &cfg) != 0)
+						goto target_done;
+
+					sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
+					sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
+
+					/* Quantum and Fujitsu workarounds.
+					 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
+					 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
+					 * Resetart with a request for U160.
+					 */
+					if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) { 
+							doFallback = 1;
+					} else {
+						dv.cmd = MPT_UPDATE_MAX;
+						mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
+						/* Update the SCSI device page 1 area
+						 */
+						pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
+						readPage0 = 1;
+					}
+				}
+
+				/* Quantum workaround. Restart this test will the fallback
+				 * flag set.
+				 */
+				if (doFallback == 0) {
+					if (memcmp(pbuf1, pbuf2, sz) != 0) {
+						if (!firstPass)
+							doFallback = 1;
+					} else
+						break;	/* test complete */
+				}
+
+
+			} else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
+				doFallback = 1;	/* set fallback flag */
+			else
+				goto target_done;
+
+			firstPass = 0;
+		}
+	}
+	/* Free pbuf2, but use pbuf1 for
+	 * acquiring the (echo) buffer size.
+	 */
+	pci_free_consistent(ioc->pcidev, sz, pbuf2, buf2_dma);
+	pbuf2 = NULL;
+	ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name));
+
+	/* Start the Enhanced Test.
+	 * 0) issue TUR to clear out check conditions
+	 * 1) read capacity of echo (regular) buffer
+	 * 2) reserve device
+	 * 3) do write-read-compare data pattern test
+	 * 4) release
+	 * 5) update nego parms to target struct
+	 */
+	cfg.hdr = &header1;
+	cfg.physAddr = cfg1_dma_addr;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+	cfg.dir = 1;
+
+	iocmd.cmd = CMD_TestUnitReady;
+	iocmd.data_dma = -1;
+	iocmd.data = NULL;
+	iocmd.size = 0;
+	notDone = 1;
+	while (notDone) {
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			goto target_done;
+
+		if (hd->pLocal == NULL)
+			goto target_done;
+
+		rc = hd->pLocal->completion;
+		if (rc == MPT_SCANDV_GOOD)
+			notDone = 0;
+		else if (rc == MPT_SCANDV_SENSE) {
+			u8 skey = hd->pLocal->sense[2] & 0x0F;
+			u8 asc = hd->pLocal->sense[12];
+			u8 ascq = hd->pLocal->sense[13];
+			ddvprintk((MYIOC_s_INFO_FMT
+				"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+				ioc->name, skey, asc, ascq));
+
+			if (skey == SK_UNIT_ATTENTION)
+				notDone++; /* repeat */
+			else if ((skey == SK_NOT_READY) &&
+					(asc == 0x04)&&(ascq == 0x01)) {
+				/* wait then repeat */
+				mdelay (2000);
+				notDone++;
+			} else if ((skey == SK_NOT_READY) && (asc == 0x3A)) {
+				/* no medium, try read test anyway */
+				notDone = 0;
+			} else {
+				/* All other errors are fatal.
+				 */
+				ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+						ioc->name));
+				goto target_done;
+			}
+		} else
+			goto target_done;
+	}
+
+	iocmd.cmd = CMD_ReadBuffer;
+	iocmd.data_dma = buf1_dma;
+	iocmd.data = pbuf1;
+	iocmd.size = 4;
+	iocmd.flags |= MPT_ICFLAG_BUF_CAP;
+
+	dataBufSize = 0;
+	echoBufSize = 0;
+	for (patt = 0; patt < 2; patt++) {
+		if (patt == 0)
+			iocmd.flags |= MPT_ICFLAG_ECHO;
+		else
+			iocmd.flags &= ~MPT_ICFLAG_ECHO;
+
+		notDone = 1;
+		while (notDone) {
+			bufsize = 0;
+
+			/* If not ready after 8 trials,
+			 * give up on this device.
+			 */
+			if (notDone > 8)
+				goto target_done;
+
+			if (mptscsih_do_cmd(hd, &iocmd) < 0)
+				goto target_done;
+			else if (hd->pLocal == NULL)
+				goto target_done;
+			else {
+				rc = hd->pLocal->completion;
+				ddvprintk(("ReadBuffer Comp Code %d", rc));
+				ddvprintk(("  buff: %0x %0x %0x %0x\n",
+					pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
+
+				if (rc == MPT_SCANDV_GOOD) {
+					notDone = 0;
+					if (iocmd.flags & MPT_ICFLAG_ECHO) {
+						bufsize =  ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
+					} else {
+						bufsize =  pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
+					}
+				} else if (rc == MPT_SCANDV_SENSE) {
+					u8 skey = hd->pLocal->sense[2] & 0x0F;
+					u8 asc = hd->pLocal->sense[12];
+					u8 ascq = hd->pLocal->sense[13];
+					ddvprintk((MYIOC_s_INFO_FMT
+						"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+						ioc->name, skey, asc, ascq));
+					if (skey == SK_ILLEGAL_REQUEST) {
+						notDone = 0;
+					} else if (skey == SK_UNIT_ATTENTION) {
+						notDone++; /* repeat */
+					} else if ((skey == SK_NOT_READY) &&
+						(asc == 0x04)&&(ascq == 0x01)) {
+						/* wait then repeat */
+						mdelay (2000);
+						notDone++;
+					} else {
+						/* All other errors are fatal.
+						 */
+						ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+							ioc->name));
+						goto target_done;
+					}
+				} else {
+					/* All other errors are fatal
+					 */
+					goto target_done;
+				}
+			}
+		}
+
+		if (iocmd.flags & MPT_ICFLAG_ECHO)
+			echoBufSize = bufsize;
+		else
+			dataBufSize = bufsize;
+	}
+	pci_free_consistent(ioc->pcidev, sz, pbuf1, buf1_dma);
+	pbuf1 = NULL;
+	sz = 0;
+	iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
+
+	/* Use echo buffers if possible,
+	 * Exit if both buffers are 0.
+	 */
+	if (echoBufSize > 0) {
+		iocmd.flags |= MPT_ICFLAG_ECHO;
+		if (dataBufSize > 0)
+			bufsize = MIN(echoBufSize, dataBufSize);
+		else
+			bufsize = echoBufSize;
+	} else if (dataBufSize == 0)
+		goto target_done;
+
+	ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
+		(iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
+
+	/* Allocate data buffers for write-read-compare test.
+	 */
+	sz = MIN(bufsize, 1024);
+	pbuf1 = pci_alloc_consistent(ioc->pcidev, sz, &buf1_dma);
+	pbuf2 = pci_alloc_consistent(ioc->pcidev, sz, &buf2_dma);
+	if (!pbuf1 || !pbuf2)
+		goto target_done;
+
+	/* --- loop ----
+	 * On first pass, always issue a reserve.
+	 * On additional loops, only if a reset has occurred.
+	 * iocmd.flags indicates if echo or regular buffer
+	 */
+	for (patt = 0; patt < 4; patt++) {
+		ddvprintk(("Pattern %d\n", patt));
+		if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
+			iocmd.cmd = CMD_TestUnitReady;
+			iocmd.data_dma = -1;
+			iocmd.data = NULL;
+			iocmd.size = 0;
+			if (mptscsih_do_cmd(hd, &iocmd) < 0)
+				goto target_done;
+
+			iocmd.cmd = CMD_Release6;
+			iocmd.data_dma = -1;
+			iocmd.data = NULL;
+			iocmd.size = 0;
+			if (mptscsih_do_cmd(hd, &iocmd) < 0)
+				goto target_done;
+			else if (hd->pLocal == NULL)
+				goto target_done;
+			else {
+				rc = hd->pLocal->completion;
+				ddvprintk(("Release rc %d\n", rc));
+				if (rc == MPT_SCANDV_GOOD)
+					iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+				else
+					goto target_done;
+			}
+			iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+		}
+		iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
+
+		repeat = 5;
+		while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
+			iocmd.cmd = CMD_Reserve6;
+			iocmd.data_dma = -1;
+			iocmd.data = NULL;
+			iocmd.size = 0;
+			if (mptscsih_do_cmd(hd, &iocmd) < 0)
+				goto target_done;
+			else if (hd->pLocal == NULL)
+				goto target_done;
+			else {
+				rc = hd->pLocal->completion;
+				if (rc == MPT_SCANDV_GOOD) {
+					iocmd.flags |= MPT_ICFLAG_RESERVED;
+				} else if (rc == MPT_SCANDV_SENSE) {
+					/* Wait if coming ready
+					 */
+					u8 skey = hd->pLocal->sense[2] & 0x0F;
+					u8 asc = hd->pLocal->sense[12];
+					u8 ascq = hd->pLocal->sense[13];
+					ddvprintk((MYIOC_s_INFO_FMT
+						"DV: Reserve Failed: ", ioc->name));
+					ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+							skey, asc, ascq));
+
+					if ((skey == SK_NOT_READY) && (asc == 0x04)&&
+									(ascq == 0x01)) {
+						/* wait then repeat */
+						mdelay (2000);
+						notDone++;
+					} else {
+						ddvprintk((MYIOC_s_INFO_FMT 
+							"DV: Reserved Failed.", ioc->name));
+						goto target_done;
+					}
+				} else {
+					ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
+							 ioc->name));
+					goto target_done;
+				}
+			}
+		}
+
+		mptscsih_fillbuf(pbuf1, sz, patt, 1);
+		iocmd.cmd = CMD_WriteBuffer;
+		iocmd.data_dma = buf1_dma;
+		iocmd.data = pbuf1;
+		iocmd.size = sz;
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			goto target_done;
+		else if (hd->pLocal == NULL)
+			goto target_done;
+		else {
+			rc = hd->pLocal->completion;
+			if (rc == MPT_SCANDV_GOOD)
+				;		/* Issue read buffer */
+			else if (rc == MPT_SCANDV_DID_RESET) {
+				/* If using echo buffers, reset to data buffers.
+				 * Else do Fallback and restart
+				 * this test (re-issue reserve
+				 * because of bus reset).
+				 */
+				if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
+					iocmd.flags &= ~MPT_ICFLAG_ECHO;
+				} else {
+					dv.cmd = MPT_FALLBACK;
+					mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+					if (mpt_config(hd->ioc, &cfg) != 0)
+						goto target_done;
+
+					if ((!dv.now.width) && (!dv.now.offset))
+						goto target_done;
+				}
+
+				iocmd.flags |= MPT_ICFLAG_DID_RESET;
+				patt = -1;
+				continue;
+			} else if (rc == MPT_SCANDV_SENSE) {
+				/* Restart data test if UA, else quit.
+				 */
+				u8 skey = hd->pLocal->sense[2] & 0x0F;
+				ddvprintk((MYIOC_s_INFO_FMT
+					"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+					hd->pLocal->sense[12], hd->pLocal->sense[13]));
+				if (skey == SK_UNIT_ATTENTION) {
+					patt = -1;
+					continue;
+				} else if (skey == SK_ILLEGAL_REQUEST) {
+					if (iocmd.flags & MPT_ICFLAG_ECHO) {
+						if (dataBufSize >= bufsize) {
+							iocmd.flags &= ~MPT_ICFLAG_ECHO;
+							patt = -1;
+							continue;
+						}
+					} 
+					goto target_done;
+				}
+				else
+					goto target_done;
+			} else {
+				/* fatal error */
+				goto target_done;
+			}
+		}
+
+		iocmd.cmd = CMD_ReadBuffer;
+		iocmd.data_dma = buf2_dma;
+		iocmd.data = pbuf2;
+		iocmd.size = sz;
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			goto target_done;
+		else if (hd->pLocal == NULL)
+			goto target_done;
+		else {
+			rc = hd->pLocal->completion;
+			if (rc == MPT_SCANDV_GOOD) {
+				 /* If buffers compare,
+				  * go to next pattern,
+				  * else, do a fallback and restart
+				  * data transfer test.
+				  */
+				if (memcmp (pbuf1, pbuf2, sz) == 0) {
+					; /* goto next pattern */
+				} else {
+					/* Miscompare with Echo buffer, go to data buffer,
+					 * if that buffer exists.
+					 * Miscompare with Data buffer, check first 4 bytes,
+					 * some devices return capacity. Exit in this case.
+					 */
+					if (iocmd.flags & MPT_ICFLAG_ECHO) {
+						if (dataBufSize >= bufsize)
+							iocmd.flags &= ~MPT_ICFLAG_ECHO;
+						else
+							goto target_done;
+					} else {
+						if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
+							/* Argh. Device returning wrong data.
+							 * Quit DV for this device.
+							 */
+							goto target_done;
+						}
+
+						/* Had an actual miscompare. Slow down.*/
+						dv.cmd = MPT_FALLBACK;
+						mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+						if (mpt_config(hd->ioc, &cfg) != 0)
+							goto target_done;
+
+						if ((!dv.now.width) && (!dv.now.offset))
+							goto target_done;
+					}
+
+					patt = -1;
+					continue;
+				}
+			} else if (rc == MPT_SCANDV_DID_RESET) {
+				/* Do Fallback and restart
+				 * this test (re-issue reserve
+				 * because of bus reset).
+				 */
+				dv.cmd = MPT_FALLBACK;
+				mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+				if (mpt_config(hd->ioc, &cfg) != 0)
+					 goto target_done;
+
+				if ((!dv.now.width) && (!dv.now.offset))
+					goto target_done;
+
+				iocmd.flags |= MPT_ICFLAG_DID_RESET;
+				patt = -1;
+				continue;
+			} else if (rc == MPT_SCANDV_SENSE) {
+				/* Restart data test if UA, else quit.
+				 */
+				u8 skey = hd->pLocal->sense[2] & 0x0F;
+				ddvprintk((MYIOC_s_INFO_FMT
+					"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+					hd->pLocal->sense[12], hd->pLocal->sense[13]));
+				if (skey == SK_UNIT_ATTENTION) {
+					patt = -1;
+					continue;
+				}
+				else
+					goto target_done;
+			} else {
+				/* fatal error */
+				goto target_done;
+			}
+		}
+
+	} /* --- end of patt loop ---- */
+
+target_done:
+	if (iocmd.flags & MPT_ICFLAG_RESERVED) {
+		iocmd.cmd = CMD_Release6;
+		iocmd.data_dma = -1;
+		iocmd.data = NULL;
+		iocmd.size = 0;
+		if (mptscsih_do_cmd(hd, &iocmd) < 0)
+			printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
+					ioc->name, id);
+		else if (hd->pLocal) {
+			if (hd->pLocal->completion == MPT_SCANDV_GOOD)
+				iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+		} else {
+			printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", 
+						ioc->name, id);
+		}
+	}
+
+
+	/* Set if cfg1_dma_addr contents is valid
+	 */
+	if (cfg.hdr != NULL) {
+		dv.cmd = MPT_SAVE;
+		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+		/* Save the final negotiated settings to
+		 * SCSI device page 1.
+		 */
+		cfg.hdr = &header1;
+		cfg.physAddr = cfg1_dma_addr;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+		cfg.dir = 1;
+		mpt_config(hd->ioc, &cfg);
+	}
+
+	/* If this is a RAID Passthrough, enable internal IOs
+	 */
+	if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
+		if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
+			ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+	}
+
+	/* Done with the DV scan of the current target
+	 */
+	if (pcfg0Data) {
+		pci_free_consistent(ioc->pcidev, header0.PageLength * 4,
+						pcfg0Data, cfg0_dma_addr);
+	}
+
+	if (pcfg1Data) {
+		pci_free_consistent(ioc->pcidev, header1.PageLength * 4,
+						pcfg1Data, cfg1_dma_addr);
+	}
+
+	if (pbuf1) {
+		pci_free_consistent(ioc->pcidev, sz, pbuf1, buf1_dma);
+		pbuf1 = NULL;
+	}
+
+	if (pbuf2) {
+		pci_free_consistent(ioc->pcidev, sz, pbuf2, buf2_dma);
+		pbuf2 = NULL;
+	}
+
+	ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
+			ioc->name, atomic_read(&queue_depth)));
+
+	return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_dv_parms - perform a variety of operations on the
+ *	parameters used for negotiation.
+ *	@hd: Pointer to a SCSI host.
+ *	@dv: Pointer to a structure that contains the maximum and current
+ *		negotiated parameters.
+ */
+static void
+mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
+{
+	VirtDevice		*pTarget = NULL;
+	SCSIDevicePage0_t	*pPage0 = NULL;
+	SCSIDevicePage1_t	*pPage1 = NULL;
+	int			val = 0, data, configuration;
+	u8			width = 0;
+	u8			offset = 0;
+	u8			factor = 0;
+	u8			negoFlags = 0;
+	u8			cmd = dv->cmd;
+	u8			id = dv->id;
+
+	switch (cmd) {
+	case MPT_GET_NVRAM_VALS:
+		ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
+							 hd->ioc->name));
+		/* Get the NVRAM values and save in tmax
+		 * If not an LVD bus, the adapter minSyncFactor has been
+		 * already throttled back.
+		 */
+		if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
+			width = pTarget->maxWidth;
+			offset = pTarget->maxOffset;
+			factor = pTarget->minSyncFactor;
+			negoFlags = pTarget->negoFlags;
+		} else {
+			if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+				data = hd->ioc->spi_data.nvram[id];
+				width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+				if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
+					factor = MPT_ASYNC;
+				else {
+					factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+					if ((factor == 0) || (factor == MPT_ASYNC)){
+						factor = MPT_ASYNC;
+						offset = 0;
+					}
+				}
+			} else {
+				width = MPT_NARROW;
+				offset = 0;
+				factor = MPT_ASYNC;
+			}
+
+			/* Set the negotiation flags */
+			negoFlags = 0;
+			if (!width)
+				negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+			if (!offset)
+				negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+		}
+
+		/* limit by adapter capabilities */
+		width = MIN(width, hd->ioc->spi_data.maxBusWidth);
+		offset = MIN(offset, hd->ioc->spi_data.maxSyncOffset);
+		factor = MAX(factor, hd->ioc->spi_data.minSyncFactor);
+
+		/* Check Consistency */
+		if (offset && (factor < MPT_ULTRA2) && !width)
+			factor = MPT_ULTRA2;
+
+		dv->max.width = width;
+		dv->max.offset = offset;
+		dv->max.factor = factor;
+		dv->max.flags = negoFlags;
+		ddvprintk((" width %d, factor %x, offset %x flags %x\n",
+				width, factor, offset, negoFlags));
+		break;
+
+	case MPT_UPDATE_MAX:
+		ddvprintk((MYIOC_s_NOTE_FMT
+			"Updating with SDP0 Data: ", hd->ioc->name));
+		/* Update tmax values with those from Device Page 0.*/
+		pPage0 = (SCSIDevicePage0_t *) pPage;
+		if (pPage0) {
+			val = cpu_to_le32(pPage0->NegotiatedParameters);
+			dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
+			dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
+			dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
+		}
+
+		dv->now.width = dv->max.width;
+		dv->now.offset = dv->max.offset;
+		dv->now.factor = dv->max.factor;
+		ddvprintk(("width %d, factor %x, offset %x, flags %x\n",
+				dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
+		break;
+
+	case MPT_SET_MAX:
+		ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
+								hd->ioc->name));
+		/* Set current to the max values. Update the config page.*/
+		dv->now.width = dv->max.width;
+		dv->now.offset = dv->max.offset;
+		dv->now.factor = dv->max.factor;
+		dv->now.flags = dv->max.flags;
+
+		pPage1 = (SCSIDevicePage1_t *)pPage;
+		if (pPage1) {
+			mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
+				dv->now.offset, &val, &configuration, dv->now.flags);
+			pPage1->RequestedParameters = le32_to_cpu(val);
+			pPage1->Reserved = 0;
+			pPage1->Configuration = le32_to_cpu(configuration);
+
+		}
+
+		ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n",
+				dv->now.width, dv->now.factor, dv->now.offset, val, configuration));
+		break;
+
+	case MPT_SET_MIN:
+		ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
+								hd->ioc->name));
+		/* Set page to asynchronous and narrow 
+		 * Do not update now, breaks fallback routine. */
+		width = MPT_NARROW;
+		offset = 0;
+		factor = MPT_ASYNC;
+		negoFlags = dv->max.flags;
+
+		pPage1 = (SCSIDevicePage1_t *)pPage;
+		if (pPage1) {
+			mptscsih_setDevicePage1Flags (width, factor,
+				offset, &val, &configuration, negoFlags);
+			pPage1->RequestedParameters = le32_to_cpu(val);
+			pPage1->Reserved = 0;
+			pPage1->Configuration = le32_to_cpu(configuration);
+		}
+		ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
+				dv->now.width, dv->now.factor,
+				dv->now.offset, val, configuration));
+		break;
+
+	case MPT_FALLBACK:
+		ddvprintk((MYIOC_s_NOTE_FMT
+			"Fallback: Start: offset %d, factor %x, width %d \n",
+				hd->ioc->name, dv->now.offset, 
+				dv->now.factor, dv->now.width));
+		width = dv->now.width;
+		offset = dv->now.offset;
+		factor = dv->now.factor;
+		if ((offset) && (dv->max.width)) {
+			if (factor < MPT_ULTRA160)
+				factor = MPT_ULTRA160;
+			else if (factor < MPT_ULTRA2) {
+				factor = MPT_ULTRA2;
+				width = MPT_WIDE;
+			} else if ((factor == MPT_ULTRA2) && width) {
+				factor = MPT_ULTRA2;
+				width = MPT_NARROW;
+			} else if (factor < MPT_ULTRA) {
+				factor = MPT_ULTRA;
+				width = MPT_WIDE;
+			} else if ((factor == MPT_ULTRA) && width) {
+				factor = MPT_ULTRA;
+				width = MPT_NARROW;
+			} else if (factor < MPT_FAST) {
+				factor = MPT_FAST;
+				width = MPT_WIDE;
+			} else if ((factor == MPT_FAST) && width) {
+				factor = MPT_FAST;
+				width = MPT_NARROW;
+			} else if (factor < MPT_SCSI) {
+				factor = MPT_SCSI;
+				width = MPT_WIDE;
+			} else if ((factor == MPT_SCSI) && width) {
+				factor = MPT_SCSI;
+				width = MPT_NARROW;
+			} else {
+				factor = MPT_ASYNC;
+				offset = 0;
+			}
+
+		} else if (offset) {
+			width = MPT_NARROW;
+			if (factor < MPT_ULTRA)
+				factor = MPT_ULTRA;
+			else if (factor < MPT_FAST)
+				factor = MPT_FAST;
+			else if (factor < MPT_SCSI)
+				factor = MPT_SCSI;
+			else {
+				factor = MPT_ASYNC;
+				offset = 0;
+			}
 
-	if (SD_Sense_Key_Specific_Valid(sd)) {
-		if (SenseKey == SK_ILLEGAL_REQUEST) {
-			Offset = SD_Bad_Byte(sd);
-			if (SD_Was_Illegal_Request(sd)) {
-				BadValue = ioop->cdbPtr[Offset];
-				len += sprintf(msg1+len, "\n  Illegal CDB value=%02Xh found at CDB ",
-						BadValue);
 		} else {
-			BadValue = ioop->dataPtr[Offset];
-			len += sprintf(msg1+len, "\n  Illegal DATA value=%02Xh found at DATA ",
-					BadValue);
+			width = MPT_NARROW;
+			factor = MPT_ASYNC;
 		}
-		len += sprintf(msg1+len, "byte=%02Xh", Offset);
-		if (SD_SKS_Bit_Pointer_Valid(sd))
-			len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
-		} else if ((SenseKey == SK_RECOVERED_ERROR) ||
-			   (SenseKey == SK_HARDWARE_ERROR) ||
-			   (SenseKey == SK_MEDIUM_ERROR)) {
-			len += sprintf(msg1+len, "\n  Recovery algorithm Actual_Retry_Count=%02Xh",
-			SD_Actual_Retry_Count(sd));
+
+		dv->now.width = width;
+		dv->now.offset = offset;
+		dv->now.factor = factor;
+		dv->now.flags = dv->max.flags;
+
+		pPage1 = (SCSIDevicePage1_t *)pPage;
+		if (pPage1) {
+			mptscsih_setDevicePage1Flags (width, factor, offset, &val,
+						&configuration, dv->now.flags);
+
+			pPage1->RequestedParameters = le32_to_cpu(val);
+			pPage1->Reserved = 0;
+			pPage1->Configuration = le32_to_cpu(configuration);
 		}
-	}
-}
-#endif
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int dump_cdb(char *foo, unsigned char *cdb)
-{
-	int i, grpCode, cdbLen;
-	int l = 0;
+		ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n",
+			     dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
+		break;
 
-	grpCode = cdb[0] >> 5;
-	if (grpCode < 1)
-		cdbLen = 6;
-	else if (grpCode < 3)
-		cdbLen = 10;
-	else if (grpCode == 5)
-		cdbLen = 12;
-	else
-		cdbLen = 16;
+	case MPT_SAVE:
+		ddvprintk((MYIOC_s_NOTE_FMT
+			"Saving to Target structure: ", hd->ioc->name));
+		ddvprintk(("offset %d, factor %x, width %d \n",
+			     dv->now.offset, dv->now.factor, dv->now.width));
 
-	for (i=0; i < cdbLen; i++)
-		l += sprintf(foo+l, " %02X", cdb[i]);
+		/* Save these values to target structures
+		 * or overwrite nvram (phys disks only).
+		 */
 
-	return l;
-}
+		if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
+			pTarget->maxWidth = dv->now.width;
+			pTarget->maxOffset = dv->now.offset;
+			pTarget->minSyncFactor = dv->now.factor;
+		} else {
+			/* Preserv all flags, use
+			 * read-modify-write algorithm
+			 */
+			data = hd->ioc->spi_data.nvram[id];
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int dump_sd(char *foo, unsigned char *sd)
-{
-	int snsLen = 8 + SD_Additional_Sense_Length(sd);
-	int l = 0;
-	int i;
+			if (dv->now.width)
+				data &= ~MPT_NVRAM_WIDE_DISABLE;
+			else
+				data |= MPT_NVRAM_WIDE_DISABLE;
 
-	for (i=0; i < MIN(snsLen,18); i++)
-		l += sprintf(foo+l, " %02X", sd[i]);
-	l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+			if (!dv->now.offset)
+				factor = MPT_ASYNC;
 
-	return l;
+			data &= ~MPT_NVRAM_SYNC_MASK;
+			data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
+
+			hd->ioc->spi_data.nvram[id] = data;
+		}
+		break;
+	}
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
-static const char * ascq_set_strings_4max(
-		u8 ASC, u8 ASCQ,
-		const char **s1, const char **s2, const char **s3, const char **s4)
+/*	mptscsih_fillbuf - fill a buffer with a special data pattern
+ *		cleanup. For bus scan only.
+ *
+ *	@buffer: Pointer to data buffer to be filled.
+ *	@size: Number of bytes to fill
+ *	@index: Pattern index
+ *	@width: bus width, 0 (8 bits) or 1 (16 bits)
+ */
+static void
+mptscsih_fillbuf(char *buffer, int size, int index, int width)
 {
-	static const char *asc_04_part1_string = "LOGICAL UNIT ";
-	static const char *asc_04_part2a_string = "NOT READY, ";
-	static const char *asc_04_part2b_string = "IS ";
-	static const char *asc_04_ascq_NN_part3_strings[] = {	/* ASC ASCQ (hex) */
-	  "CAUSE NOT REPORTABLE",				/* 04 00 */
-	  "IN PROCESS OF BECOMING READY",			/* 04 01 */
-	  "INITIALIZING CMD. REQUIRED",				/* 04 02 */
-	  "MANUAL INTERVENTION REQUIRED",			/* 04 03 */
-	  /* Add	" IN PROGRESS" to all the following... */
-	  "FORMAT",						/* 04 04 */
-	  "REBUILD",						/* 04 05 */
-	  "RECALCULATION",					/* 04 06 */
-	  "OPERATION",						/* 04 07 */
-	  "LONG WRITE",						/* 04 08 */
-	  "SELF-TEST",						/* 04 09 */
-	  NULL
-	};
-	static char *asc_04_part4_string = " IN PROGRESS";
+	char *ptr = buffer;
+	int ii;
+	char byte;
+	short val;
 
-	static char *asc_29_ascq_NN_strings[] = {		/* ASC ASCQ (hex) */
-	  "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",	/* 29 00 */
-	  "POWER ON OCCURRED",					/* 29 01 */
-	  "SCSI BUS RESET OCCURRED",				/* 29 02 */
-	  "BUS DEVICE RESET FUNCTION OCCURRED",			/* 29 03 */
-	  "DEVICE INTERNAL RESET",				/* 29 04 */
-	  "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED",		/* 29 05 */
-	  "TRANSCEIVER MODE CHANGED TO LVD",			/* 29 06 */
-	  NULL
-	};
-	static char *ascq_vendor_uniq = "(Vendor Unique)";
-	static char *ascq_noone = "(no matching ASC/ASCQ description found)";
-	int idx;
+	switch (index) {
+	case 0:
 
-	*s1 = *s2 = *s3 = *s4 = "";		/* set'em all to the empty "" string */
+		if (width) {
+			/* Pattern:  0000 FFFF 0000 FFFF
+			 */
+			for (ii=0; ii < size; ii++, ptr++) {
+				if (ii & 0x02)
+					*ptr = 0xFF;
+				else
+					*ptr = 0x00;
+			}
+		} else {
+			/* Pattern:  00 FF 00 FF
+			 */
+			for (ii=0; ii < size; ii++, ptr++) {
+				if (ii & 0x01)
+					*ptr = 0xFF;
+				else
+					*ptr = 0x00;
+			}
+		}
+		break;
 
-	/* CHECKME! Need lock/sem?
-	 *  Update and examine for isense module presense.
-	 */
-	mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+	case 1:
+		if (width) {
+			/* Pattern:  5555 AAAA 5555 AAAA 5555
+			 */
+			for (ii=0; ii < size; ii++, ptr++) {
+				if (ii & 0x02)
+					*ptr = 0xAA;
+				else
+					*ptr = 0x55;
+			}
+		} else {
+			/* Pattern:  55 AA 55 AA 55
+			 */
+			for (ii=0; ii < size; ii++, ptr++) {
+				if (ii & 0x01)
+					*ptr = 0xAA;
+				else
+					*ptr = 0x55;
+			}
+		}
+		break;
 
-	if (mptscsih_ASCQ_TablePtr == NULL) {
-		/* 2nd chances... */
-		if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
-			*s1 = asc_04_part1_string;
-			*s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
-			*s3 = asc_04_ascq_NN_part3_strings[ASCQ];
-			/* check for " IN PROGRESS" ones */
-			if (ASCQ >= 0x04)
-				*s4 = asc_04_part4_string;
-		} else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
-			*s1 = asc_29_ascq_NN_strings[ASCQ];
-		/*
-		 *	else { leave all *s[1-4] values pointing to the empty "" string }
+	case 2:
+		/* Pattern:  00 01 02 03 04 05
+		 * ... FE FF 00 01..
 		 */
-		return *s1;
-	}
+		for (ii=0; ii < size; ii++, ptr++)
+			*ptr = (char) ii;
+		break;
 
-	/*
-	 *  Need to check ASC here; if it is "special," then
-	 *  the ASCQ is variable, and indicates failed component number.
-	 *  We must treat the ASCQ as a "don't care" while searching the
-	 *  mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
-	 *  on when we actually need to identify the failed component.
-	 */
-	if (SPECIAL_ASCQ(ASC,ASCQ))
-		ASCQ = 0xFF;
+	case 3:
+		if (width) {
+			/* Wide Pattern:  FFFE 0001 FFFD 0002
+			 * ...  4000 DFFF 8000 EFFF
+			 */
+			byte = 0;
+			for (ii=0; ii < size/2; ii++) {
+				/* Create the base pattern
+				 */
+				val = (1 << byte);
+				/* every 64 (0x40) bytes flip the pattern
+				 * since we fill 2 bytes / iteration,
+				 * test for ii = 0x20
+				 */
+				if (ii & 0x20)
+					val = ~(val);
 
-	/*  OK, now search mptscsih_ASCQ_Table[] for a matching entry  */
-	for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
-		if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ))
-			return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description);
+				if (ii & 0x01) {
+					*ptr = (char)( (val & 0xFF00) >> 8);
+					ptr++;
+					*ptr = (char)(val & 0xFF);
+					byte++;
+					byte &= 0x0F;
+				} else {
+					val = ~val;
+					*ptr = (char)( (val & 0xFF00) >> 8);
+					ptr++;
+					*ptr = (char)(val & 0xFF);
+				}
 
-	if ((ASC >= 0x80) || (ASCQ >= 0x80))
-		*s1 = ascq_vendor_uniq;
-	else
-		*s1 = ascq_noone;
+				ptr++;
+			}
+		} else {
+			/* Narrow Pattern:  FE 01 FD 02 FB 04
+			 * .. 7F 80 01 FE 02 FD ...  80 7F
+			 */
+			byte = 0;
+			for (ii=0; ii < size; ii++, ptr++) {
+				/* Base pattern - first 32 bytes
+				 */
+				if (ii & 0x01) {
+					*ptr = (1 << byte);
+					byte++;
+					byte &= 0x07;
+				} else {
+					*ptr = (char) (~(1 << byte));
+				}
 
-	return *s1;
+				/* Flip the pattern every 32 bytes
+				 */
+				if (ii & 0x20)
+					*ptr = ~(*ptr);
+			}
+		}
+		break;
+	}
 }
+#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  SCSI Error Report; desired output format...
- *---
-SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
-  SCSI_Status=02h (CHECK CONDITION)
-  Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
-  SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
-  SenseKey=6h (UNIT ATTENTION); FRU=03h
-  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
- *---
+/* Commandline Parsing routines and defines.
+ *
+ * insmod format:
+ *	insmod mptscsih mptscsih="width:1 dv:n factor:0x09"
+ *  boot format:
+ *	mptscsih=width:1,dv:n,factor:0x8
+ *
  */
+#ifdef MODULE
+#define	ARG_SEP	' '
+#else
+#define	ARG_SEP	','
+#endif
 
-int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
-{
-	char		 foo[512];
-	char		 buf2[32];
-	char		*statstr;
-	const char	*opstr;
-	int		 sk		= SD_Sense_Key(ioop->sensePtr);
-	const char	*skstr		= SenseKeyString[sk];
-	unsigned char	 asc		= SD_ASC(ioop->sensePtr);
-	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
-	int		 l;
+static char setup_token[] __initdata =
+	"dv:"
+	"width:"
+	"factor:"
+       ;	/* DONNOT REMOVE THIS ';' */
+
+#define OPT_DV			1
+#define OPT_MAX_WIDTH		2
+#define OPT_MIN_SYNC_FACTOR	3
 
-	/*
-	 *  More quiet mode.
-	 *  Filter out common, repetitive, warning-type errors...  like:
-	 *    POWER ON (06,29/00 or 06,29/01),
-	 *    SPINNING UP (02,04/01),
-	 *    LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
-	 */
-	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
-	     || (sk==SK_NOT_READY	&& asc==0x04 && ascq==0x01)
-	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
-	   )
-	{
-		/* Do nothing! */
-		return 0;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+__init get_setup_token(char *p)
+{
+	char *cur = setup_token;
+	char *pc;
+	int i = 0;
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		++pc;
+		++i;
+		if (!strncmp(p, cur, pc - cur))
+			return i;
+		cur = pc;
 	}
+	return 0;
+}
 
-	/*
-	 *  Protect ourselves...
-	 */
-	if (ioop->cdbPtr == NULL)
-		ioop->cdbPtr = dummyCDB;
-	if (ioop->sensePtr == NULL)
-		ioop->sensePtr = dummySenseData;
-	if (ioop->inqPtr == NULL)
-		ioop->inqPtr = dummyInqData;
-	if (ioop->dataPtr == NULL)
-		ioop->dataPtr = dummyScsiData;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+__init mptscsih_setup(char *str)
+{
+	char *cur = str;
+	char *pc, *pv;
+	unsigned long val;
+	int  c;
+
+	printk("KERN_WARNING: mptscsih_setup arg %s\n", str);
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		char *pe;
+
+		val = 0;
+		pv = pc;
+		c = *++pv;
+
+		if	(c == 'n')
+			val = 0;
+		else if	(c == 'y')
+			val = 1;
+		else
+			val = (int) simple_strtoul(pv, &pe, 0);
 
-	statstr = NULL;
-	if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
-	    ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
-		(void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
-		statstr = buf2;
-	}
+		printk("Found Token: %s, value %x\n", cur, (int)val);
+		switch (get_setup_token(cur)) {
+		case OPT_DV:
+			driver_setup.dv = val;
+			break;
 
-	opstr = NULL;
-	if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
-		opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
-	else if (mpt_ScsiOpcodesPtr)
-		opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
+		case OPT_MAX_WIDTH:
+			driver_setup.max_width = val;
+			break;
 
-	l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
-	  "  SCSI_Status=%02Xh (%s)\n"
-	  "  Original_CDB[]:",
-			ioop->DevIDStr,
-			ioop->SCSIStatus,
-			statstr);
-	l += dump_cdb(foo+l, ioop->cdbPtr);
-	if (opstr)
-		l += sprintf(foo+l, " - \"%s\"", opstr);
-	l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
-	l += dump_sd(foo+l, ioop->sensePtr);
-	l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
-			sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
+		case OPT_MIN_SYNC_FACTOR:
+			driver_setup.min_sync_fac = val;
+			break;
 
-	{
-		const char	*x1, *x2, *x3, *x4;
-		x1 = x2 = x3 = x4 = "";
-		x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
-		if (x1 != NULL) {
-			if (x1[0] != '(')
-				l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
-			else
-				l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
+		default:
+			printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+			break;
 		}
-	}
-
-#if 0
-	if (SPECIAL_ASCQ(asc,ascq))
-		l += sprintf(foo+l, " (%02Xh)", ascq);
-#endif
-
-	PrintF(("%s\n", foo));
 
-	return l;
+		if ((cur = strchr(cur, ARG_SEP)) != NULL)
+			++cur;
+	}
+	return 1;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -urN linux-2.4.19-pre4/drivers/message/fusion/mptscsih.h linux-2.4.19-pre5/drivers/message/fusion/mptscsih.h
--- linux-2.4.19-pre4/drivers/message/fusion/mptscsih.h	Fri Jul  6 17:03:11 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/mptscsih.h	Fri Mar 29 14:49:34 2002
@@ -15,11 +15,12 @@
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $
+ *  $Id: mptscsih.h,v 1.16 2002/02/27 18:44:30 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -68,14 +69,47 @@
  *	SCSI Public stuff...
  */
 
-#ifdef __sparc__
-#define MPT_SCSI_CAN_QUEUE	63
-#define MPT_SCSI_CMD_PER_LUN	63
-	/* FIXME!  Still investigating qd=64 hang on sparc64... */
-#else
-#define MPT_SCSI_CAN_QUEUE	64
-#define MPT_SCSI_CMD_PER_LUN	64
-#endif
+/*
+ *	Try to keep these at 2^N-1
+ */
+#define MPT_FC_CAN_QUEUE	63
+#define MPT_SCSI_CAN_QUEUE	31
+#define MPT_SCSI_CMD_PER_LUN	 7
+
+#define MPT_SCSI_SG_DEPTH	40
+
+/* To disable domain validation, uncomment the
+ * following line. No effect for FC devices.
+ * For SCSI devices, driver will negotiate to
+ * NVRAM settings (if available) or to maximum adapter
+ * capabilities.
+ */
+/* #define MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+
+/* SCSI driver setup structure. Settings can be overridden
+ * by command line options.
+ */
+#define MPTSCSIH_DOMAIN_VALIDATION      1
+#define MPTSCSIH_MAX_WIDTH              1
+#define MPTSCSIH_MIN_SYNC               0x08
+
+struct mptscsih_driver_setup
+{
+        u8      dv;
+        u8      max_width;
+        u8      min_sync_fac;
+};
+
+
+#define MPTSCSIH_DRIVER_SETUP                   \
+{                                               \
+        MPTSCSIH_DOMAIN_VALIDATION,             \
+        MPTSCSIH_MAX_WIDTH,                     \
+        MPTSCSIH_MIN_SYNC,                      \
+}
+
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -143,6 +177,7 @@
 #define x_scsi_dev_reset	mptscsih_dev_reset
 #define x_scsi_host_reset	mptscsih_host_reset
 #define x_scsi_bios_param	mptscsih_bios_param
+#define x_scsi_select_queue_depths	mptscsih_select_queue_depths
 
 #define x_scsi_taskmgmt_bh	mptscsih_taskmgmt_bh
 #define x_scsi_old_abort	mptscsih_old_abort
@@ -155,7 +190,6 @@
 extern	int		 x_scsi_detect(Scsi_Host_Template *);
 extern	int		 x_scsi_release(struct Scsi_Host *host);
 extern	const char	*x_scsi_info(struct Scsi_Host *);
-/*extern	int		 x_scsi_command(Scsi_Cmnd *);*/
 extern	int		 x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 #ifdef MPT_SCSI_USE_NEW_EH
 extern	int		 x_scsi_abort(Scsi_Cmnd *);
@@ -167,6 +201,7 @@
 extern	int		 x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
 #endif
 extern	int		 x_scsi_bios_param(Disk *, kdev_t, int *);
+extern	void		 x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
 extern	void		 x_scsi_taskmgmt_bh(void *);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -194,7 +229,7 @@
 	bios_param:			x_scsi_bios_param,	\
 	can_queue:			MPT_SCSI_CAN_QUEUE,	\
 	this_id:			-1,			\
-	sg_tablesize:			25,			\
+	sg_tablesize:			MPT_SCSI_SG_DEPTH,	\
 	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
 	unchecked_isa_dma:		0,			\
 	use_clustering:			ENABLE_CLUSTERING,	\
@@ -217,7 +252,7 @@
 	bios_param:			x_scsi_bios_param,	\
 	can_queue:			MPT_SCSI_CAN_QUEUE,	\
 	this_id:			-1,			\
-	sg_tablesize:			25,			\
+	sg_tablesize:			MPT_SCSI_SG_DEPTH,	\
 	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
 	unchecked_isa_dma:		0,			\
 	use_clustering:			ENABLE_CLUSTERING	\
diff -urN linux-2.4.19-pre4/drivers/message/fusion/scsi3.h linux-2.4.19-pre5/drivers/message/fusion/scsi3.h
--- linux-2.4.19-pre4/drivers/message/fusion/scsi3.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre5/drivers/message/fusion/scsi3.h	Fri Mar 29 14:49:34 2002
@@ -4,11 +4,12 @@
  *      (Ultimately) SCSI-3 definitions; for now, inheriting
  *      SCSI-2 definitions.
  *
- *  Copyright (c) 1996-2001 Steven J. Ralston
+ *  Copyright (c) 1996-2002 Steven J. Ralston
  *  Written By: Steven J. Ralston (19960517)
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: scsi3.h,v 1.5 2001/04/06 14:31:32 sralston Exp $
+ *  $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $
  */
 
 #ifndef SCSI3_H_INCLUDED
@@ -63,7 +64,10 @@
 #define CMD_Write10            0x2A
 #define CMD_WriteVerify        0x2E
 #define CMD_Verify             0x2F
+#define CMD_SynchronizeCache   0x35
 #define CMD_ReadDefectData     0x37
+#define CMD_WriteBuffer        0x3B
+#define CMD_ReadBuffer         0x3C
 #define CMD_ReadLong           0x3E
 #define CMD_LogSelect          0x4C
 #define CMD_LogSense           0x4D
diff -urN linux-2.4.19-pre4/drivers/mtd/Config.in linux-2.4.19-pre5/drivers/mtd/Config.in
--- linux-2.4.19-pre4/drivers/mtd/Config.in	Thu Oct 11 09:14:32 2001
+++ linux-2.4.19-pre5/drivers/mtd/Config.in	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 
-# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $
+# $Id: Config.in,v 1.73 2002/03/08 16:34:35 rkaiser Exp $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
@@ -12,6 +12,7 @@
       int '  Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
    fi
    dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
+   dep_tristate '  MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
diff -urN linux-2.4.19-pre4/drivers/mtd/Makefile linux-2.4.19-pre5/drivers/mtd/Makefile
--- linux-2.4.19-pre4/drivers/mtd/Makefile	Thu Oct  4 15:13:18 2001
+++ linux-2.4.19-pre5/drivers/mtd/Makefile	Fri Mar 29 14:49:34 2002
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes..
 #
-# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $
+# $Id: Makefile,v 1.65 2002/03/22 07:10:34 dwmw2 Exp $
 
 
 obj-y           += chips/chipslink.o maps/mapslink.o \
@@ -19,7 +19,7 @@
 
 O_TARGET	:= mtdlink.o
 
-export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o afs.o
+export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o
 list-multi	:= nftl.o
 
 mod-subdirs	:= 
@@ -44,6 +44,7 @@
 
 # Core functionality.
 obj-$(CONFIG_MTD)		+= mtdcore.o
+obj-$(CONFIG_MTD_CONCAT)		+= mtdconcat.o
 obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
diff -urN linux-2.4.19-pre4/drivers/mtd/afs.c linux-2.4.19-pre5/drivers/mtd/afs.c
--- linux-2.4.19-pre4/drivers/mtd/afs.c	Thu Oct  4 15:14:41 2001
+++ linux-2.4.19-pre5/drivers/mtd/afs.c	Fri Mar 29 14:49:34 2002
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $
+   $Id: afs.c,v 1.7 2001/11/01 20:04:54 rmk Exp $
 
 ======================================================================*/
 
@@ -82,6 +82,12 @@
 	if (fs.signature != 0xa0ffff9f)
 		ret = 1;
 
+	/*
+	 * Don't touch the SIB.
+	 */
+	if (fs.type == 2)
+		ret = 1;
+
 	*iis_start = fs.image_info_base & mask;
 	*img_start = fs.image_start & mask;
 
diff -urN linux-2.4.19-pre4/drivers/mtd/chips/Makefile linux-2.4.19-pre5/drivers/mtd/chips/Makefile
--- linux-2.4.19-pre4/drivers/mtd/chips/Makefile	Fri Oct  5 12:05:47 2001
+++ linux-2.4.19-pre5/drivers/mtd/chips/Makefile	Fri Mar 29 14:49:34 2002
@@ -1,7 +1,7 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $
+# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $
 
 O_TARGET	:= chipslink.o
 
@@ -20,7 +20,6 @@
 obj-$(CONFIG_MTD_CFI_AMDSTD)	+= cfi_cmdset_0002.o
 obj-$(CONFIG_MTD_CFI_INTELEXT)	+= cfi_cmdset_0001.o
 obj-$(CONFIG_MTD_GEN_PROBE)	+= gen_probe.o
-obj-$(CONFIG_MTD_INTELPROBE)	+= intel_probe.o
 obj-$(CONFIG_MTD_JEDEC)		+= jedec.o
 obj-$(CONFIG_MTD_JEDECPROBE)	+= jedec_probe.o
 obj-$(CONFIG_MTD_RAM)		+= map_ram.o
diff -urN linux-2.4.19-pre4/drivers/mtd/chips/amd_flash.c linux-2.4.19-pre5/drivers/mtd/chips/amd_flash.c
--- linux-2.4.19-pre4/drivers/mtd/chips/amd_flash.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/chips/amd_flash.c	Fri Mar 29 14:49:34 2002
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.17 2002/03/05 17:00:37 jonashg Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -52,6 +52,7 @@
 
 /* Manufacturers */
 #define MANUFACTURER_AMD	0x0001
+#define MANUFACTURER_ATMEL	0x001F
 #define MANUFACTURER_FUJITSU	0x0004
 #define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_SST	0x00BF
@@ -67,6 +68,9 @@
 #define AM29BDS323D     0x22D1
 #define AM29BDS643D	0x227E
 
+/* Atmel */
+#define AT49xV16x	0x00C0
+#define AT49xV16xT	0x00C2
 
 /* Fujitsu */
 #define MBM29LV160TE	0x22C4
@@ -613,6 +617,26 @@
 			{ offset: 0x600000, erasesize: 0x10000, numblocks: 31 },
 			{ offset: 0x7f0000, erasesize: 0x02000, numblocks:  8 },
 		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49xV16x,
+		name: "Atmel AT49xV16x",
+		size: 0x00200000,
+		numeraseregions: 2,
+		regions: {
+			{ offset: 0x000000, erasesize: 0x02000, numblocks:  8 },
+			{ offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49xV16xT,
+		name: "Atmel AT49xV16xT",
+		size: 0x00200000,
+		numeraseregions: 2,
+		regions: {
+			{ offset: 0x000000, erasesize: 0x10000, numblocks: 31 },
+			{ offset: 0x1F0000, erasesize: 0x02000, numblocks:  8 }
+		}
 	} 
 	};
 
diff -urN linux-2.4.19-pre4/drivers/mtd/chips/jedec.c linux-2.4.19-pre5/drivers/mtd/chips/jedec.c
--- linux-2.4.19-pre4/drivers/mtd/chips/jedec.c	Fri Nov  9 14:29:40 2001
+++ linux-2.4.19-pre5/drivers/mtd/chips/jedec.c	Fri Mar 29 14:49:34 2002
@@ -11,7 +11,7 @@
  * not going to guess how to send commands to them, plus I expect they will
  * all speak CFI..
  *
- * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $
+ * $Id: jedec.c,v 1.13 2002/02/08 15:57:21 rkaiser Exp $
  */
 
 #include <linux/mtd/jedec.h>
@@ -738,6 +738,7 @@
    }
        	    
    //printk("done\n");
+   instr->state = MTD_ERASE_DONE;
    if (instr->callback)
 	instr->callback(instr);
    return 0;
diff -urN linux-2.4.19-pre4/drivers/mtd/chips/sharp.c linux-2.4.19-pre5/drivers/mtd/chips/sharp.c
--- linux-2.4.19-pre4/drivers/mtd/chips/sharp.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/chips/sharp.c	Fri Mar 29 14:49:34 2002
@@ -4,7 +4,7 @@
  * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
  *           2000,2001 Lineo, Inc.
  *
- * $Id: sharp.c,v 1.6 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: sharp.c,v 1.7 2002/02/13 15:49:07 dwmw2 Exp $
  *
  * Devices supported:
  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
diff -urN linux-2.4.19-pre4/drivers/mtd/devices/doc1000.c linux-2.4.19-pre5/drivers/mtd/devices/doc1000.c
--- linux-2.4.19-pre4/drivers/mtd/devices/doc1000.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/devices/doc1000.c	Fri Mar 29 14:49:34 2002
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: doc1000.c,v 1.15 2001/10/02 15:05:13 dwmw2 Exp $
+  $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $
 
 ======================================================================*/
 
@@ -483,7 +483,7 @@
 			else
 				priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
 		}
-		else if (erase->time + erase_timeout < jiffies)
+		else if (time_after(jiffies, erase->time + erase_timeout))
 		{
 			printk("Flash erase timed out. The world is broken.\n");
 
diff -urN linux-2.4.19-pre4/drivers/mtd/devices/mtdram.c linux-2.4.19-pre5/drivers/mtd/devices/mtdram.c
--- linux-2.4.19-pre4/drivers/mtd/devices/mtdram.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/devices/mtdram.c	Fri Mar 29 14:49:34 2002
@@ -1,6 +1,6 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.26 2001/12/01 10:24:18 dwmw2 Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
@@ -123,7 +123,7 @@
    // Allocate some memory
    mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
    if (!mtd_info)
-      return 0;
+      return -ENOMEM;
    
    memset(mtd_info, 0, sizeof(*mtd_info));
 
diff -urN linux-2.4.19-pre4/drivers/mtd/devices/pmc551.c linux-2.4.19-pre5/drivers/mtd/devices/pmc551.c
--- linux-2.4.19-pre4/drivers/mtd/devices/pmc551.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/devices/pmc551.c	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.19 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.20 2002/03/05 13:47:08 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
diff -urN linux-2.4.19-pre4/drivers/mtd/ftl.c linux-2.4.19-pre5/drivers/mtd/ftl.c
--- linux-2.4.19-pre4/drivers/mtd/ftl.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/ftl.c	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -99,6 +99,13 @@
 #define request_arg_t           request_queue_t *q
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#else
+#define BLK_INC_USE_COUNT do {} while(0)
+#define BLK_DEC_USE_COUNT do {} while(0)
+#endif
 
 /*====================================================================*/
 
@@ -235,7 +242,9 @@
 };
 #else
 static struct block_device_operations ftl_blk_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
     owner:	THIS_MODULE,
+#endif
     open:	ftl_open,
     release:	ftl_close,
     ioctl:	ftl_ioctl,
@@ -895,11 +904,16 @@
     if (ftl_gendisk.part[minor].nr_sects == 0)
 	return -ENXIO;
 
-    if (!get_mtd_device(partition->mtd, -1))
-	    return /* -E'SBUGGEREDOFF */ -ENXIO;
+    BLK_INC_USE_COUNT;
 
+    if (!get_mtd_device(partition->mtd, -1)) {
+	    BLK_DEC_USE_COUNT;
+	    return -ENXIO;
+    }
+    
     if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
 	    put_mtd_device(partition->mtd);
+	    BLK_DEC_USE_COUNT;
             return -EROFS;
     }
     
@@ -920,9 +934,6 @@
     
     DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
 
-    /* Flush all writes */
-    invalidate_device(inode->i_rdev, 1);
-
     /* Wait for any pending erase operations to complete */
     if (part->mtd->sync)
 	    part->mtd->sync(part->mtd);
@@ -935,6 +946,7 @@
     atomic_dec(&part->open);
 
     put_mtd_device(part->mtd);
+    BLK_DEC_USE_COUNT;
     release_return(0);
 } /* ftl_close */
 
@@ -1171,9 +1183,11 @@
     case BLKGETSIZE:
 	ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
 	break;
+#ifdef BLKGETSIZE64
     case BLKGETSIZE64:
 	ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
 	break;
+#endif
     case BLKRRPART:
 	ret = ftl_reread_partitions(minor);
 	break;
@@ -1401,7 +1415,7 @@
 
     memset(myparts, 0, sizeof(myparts));
     
-    DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n");
+    DEBUG(0, "$Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $\n");
     
     if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
 	printk(KERN_NOTICE "ftl_cs: unable to grab major "
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/Config.in linux-2.4.19-pre5/drivers/mtd/maps/Config.in
--- linux-2.4.19-pre4/drivers/mtd/maps/Config.in	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/maps/Config.in	Fri Mar 29 14:49:34 2002
@@ -1,12 +1,12 @@
 # drivers/mtd/maps/Config.in
 
-# $Id: Config.in,v 1.16 2001/09/19 18:28:37 dwmw2 Exp $
+# $Id: Config.in,v 1.28 2002/03/08 16:34:35 rkaiser Exp $
 
 mainmenu_option next_comment
 
 comment 'Mapping drivers for chip access'
 
-dep_tristate '  CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
+dep_tristate '  CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE
 if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
    hex '    Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
    hex '    Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
@@ -23,16 +23,23 @@
    dep_tristate '  CFI Flash device mapped on AMD NetSc520'  CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
    dep_tristate '  CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
    dep_tristate '  CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
+   dep_tristate '  CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT
+   if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then
+     hex '    Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000
+   fi
    dep_tristate '  JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
-   dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_I386 $CONFIG_MTD_JEDEC
+   dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
+   dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE   
+   dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
 fi
 
 if [ "$CONFIG_PPC" = "y" ]; then
-   dep_tristate '  CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL $CONFIG_PPC
-   dep_tristate '  CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI $CONFIG_PPC
-   dep_tristate '  CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI_INTELSTD $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI_AMDSTD
+   dep_tristate '  CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL
+   dep_tristate '  CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
+   dep_tristate '  System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI
+   dep_tristate '  CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI
    dep_tristate '  CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
 fi
 
@@ -52,8 +59,12 @@
    dep_tristate '  Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT
 fi
 
-if [ "$CONFIG_SH" = "y" ]; then
-   dep_tristate '  CFI Flash device mapped on Hitachi SolutionEngine' CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_CFI $CONFIG_SH $CONFIG_MTD_REDBOOT_PARTS
+if [ "$CONFIG_SUPERH" = "y" ]; then
+   dep_tristate '  CFI Flash device mapped on Hitachi SolutionEngine' \
+      CONFIG_MTD_SOLUTIONENGINE $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CFI
+   if [ "$CONFIG_MTD_SOLUTIONENGINE" != "n" ]; then
+      hex '  Default reserved Flash size'  CONFIG_MTD_SUPERH_RESERVE 0x00010000
+   fi
 fi
 
 if [ "$CONFIG_ARM" = "y" ]; then
@@ -63,6 +74,14 @@
    dep_tristate '  CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
    dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
    dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
+   dep_tristate '  CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI  $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+   dep_tristate '  NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
 fi
+if [ "$CONFIG_ALPHA" = "y" ]; then
+   dep_tristate '  Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE
+fi
+
+# This needs CFI or JEDEC, depending on the cards found.
+dep_tristate '  PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
 
 endmenu
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/Makefile linux-2.4.19-pre5/drivers/mtd/maps/Makefile
--- linux-2.4.19-pre4/drivers/mtd/maps/Makefile	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/maps/Makefile	Fri Mar 29 14:49:34 2002
@@ -1,7 +1,7 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $
+# $Id: Makefile,v 1.21 2002/02/22 09:34:44 gleixner Exp $
 
 O_TARGET	:= mapslink.o
 
@@ -11,9 +11,15 @@
 obj-$(CONFIG_MTD_CFI_FLAGADM)	+= cfi_flagadm.o
 obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
 obj-$(CONFIG_MTD_DC21285)       += dc21285.o
+obj-$(CONFIG_MTD_DILNETPC)      += dilnetpc.o
 obj-$(CONFIG_MTD_ELAN_104NC)    += elan-104nc.o
+obj-$(CONFIG_MTD_EPXA10DB)      += epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
 obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
+obj-$(CONFIG_MTD_AMD766ROM)	+= amd766rom.o
+obj-$(CONFIG_MTD_ICH2ROM)	+= ich2rom.o
+obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
+obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
 obj-$(CONFIG_MTD_NORA)		+= nora.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
@@ -29,7 +35,9 @@
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
+obj-$(CONFIG_MTD_PCI)		+= pci.o
 obj-$(CONFIG_MTD_PB1000)        += pb1xxx-flash.o
 obj-$(CONFIG_MTD_PB1500)        += pb1xxx-flash.o
+obj-$(CONFIG_MTD_AUTCPU12)      += autcpu12-nvram.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/amd766rom.c linux-2.4.19-pre5/drivers/mtd/maps/amd766rom.c
--- linux-2.4.19-pre4/drivers/mtd/maps/amd766rom.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/amd766rom.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,245 @@
+/*
+ * amd766rom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: amd766rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+
+struct amd766rom_map_info {
+	struct map_info map;
+	struct mtd_info *mtd;
+	unsigned long window_addr;
+	u32 window_start, window_size;
+	struct pci_dev *pdev;
+};
+
+static __u8 amd766rom_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 amd766rom_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 amd766rom_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void amd766rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void amd766rom_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd766rom_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd766rom_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd766rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct amd766rom_map_info amd766rom_map = {
+	map: {
+		name: "AMD766 rom",
+		size: 0,
+		buswidth: 1,
+		read8: amd766rom_read8,
+		read16: amd766rom_read16,
+		read32: amd766rom_read32,
+		copy_from: amd766rom_copy_from,
+		write8: amd766rom_write8,
+		write16: amd766rom_write16,
+		write32: amd766rom_write32,
+		copy_to: amd766rom_copy_to,
+		/* The standard rom socket is for single power supply chips
+		 * that don't have an extra vpp.
+		 */
+	},
+	mtd: 0,
+	window_addr: 0,
+};
+
+static int __devinit amd766rom_init_one (struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct rom_window {
+		u32 start;
+		u32 size;
+		u8 segen_bits;
+	};
+	static struct rom_window rom_window[] = {
+		{ 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
+		{ 0xffc00000, 4*1024*1024, (1<<7), },
+		{ 0xffff0000, 64*1024,     0 },
+		{ 0         , 0,           0 },
+	};
+	static const u32 rom_probe_sizes[] = { 
+		5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
+		256*1024, 128*1024, 64*1024, 0};
+	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
+	u8 byte;
+	struct amd766rom_map_info *info = &amd766rom_map;
+	struct rom_window *window;
+	int i;
+	u32 rom_size;
+
+	window = &rom_window[0];
+	while(window->size) {
+		if (request_mem_region(window->start, window->size, "amd766rom")) {
+			break;
+		}
+		window++;
+	}
+	if (!window->size) {
+		printk(KERN_ERR "amd766rom: cannot reserve rom window");
+		goto err_out_none;
+	}
+
+	/* Enable the selected rom window */
+	pci_read_config_byte(pdev, 0x43, &byte);
+	pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
+
+	/* Enable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte | 1);
+
+	/* FIXME handle registers 0x80 - 0x8C the bios region locks */
+
+	printk(KERN_NOTICE "amd766rom window : %x at %x\n", 
+		window->size, window->start);
+	/* For write accesses caches are useless */
+	info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
+
+	if (!info->window_addr) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		goto err_out_free_mmio_region;
+	}
+	info->mtd = 0;
+	for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
+		char **chip_type;
+		if (rom_size > window->size) {
+			continue;
+		}
+		info->map.map_priv_1 = 
+			info->window_addr + window->size - rom_size;
+		info->map.size = rom_size;
+		chip_type = rom_probe_types;
+		for(; !info->mtd && *chip_type; chip_type++) {
+			info->mtd = do_map_probe(*chip_type, &amd766rom_map.map);
+		}
+		if (info->mtd) {
+			break;
+		}
+	}
+	if (!info->mtd) {
+		goto err_out_iounmap;
+	}
+	printk(KERN_NOTICE "amd766rom chip at offset: %x\n",
+		window->size - rom_size);
+		
+	info->mtd->module = THIS_MODULE;
+	add_mtd_device(info->mtd);
+	info->window_start = window->start;
+	info->window_size = window->size;
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *)(info->window_addr));
+err_out_free_mmio_region:
+	release_mem_region(window->start, window->size);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static void __devexit amd766rom_remove_one (struct pci_dev *pdev)
+{
+	struct amd766rom_map_info *info = &amd766rom_map;
+	u8 byte;
+
+	del_mtd_device(info->mtd);
+	map_destroy(info->mtd);
+	info->mtd = 0;
+	info->map.map_priv_1 = 0;
+
+	iounmap((void *)(info->window_addr));
+	info->window_addr = 0;
+
+	/* Disable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte & ~1);
+	
+	release_mem_region(info->window_start, info->window_size);
+}
+
+static struct pci_device_id amd766rom_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+};
+
+MODULE_DEVICE_TABLE(pci, amd766rom_pci_tbl);
+
+#if 0
+static struct pci_driver amd766rom_driver = {
+	name:	  "amd766rom",
+	id_table: amd766rom_pci_tbl,
+	probe:    amd766rom_init_one,
+	remove:   amd766rom_remove_one,
+};
+#endif
+
+int __init init_amd766rom(void)
+{
+	struct pci_dev *pdev;
+	pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
+	if (pdev) {
+		amd766rom_map.pdev = pdev;
+		return amd766rom_init_one(pdev, &amd766rom_pci_tbl[0]);
+	}
+	return -ENXIO;
+#if 0
+	return pci_module_init(&amd766rom_driver);
+#endif
+}
+
+static void __exit cleanup_amd766rom(void)
+{
+	amd766rom_remove_one(amd766rom_map.pdev);
+}
+
+module_init(init_amd766rom);
+module_exit(cleanup_amd766rom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD766 southbridge");
+
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/autcpu12-nvram.c linux-2.4.19-pre5/drivers/mtd/maps/autcpu12-nvram.c
--- linux-2.4.19-pre4/drivers/mtd/maps/autcpu12-nvram.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/autcpu12-nvram.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,179 @@
+/*
+ * NV-RAM memory access on autcpu12 
+ * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/hardware.h>
+#include <asm/arch/autcpu12.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	while(len) {
+		__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
+		from++;
+		to++;
+		len--;
+	}
+}
+
+static struct mtd_info *sram_mtd;
+
+struct map_info autcpu12_sram_map = {
+	name: "SRAM",
+	size: 32768,
+	buswidth: 8,
+	read8: autcpu12_read8,
+	read16: autcpu12_read16,
+	read32: autcpu12_read32,
+	copy_from: autcpu12_copy_from,
+	write8: autcpu12_write8,
+	write16: autcpu12_write16,
+	write32: autcpu12_write32,
+	copy_to: autcpu12_copy_to
+};
+
+static int __init init_autcpu12_sram (void)
+{
+	int err, save0, save1;
+
+	autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
+	if (!autcpu12_sram_map.map_priv_1) {
+		printk("Failed to ioremap autcpu12 NV-RAM space\n");
+		err = -EIO;
+		goto out;
+	}
+	
+	/* 
+	 * Check for 32K/128K 
+	 * read ofs 0 
+	 * read ofs 0x10000 
+	 * Write complement to ofs 0x100000
+	 * Read	and check result on ofs 0x0
+	 * Restore contents
+	 */
+	save0 = autcpu12_read32(&autcpu12_sram_map,0);
+	save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
+	autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
+	/* if we find this pattern on 0x0, we have 32K size 
+	 * restore contents and exit
+	 */
+	if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
+		autcpu12_write32(&autcpu12_sram_map,save0,0x0);
+		goto map;
+	}
+	/* We have a 128K found, restore 0x10000 and set size
+	 * to 128K
+	 */
+	autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
+	autcpu12_sram_map.size = SZ_128K;
+
+map:
+	sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map);
+	if (!sram_mtd) {
+		printk("NV-RAM probe failed\n");
+		err = -ENXIO;
+		goto out_ioremap;
+	}
+
+	sram_mtd->module = THIS_MODULE;
+	sram_mtd->erasesize = 16;
+	
+	if (add_mtd_device(sram_mtd)) {
+		printk("NV-RAM device addition failed\n");
+		err = -ENOMEM;
+		goto out_probe;
+	}
+
+	printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
+		
+	return 0;
+
+out_probe:
+	map_destroy(sram_mtd);
+	sram_mtd = 0;
+
+out_ioremap:
+	iounmap((void *)autcpu12_sram_map.map_priv_1);
+out:
+	return err;
+}
+
+static void __exit cleanup_autcpu12_maps(void)
+{
+	if (sram_mtd) {
+		del_mtd_device(sram_mtd);
+		map_destroy(sram_mtd);
+		iounmap((void *)autcpu12_sram_map.map_priv_1);
+	}
+}
+
+module_init(init_autcpu12_sram);
+module_exit(cleanup_autcpu12_maps);
+
+MODULE_AUTHOR("Thomas Gleixner");
+MODULE_DESCRIPTION("autcpu12 NV-RAM map driver");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/dc21285.c linux-2.4.19-pre5/drivers/mtd/maps/dc21285.c
--- linux-2.4.19-pre4/drivers/mtd/maps/dc21285.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/dc21285.c	Fri Mar 29 14:49:34 2002
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  * 
- * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: dc21285.c,v 1.7 2001/10/11 16:17:51 nico Exp $
  */
 
 #include <linux/module.h>
@@ -44,15 +44,15 @@
 
 void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-	*CSR_ROMWRITEREG = adr;
+	*CSR_ROMWRITEREG = adr & 3;
 	adr &= ~3;
 	*(__u8*)(map->map_priv_1 + adr) = d;
 }
 
 void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-	*CSR_ROMWRITEREG = adr;
-	adr &= ~1;
+	*CSR_ROMWRITEREG = adr & 3;
+	adr &= ~3;
 	*(__u16*)(map->map_priv_1 + adr) = d;
 }
 
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/dilnetpc.c linux-2.4.19-pre5/drivers/mtd/maps/dilnetpc.c
--- linux-2.4.19-pre4/drivers/mtd/maps/dilnetpc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/dilnetpc.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,540 @@
+/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP"
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser Exp $
+ *
+ * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
+ * featuring the AMD Elan SC410 processor. There are two variants of this
+ * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash
+ * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs
+ * flash and 16 megs of RAM.
+ * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm
+ * and http://www.ssv-embedded.de/ssv/pc104/p170.htm
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+/*
+** The DIL/NetPC keeps it's BIOS in two distinct flash blocks.
+** Destroying any of these blocks transforms the DNPC into
+** a paperweight (albeit not a very useful one, considering
+** it only weighs a few grams).
+**
+** Therefore, the BIOS blocks must never be erased or written to
+** except by people who know exactly what they are doing (e.g.
+** to install a BIOS update). These partitions are marked read-only
+** by default, but can be made read/write by undefining
+** DNPC_BIOS_BLOCKS_WRITEPROTECTED:
+*/
+#define DNPC_BIOS_BLOCKS_WRITEPROTECTED
+
+/*
+** The ID string (in ROM) is checked to determine whether we
+** are running on a DNP/1486 or ADNP/1486
+*/
+#define BIOSID_BASE	0x000fe100
+
+#define ID_DNPC	"DNP1486"
+#define ID_ADNP	"ADNP1486"
+
+/*
+** Address where the flash should appear in CPU space
+*/
+#define FLASH_BASE	0x2000000
+
+/*
+** Chip Setup and Control (CSC) indexed register space
+*/
+#define CSC_INDEX	0x22
+#define CSC_DATA	0x23
+
+#define CSC_MMSWAR	0x30	/* MMS window C-F attributes register */
+#define CSC_MMSWDSR	0x31	/* MMS window C-F device select register */
+
+#define CSC_RBWR	0xa7	/* GPIO Read-Back/Write Register B */
+
+#define CSC_CR		0xd0	/* internal I/O device disable/Echo */
+				/* Z-bus/configuration register */
+
+#define CSC_PCCMDCR	0xf1	/* PC card mode and DMA control register */
+
+
+/*
+** PC Card indexed register space:
+*/
+
+#define PCC_INDEX	0x3e0
+#define PCC_DATA	0x3e1
+
+#define PCC_AWER_B		0x46	/* Socket B Address Window enable register */
+#define PCC_MWSAR_1_Lo	0x58	/* memory window 1 start address low register */
+#define PCC_MWSAR_1_Hi	0x59	/* memory window 1 start address high register */
+#define PCC_MWEAR_1_Lo	0x5A	/* memory window 1 stop address low register */
+#define PCC_MWEAR_1_Hi	0x5B	/* memory window 1 stop address high register */
+#define PCC_MWAOR_1_Lo	0x5C	/* memory window 1 address offset low register */
+#define PCC_MWAOR_1_Hi	0x5D	/* memory window 1 address offset high register */
+
+
+/*
+** Access to SC4x0's Chip Setup and Control (CSC)
+** and PC Card (PCC) indexed registers:
+*/
+static inline void setcsc(int reg, unsigned char data)
+{
+	outb(reg, CSC_INDEX);
+	outb(data, CSC_DATA);
+}
+
+static inline unsigned char getcsc(int reg)
+{
+	outb(reg, CSC_INDEX);
+	return(inb(CSC_DATA));
+}
+
+static inline void setpcc(int reg, unsigned char data)
+{
+	outb(reg, PCC_INDEX);
+	outb(data, PCC_DATA);
+}
+
+static inline unsigned char getpcc(int reg)
+{
+	outb(reg, PCC_INDEX);
+	return(inb(PCC_DATA));
+}
+
+
+/*
+************************************************************
+** Enable access to DIL/NetPC's flash by mapping it into
+** the SC4x0's MMS Window C.
+************************************************************
+*/
+static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size)
+{
+	unsigned long flash_end = flash_base + flash_size - 1;
+
+	/*
+	** enable setup of MMS windows C-F:
+	*/
+	/* - enable PC Card indexed register space */
+	setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
+	/* - set PC Card controller to operate in standard mode */
+	setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1);
+
+	/*
+	** Program base address and end address of window
+	** where the flash ROM should appear in CPU address space
+	*/
+	setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff);
+	setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f);
+	setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff);
+	setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f);
+
+	/* program offset of first flash location to appear in this window (0) */
+	setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff);
+	setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f);
+
+	/* set attributes for MMS window C: non-cacheable, write-enabled */
+	setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11);
+
+	/* select physical device ROMCS0 (i.e. flash) for MMS Window C */
+	setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03);
+
+	/* enable memory window 1 */
+	setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02);
+
+	/* now disable PC Card indexed register space again */
+	setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
+}
+
+
+/*
+************************************************************
+** Disable access to DIL/NetPC's flash by mapping it into
+** the SC4x0's MMS Window C.
+************************************************************
+*/
+static void dnpc_unmap_flash(void)
+{
+	/* - enable PC Card indexed register space */
+	setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
+
+	/* disable memory window 1 */
+	setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02);
+
+	/* now disable PC Card indexed register space again */
+	setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
+}
+
+
+static __u8 dnpc_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 dnpc_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 dnpc_read32(struct map_info *map, unsigned long ofs)
+{
+	return readl(map->map_priv_1 + ofs);
+}
+
+static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+}
+
+/*
+************************************************************
+** Enable/Disable VPP to write to flash
+************************************************************
+*/
+
+static spinlock_t dnpc_spin   = SPIN_LOCK_UNLOCKED;
+static int        vpp_counter = 0;
+/*
+** This is what has to be done for the DNP board ..
+*/
+static void dnp_set_vpp(struct map_info *not_used, int on)
+{
+	spin_lock_irq(&dnpc_spin);
+
+	if (on)
+	{
+		if(++vpp_counter == 1)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4);
+	}
+	else
+	{
+		if(--vpp_counter == 0)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4);
+		else if(vpp_counter < 0)
+			BUG();
+	}
+	spin_unlock_irq(&dnpc_spin);
+}
+
+/*
+** .. and this the ADNP version:
+*/
+static void adnp_set_vpp(struct map_info *not_used, int on)
+{
+	spin_lock_irq(&dnpc_spin);
+
+	if (on)
+	{
+		if(++vpp_counter == 1)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8);
+	}
+	else
+	{
+		if(--vpp_counter == 0)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8);
+		else if(vpp_counter < 0)
+			BUG();
+	}
+	spin_unlock_irq(&dnpc_spin);
+}
+
+
+
+#define DNP_WINDOW_SIZE		0x00200000	/*  DNP flash size is 2MiB  */
+#define ADNP_WINDOW_SIZE	0x00400000	/* ADNP flash size is 4MiB */
+#define WINDOW_ADDR			FLASH_BASE
+
+static struct map_info dnpc_map = {
+	name: "ADNP Flash Bank",
+	size: ADNP_WINDOW_SIZE,
+	buswidth: 1,
+	read8: dnpc_read8,
+	read16: dnpc_read16,
+	read32: dnpc_read32,
+	copy_from: dnpc_copy_from,
+	write8: dnpc_write8,
+	write16: dnpc_write16,
+	write32: dnpc_write32,
+	copy_to: dnpc_copy_to,
+	set_vpp: adnp_set_vpp,
+	map_priv_2: WINDOW_ADDR
+};
+
+/*
+** The layout of the flash is somewhat "strange":
+**
+** 1.  960 KiB (15 blocks) : Space for ROM Bootloader and user data
+** 2.   64 KiB (1 block)   : System BIOS
+** 3.  960 KiB (15 blocks) : User Data (DNP model) or
+** 3. 3008 KiB (47 blocks) : User Data (ADNP model)
+** 4.   64 KiB (1 block)   : System BIOS Entry
+*/
+
+static struct mtd_partition partition_info[]=
+{
+	{ 
+		name:		"ADNP boot", 
+		offset:		0, 
+		size:		0xf0000,
+	},
+	{ 
+		name:		"ADNP system BIOS", 
+		offset:		MTDPART_OFS_NXTBLK,
+		size:		0x10000,
+#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
+		mask_flags:	MTD_WRITEABLE,
+#endif
+	},
+	{
+		name:		"ADNP file system",
+		offset:		MTDPART_OFS_NXTBLK,
+		size:		0x2f0000,
+	},
+	{
+		name:		"ADNP system BIOS entry", 
+		offset:		MTDPART_OFS_NXTBLK,
+		size:		MTDPART_SIZ_FULL,
+#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
+		mask_flags:	MTD_WRITEABLE,
+#endif
+	},
+};
+
+#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+
+static struct mtd_info *mymtd;
+static struct mtd_info *lowlvl_parts[NUM_PARTITIONS];
+static struct mtd_info *merged_mtd;
+
+/*
+** "Highlevel" partition info:
+**
+** Using the MTD concat layer, we can re-arrange partitions to our
+** liking: we construct a virtual MTD device by concatenating the
+** partitions, specifying the sequence such that the boot block
+** is immediately followed by the filesystem block (i.e. the stupid
+** system BIOS block is mapped to a different place). When re-partitioning
+** this concatenated MTD device, we can set the boot block size to
+** an arbitrary (though erase block aligned) value i.e. not one that
+** is dictated by the flash's physical layout. We can thus set the
+** boot block to be e.g. 64 KB (which is fully sufficient if we want
+** to boot an etherboot image) or to -say- 1.5 MB if we want to boot
+** a large kernel image. In all cases, the remainder of the flash
+** is available as file system space.
+*/
+
+static struct mtd_partition higlvl_partition_info[]=
+{
+	{ 
+		name:		"ADNP boot block", 
+		offset:		0, 
+		size:		CONFIG_MTD_DILNETPC_BOOTSIZE,
+	},
+	{
+		name:		"ADNP file system space",
+		offset:		MTDPART_OFS_NXTBLK,
+		size:		ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
+	},
+	{ 
+		name:		"ADNP system BIOS + BIOS Entry", 
+		offset:		MTDPART_OFS_NXTBLK,
+		size:		MTDPART_SIZ_FULL,
+#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
+		mask_flags:	MTD_WRITEABLE,
+#endif
+	},
+};
+
+#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0]))
+
+
+static int dnp_adnp_probe(void)
+{
+	char *biosid, rc = -1;
+
+	biosid = (char*)ioremap(BIOSID_BASE, 16);
+	if(biosid)
+	{
+		if(!strcmp(biosid, ID_DNPC))
+			rc = 1;		/* this is a DNPC  */
+		else if(!strcmp(biosid, ID_ADNP))
+			rc = 0;		/* this is a ADNPC */
+	}
+	iounmap((void *)biosid);
+	return(rc);
+}
+
+
+static int __init init_dnpc(void)
+{
+	int is_dnp;
+
+	/*
+	** determine hardware (DNP/ADNP/invalid)
+	*/	
+	if((is_dnp = dnp_adnp_probe()) < 0)
+		return -ENXIO;
+
+	/*
+	** Things are set up for ADNP by default
+	** -> modify all that needs to be different for DNP
+	*/
+	if(is_dnp)
+	{	/*
+		** Adjust window size, select correct set_vpp function.
+		** The partitioning scheme is identical on both DNP
+		** and ADNP except for the size of the third partition.
+		*/
+		int i;
+		dnpc_map.size          = DNP_WINDOW_SIZE;
+		dnpc_map.set_vpp       = dnp_set_vpp;
+		partition_info[2].size = 0xf0000;
+
+		/*
+		** increment all string pointers so the leading 'A' gets skipped,
+		** thus turning all occurrences of "ADNP ..." into "DNP ..."
+		*/
+		++dnpc_map.name;
+		for(i = 0; i < NUM_PARTITIONS; i++)
+			++partition_info[i].name;
+		higlvl_partition_info[1].size = DNP_WINDOW_SIZE - 
+			CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000;
+		for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++)
+			++higlvl_partition_info[i].name;
+	}
+
+	printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", 
+		is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2);
+
+	dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size);
+
+	dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size);
+
+	if (!dnpc_map.map_priv_1) {
+		printk("Failed to ioremap_nocache\n");
+		return -EIO;
+	}
+
+	printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1);
+
+	mymtd = do_map_probe("jedec_probe", &dnpc_map);
+
+	if (!mymtd)
+		mymtd = do_map_probe("cfi_probe", &dnpc_map);
+
+	/*
+	** If flash probes fail, try to make flashes accessible
+	** at least as ROM. Ajust erasesize in this case since
+	** the default one (128M) will break our partitioning
+	*/
+	if (!mymtd)
+		if((mymtd = do_map_probe("map_rom", &dnpc_map)))
+			mymtd->erasesize = 0x10000;
+
+	if (!mymtd) {
+		iounmap((void *)dnpc_map.map_priv_1);
+		return -ENXIO;
+	}
+		
+	mymtd->module = THIS_MODULE;
+
+	/*
+	** Supply pointers to lowlvl_parts[] array to add_mtd_partitions()
+	** -> add_mtd_partitions() will _not_ register MTD devices for
+	** the partitions, but will instead store pointers to the MTD
+	** objects it creates into our lowlvl_parts[] array.
+	** NOTE: we arrange the pointers such that the sequence of the
+	**       partitions gets re-arranged: partition #2 follows
+	**       partition #0.
+	*/
+	partition_info[0].mtdp = &lowlvl_parts[0];
+	partition_info[1].mtdp = &lowlvl_parts[2];
+	partition_info[2].mtdp = &lowlvl_parts[1];
+	partition_info[3].mtdp = &lowlvl_parts[3];
+
+	add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+
+	/*
+	** now create a virtual MTD device by concatenating the for partitions
+	** (in the sequence given by the lowlvl_parts[] array.
+	*/
+	merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated");
+	if(merged_mtd)
+	{	/*
+		** now partition the new device the way we want it. This time,
+		** we do not supply mtd pointers in higlvl_partition_info, so
+		** add_mtd_partitions() will register the devices.
+		*/
+		add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS);
+	}
+
+	return 0;
+}
+
+static void __exit cleanup_dnpc(void)
+{
+	if(merged_mtd) {
+		del_mtd_partitions(merged_mtd);
+		mtd_concat_destroy(merged_mtd);
+	}
+
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (dnpc_map.map_priv_1) {
+		iounmap((void *)dnpc_map.map_priv_1);
+		dnpc_unmap_flash();
+		dnpc_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_dnpc);
+module_exit(cleanup_dnpc);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH");
+MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP");
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/elan-104nc.c linux-2.4.19-pre5/drivers/mtd/maps/elan-104nc.c
--- linux-2.4.19-pre4/drivers/mtd/maps/elan-104nc.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre5/drivers/mtd/maps/elan-104nc.c	Fri Mar 29 14:49:34 2002
@@ -16,7 +16,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: elan-104nc.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+   $Id: elan-104nc.c,v 1.13 2002/02/13 15:30:20 dwmw2 Exp $
 
 The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
 mode.  This drivers uses the CFI probe and Intel Extended Command Set drivers.
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/epxa10db-flash.c linux-2.4.19-pre5/drivers/mtd/maps/epxa10db-flash.c
--- linux-2.4.19-pre4/drivers/mtd/maps/epxa10db-flash.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/epxa10db-flash.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,219 @@
+/*
+ * Flash memory access on EPXA based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *  Copyright (C) 2001 Altera Corporation
+ *  Copyright (C) 2001 Red Hat, Inc.
+ *
+ * $Id: epxa10db-flash.c,v 1.2 2001/12/19 13:00:19 jskov Exp $ 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+
+static int nr_parts = 0;
+static struct mtd_partition *parts;
+
+static struct mtd_info *mymtd;
+
+extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
+static int epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+
+static __u8 epxa10db_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 epxa10db_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 epxa10db_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void epxa10db_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void epxa10db_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void epxa10db_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void epxa10db_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void epxa10db_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+}
+
+
+
+static struct map_info epxa10db_map = {
+	name:		"EPXA10DB flash",
+	size:		FLASH_SIZE,
+	buswidth:	2,
+	read8:		epxa10db_read8,
+	read16:		epxa10db_read16,
+	read32:		epxa10db_read32,
+	copy_from:	epxa10db_copy_from,
+	write8:		epxa10db_write8,
+	write16:	epxa10db_write16,
+	write32:	epxa10db_write32,
+	copy_to:	epxa10db_copy_to
+};
+
+
+static int __init epxa10db_mtd_init(void)
+{
+	int i;
+	printk(KERN_NOTICE "Epxa10db flash device: %x at %x\n", FLASH_SIZE, FLASH_START);
+	epxa10db_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+	if (!epxa10db_map.map_priv_1) {
+		printk("Failed to ioremap Epxa10db flash\n");
+		return -EIO;
+	}
+
+	mymtd = do_map_probe("cfi_probe", &epxa10db_map);
+	if (!mymtd) {
+		iounmap((void *)epxa10db_map.map_priv_1);
+		return -ENXIO;
+	}
+
+	mymtd->module = THIS_MODULE;
+
+	/* Unlock the flash device. */
+	for (i=0; i<mymtd->numeraseregions;i++){
+		int j;
+		for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+			mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,4);
+		}
+	}
+
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+	nr_parts = parse_redboot_partitions(mymtd, &parts);
+
+	if (nr_parts > 0) {
+		add_mtd_partitions(mymtd, parts, nr_parts);
+		return 0;
+	}
+#endif
+#ifdef CONFIG_MTD_AFS_PARTS
+	nr_parts = parse_afs_partitions(mymtd, &parts);
+
+	if (nr_parts > 0) {
+		add_mtd_partitions(mymtd, parts, nr_parts);
+		return 0;
+	}
+#endif
+
+	/* No recognised partitioning schemes found - use defaults */
+	nr_parts = epxa10db_default_partitions(mymtd, &parts);
+	if (nr_parts > 0) {
+		add_mtd_partitions(mymtd, parts, nr_parts);
+		return 0;
+	}
+
+	/* If all else fails... */
+	add_mtd_device(mymtd);
+	return 0;
+}
+
+static void __exit epxa10db_mtd_cleanup(void)
+{
+	if (mymtd) {
+		if (nr_parts)
+			del_mtd_partitions(mymtd);
+		else
+			del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (epxa10db_map.map_priv_1) {
+		iounmap((void *)epxa10db_map.map_priv_1);
+		epxa10db_map.map_priv_1 = 0;
+	}
+}
+
+
+/* 
+ * This will do for now, once we decide which bootldr we're finally 
+ * going to use then we'll remove this function and do it properly
+ *
+ * Partions are currently (as offsets from base of flash):
+ * 0x00000000 - 0x003FFFFF - bootloader (!)
+ * 0x00400000 - 0x00FFFFFF - Flashdisk
+ */
+
+static int __init epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+	struct mtd_partition *parts;
+	int ret, i;
+	int npartitions = 0;
+	char *names; 
+	const char *name = "jffs";
+
+	printk("Using default partitions for epxa10db\n");
+	npartitions=1;
+	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+	if (!parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	i=0;
+	names = (char *)&parts[npartitions];	
+	parts[i].name = names;
+	names += strlen(name) + 1;
+	strcpy(parts[i].name, name);
+
+	parts[i].size = FLASH_SIZE-0x00400000;
+	parts[i].offset = 0x00400000;
+	parts[i].mask_flags = 0;
+
+ out:
+	*pparts = parts;
+	return npartitions;
+}
+
+module_init(epxa10db_mtd_init);
+module_exit(epxa10db_mtd_cleanup);
+
+MODULE_AUTHOR("Clive Davies");
+MODULE_DESCRIPTION("Altera epxa10db mtd flash map");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/ich2rom.c linux-2.4.19-pre5/drivers/mtd/maps/ich2rom.c
--- linux-2.4.19-pre4/drivers/mtd/maps/ich2rom.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/ich2rom.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,302 @@
+/*
+ * ich2rom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#define RESERVE_MEM_REGION 0
+
+#define ICH2_FWH_REGION_START	0xFF000000UL
+#define ICH2_FWH_REGION_SIZE	0x01000000UL
+#define BIOS_CNTL	0x4e
+#define FWH_DEC_EN1	0xE3
+#define FWH_DEC_EN2	0xF0
+#define FWH_SEL1	0xE8
+#define FWH_SEL2	0xEE
+
+struct ich2rom_map_info {
+	struct map_info map;
+	struct mtd_info *mtd;
+	unsigned long window_addr;
+};
+
+static inline unsigned long addr(struct map_info *map, unsigned long ofs)
+{
+	unsigned long offset;
+	offset = ((8*1024*1024) - map->size) + ofs;
+	if (offset >= (4*1024*1024)) {
+		offset += 0x400000;
+	}
+	return map->map_priv_1 + 0x400000 + offset;
+}
+
+static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
+{
+	return addr - map->map_priv_1 + ICH2_FWH_REGION_START;
+}
+	
+static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(addr(map, ofs));
+}
+
+static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(addr(map, ofs));
+}
+
+static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(addr(map, ofs));
+}
+
+static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, addr(map, from), len);
+}
+
+static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs)
+{
+	__raw_writeb(d, addr(map,ofs));
+	mb();
+}
+
+static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs)
+{
+	__raw_writew(d, addr(map, ofs));
+	mb();
+}
+
+static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs)
+{
+	__raw_writel(d, addr(map, ofs));
+	mb();
+}
+
+static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(addr(map, to), from, len);
+}
+
+static struct ich2rom_map_info ich2rom_map = {
+	map: {
+		name: "ICH2 rom",
+		size: 0,
+		buswidth: 1,
+		read8: ich2rom_read8,
+		read16: ich2rom_read16,
+		read32: ich2rom_read32,
+		copy_from: ich2rom_copy_from,
+		write8: ich2rom_write8,
+		write16: ich2rom_write16,
+		write32: ich2rom_write32,
+		copy_to: ich2rom_copy_to,
+		/* Firmware hubs only use vpp when being programmed
+		 * in a factory setting.  So in place programming
+		 * needs to use a different method.
+		 */
+	},
+	mtd: 0,
+	window_addr: 0,
+};
+
+enum fwh_lock_state {
+	FWH_DENY_WRITE = 1,
+	FWH_IMMUTABLE  = 2,
+	FWH_DENY_READ  = 4,
+};
+
+static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
+	enum fwh_lock_state state)
+{
+	struct map_info *map = mtd->priv;
+	unsigned long start = ofs;
+	unsigned long end = start + len -1;
+
+	/* FIXME do I need to guard against concurrency here? */
+	/* round down to 64K boundaries */
+	start = start & ~0xFFFF;
+	end = end & ~0xFFFF;
+	while (start <= end) {
+		unsigned long ctrl_addr;
+		ctrl_addr = addr(map, start) - 0x400000 + 2;
+		writeb(state, ctrl_addr);
+		start = start + 0x10000;
+	}
+	return 0;
+}
+
+static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
+}
+
+static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	return ich2rom_set_lock_state(mtd, ofs, len, 0);
+}
+
+static int __devinit ich2rom_init_one (struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	u16 word;
+	struct ich2rom_map_info *info = &ich2rom_map;
+	unsigned long map_size;
+
+	/* For now I just handle the ich2 and I assume there
+	 * are not a lot of resources up at the top of the address
+	 * space.  It is possible to handle other devices in the
+	 * top 16MB but it is very painful.  Also since
+	 * you can only really attach a FWH to an ICH2 there
+	 * a number of simplifications you can make.
+	 *
+	 * Also you can page firmware hubs if an 8MB window isn't enough 
+	 * but don't currently handle that case either.
+	 */
+
+#if RESERVE_MEM_REGION
+	/* Some boards have this reserved and I haven't found a good work
+	 * around to say I know what I'm doing!
+	 */
+	if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) {
+		printk(KERN_ERR "ich2rom: cannot reserve rom window\n");
+		goto err_out_none;
+	}
+#endif /* RESERVE_MEM_REGION */
+	
+	/* Enable writes through the rom window */
+	pci_read_config_word(pdev, BIOS_CNTL, &word);
+	if (!(word & 1)  && (word & (1<<1))) {
+		/* The BIOS will generate an error if I enable
+		 * this device, so don't even try.
+		 */
+		printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n");
+		goto err_out_none;
+	}
+	pci_write_config_word(pdev, BIOS_CNTL, word | 1);
+
+
+	/* Map the firmware hub into my address space. */
+	/* Does this use to much virtual address space? */
+	info->window_addr = (unsigned long)ioremap(
+		ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
+	if (!info->window_addr) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		goto err_out_free_mmio_region;
+	}
+
+	/* For now assume the firmware has setup all relavent firmware
+	 * windows.  We don't have enough information to handle this case
+	 * intelligently.
+	 */
+
+	/* FIXME select the firmware hub and enable a window to it. */
+
+	info->mtd = 0;
+	info->map.map_priv_1 = 	info->window_addr;
+
+	map_size = ICH2_FWH_REGION_SIZE;
+	while(!info->mtd && (map_size > 0)) {
+		info->map.size = map_size;
+		info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map);
+		map_size -= 512*1024;
+	}
+	if (!info->mtd) {
+		goto err_out_iounmap;
+	}
+	/* I know I can only be a firmware hub here so put
+	 * in the special lock and unlock routines.
+	 */
+	info->mtd->lock = ich2rom_lock;
+	info->mtd->unlock = ich2rom_unlock;
+		
+	info->mtd->module = THIS_MODULE;
+	add_mtd_device(info->mtd);
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *)(info->window_addr));
+err_out_free_mmio_region:
+#if RESERVE_MEM_REGION
+	release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
+#endif
+err_out_none:
+	return -ENODEV;
+}
+
+
+static void __devexit ich2rom_remove_one (struct pci_dev *pdev)
+{
+	struct ich2rom_map_info *info = &ich2rom_map;
+	u16 word;
+
+	del_mtd_device(info->mtd);
+	map_destroy(info->mtd);
+	info->mtd = 0;
+	info->map.map_priv_1 = 0;
+
+	iounmap((void *)(info->window_addr));
+	info->window_addr = 0;
+
+	/* Disable writes through the rom window */
+	pci_read_config_word(pdev, BIOS_CNTL, &word);
+	pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
+
+#if RESERVE_MEM_REGION	
+	release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
+#endif
+}
+
+static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+};
+
+MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl);
+
+#if 0
+static struct pci_driver ich2rom_driver = {
+	name:	  "ich2rom",
+	id_table: ich2rom_pci_tbl,
+	probe:    ich2rom_init_one,
+	remove:   ich2rom_remove_one,
+};
+#endif
+
+static struct pci_dev *mydev;
+int __init init_ich2rom(void)
+{
+	struct pci_dev *pdev;
+	pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0);
+	if (pdev) {
+		mydev = pdev;
+		return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]);
+	}
+	return -ENXIO;
+#if 0
+	return pci_module_init(&ich2rom_driver);
+#endif
+}
+
+static void __exit cleanup_ich2rom(void)
+{
+	ich2rom_remove_one(mydev);
+}
+
+module_init(init_ich2rom);
+module_exit(cleanup_ich2rom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge");
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/integrator-flash.c linux-2.4.19-pre5/drivers/mtd/maps/integrator-flash.c
--- linux-2.4.19-pre4/drivers/mtd/maps/integrator-flash.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/integrator-flash.c	Fri Mar 29 14:49:34 2002
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: integrator-flash.c,v 1.6 2001/10/02 16:00:01 dwmw2 Exp $
+   $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $
 
 ======================================================================*/
 
@@ -208,10 +208,10 @@
 };
 
 static struct mtd_info *mtd;
+static struct mtd_partition *parts;
 
 static int __init armflash_cfi_init(void *base, u_int size)
 {
-	struct mtd_partition *parts;
 	int ret;
 
 	armflash_flash_init();
@@ -238,8 +238,6 @@
 	ret = parse_afs_partitions(mtd, &parts);
 	if (ret > 0) {
 		ret = add_mtd_partitions(mtd, parts, ret);
-		/* we don't need the partition info any longer */
-		kfree(parts);
 		if (ret)
 			printk(KERN_ERR "mtd partition registration "
 				"failed: %d\n", ret);
@@ -262,6 +260,8 @@
 		del_mtd_partitions(mtd);
 		map_destroy(mtd);
 	}
+	if (parts)
+		kfree(parts);
 }
 
 static int __init armflash_init(void)
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/iq80310.c linux-2.4.19-pre5/drivers/mtd/maps/iq80310.c
--- linux-2.4.19-pre4/drivers/mtd/maps/iq80310.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/iq80310.c	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
  *
  * Mapping for the Intel XScale IQ80310 evaluation board
  *
@@ -116,7 +116,7 @@
 	int parsed_nr_parts = 0;
 	char *part_type = "static";
 
-	iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
+	iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 	if (!iq80310_map.map_priv_1) {
 		printk("Failed to ioremap\n");
 		return -EIO;
@@ -161,7 +161,6 @@
 	}
 	if (iq80310_map.map_priv_1)
 		iounmap((void *)iq80310_map.map_priv_1);
-	return 0;
 }
 
 module_init(init_iq80310);
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/l440gx.c linux-2.4.19-pre5/drivers/mtd/maps/l440gx.c
--- linux-2.4.19-pre4/drivers/mtd/maps/l440gx.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/l440gx.c	Fri Mar 29 14:49:34 2002
@@ -1,7 +1,9 @@
 /*
- * $Id: l440gx.c,v 1.7 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $
  *
  * BIOS Flash chip on Intel 440GX board.
+ *
+ * Bugs this currently does not work under linuxBIOS.
  */
 
 #include <linux/module.h>
@@ -12,12 +14,14 @@
 #include <linux/mtd/map.h>
 #include <linux/config.h>
 
+#define PIIXE_IOBASE_RESOURCE	11
 
 #define WINDOW_ADDR 0xfff00000
 #define WINDOW_SIZE 0x00100000
 #define BUSWIDTH 1
 
-#define IOBASE 0xc00
+static u32 iobase;
+#define IOBASE iobase
 #define TRIBUF_PORT (IOBASE+0x37)
 #define VPP_PORT (IOBASE+0x28)
 
@@ -66,12 +70,17 @@
 	memcpy_toio(map->map_priv_1 + to, from, len);
 }
 
+/* Is this really the vpp port? */
 void l440gx_set_vpp(struct map_info *map, int vpp)
 {
 	unsigned long l;
 
 	l = inl(VPP_PORT);
-	l = vpp?(l | 1):(l & ~1);
+	if (vpp) {
+		l |= 1;
+	} else {
+		l &= ~1;
+	}
 	outl(l, VPP_PORT);
 }
 
@@ -87,44 +96,86 @@
 	write16: l440gx_write16,
 	write32: l440gx_write32,
 	copy_to: l440gx_copy_to,
+#if 0
+	/* FIXME verify that this is the 
+	 * appripriate code for vpp enable/disable
+	 */
 	set_vpp: l440gx_set_vpp
+#endif
 };
 
 static int __init init_l440gx(void)
 {
-	struct pci_dev *dev;
-	unsigned char b;
-	__u16 w;
+	struct pci_dev *dev, *pm_dev;
+	struct resource *pm_iobase;
+	__u16 word;
+
+	dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+		PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
 
-	dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
-			      NULL);
 
-	if (!dev) {
+	pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+		PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+
+	if (!dev || !pm_dev) {
 		printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n");
 		return -ENODEV;
 	}
 
 
-	l440gx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+	l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
 
 	if (!l440gx_map.map_priv_1) {
-		printk("Failed to ioremap L440GX flash region\n");
+		printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
 		return -ENOMEM;
 	}
 
+	printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1);
+
+	/* Setup the pm iobase resource 
+	 * This code should move into some kind of generic bridge
+	 * driver but for the moment I'm content with getting the
+	 * allocation correct. 
+	 */
+	pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE];
+	if (!(pm_iobase->flags & IORESOURCE_IO)) {
+		pm_iobase->name = "pm iobase";
+		pm_iobase->start = 0;
+		pm_iobase->end = 63;
+		pm_iobase->flags = IORESOURCE_IO;
+
+		/* Put the current value in the resource */
+		pci_read_config_dword(pm_dev, 0x40, &iobase);
+		iobase &= ~1;
+		pm_iobase->start += iobase & ~1;
+		pm_iobase->end += iobase & ~1;
+
+		/* Allocate the resource region */
+		if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
+			printk(KERN_WARNING "Could not allocate pm iobase resource\n");
+			iounmap((void *)l440gx_map.map_priv_1);
+			return -ENXIO;
+		}
+	}
+	/* Set the iobase */
+	iobase = pm_iobase->start;
+	pci_write_config_dword(pm_dev, 0x40, iobase | 1);
+	
+
 	/* Set XBCS# */
-	pci_read_config_word(dev, 0x4e, &w);
-	w |= 0x4;
-        pci_write_config_word(dev, 0x4e, w);
+	pci_read_config_word(dev, 0x4e, &word);
+	word |= 0x4;
+        pci_write_config_word(dev, 0x4e, word);
+
+	/* Supply write voltage to the chip */
+	l440gx_set_vpp(&l440gx_map, 1);
 
 	/* Enable the gate on the WE line */
-	b = inb(TRIBUF_PORT);
-	b |= 1;
-	outb(b, TRIBUF_PORT);
+	outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT);
 	
        	printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n");
 
-	mymtd = do_map_probe("jedec", &l440gx_map);
+	mymtd = do_map_probe("jedec_probe", &l440gx_map);
 	if (!mymtd) {
 		printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM\n");
 		mymtd = do_map_probe("map_rom", &l440gx_map);
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/mbx860.c linux-2.4.19-pre5/drivers/mtd/maps/mbx860.c
--- linux-2.4.19-pre4/drivers/mtd/maps/mbx860.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/mbx860.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,144 @@
+/*
+ * $Id: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $
+ *
+ * Handle mapping of the flash on MBX860 boards
+ *
+ * Author:	Anton Todorov
+ * Copyright:	(C) 2001 Emness Technology
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+
+#define WINDOW_ADDR 0xfe000000
+#define WINDOW_SIZE 0x00200000
+
+/* Flash / Partition sizing */
+#define MAX_SIZE_KiB              8192
+#define BOOT_PARTITION_SIZE_KiB    512
+#define KERNEL_PARTITION_SIZE_KiB 5632
+#define APP_PARTITION_SIZE_KiB    2048
+
+#define NUM_PARTITIONS 3
+
+/* partition_info gives details on the logical partitions that the split the
+ * single flash device into. If the size if zero we use up to the end of the
+ * device. */
+static struct mtd_partition partition_info[]={
+	{ name: "MBX flash BOOT partition",
+	offset: 0,
+	size:   BOOT_PARTITION_SIZE_KiB*1024 },
+	{ name: "MBX flash DATA partition",
+	offset: BOOT_PARTITION_SIZE_KiB*1024,
+	size: (KERNEL_PARTITION_SIZE_KiB)*1024 },
+	{ name: "MBX flash APPLICATION partition",
+	offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
+};
+				   
+
+static struct mtd_info *mymtd;
+
+__u8 mbx_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+__u16 mbx_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+__u32 mbx_read32(struct map_info *map, unsigned long ofs)
+{
+	return readl(map->map_priv_1 + ofs);
+}
+
+void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void mbx_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+void mbx_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+void mbx_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info mbx_map = {
+	name: "MBX flash",
+	size: WINDOW_SIZE,
+	buswidth: 4,
+	read8: mbx_read8,
+	read16: mbx_read16,
+	read32: mbx_read32,
+	copy_from: mbx_copy_from,
+	write8: mbx_write8,
+	write16: mbx_write16,
+	write32: mbx_write32,
+	copy_to: mbx_copy_to
+};
+
+int __init init_mbx(void)
+{
+	printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
+	mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
+
+	if (!mbx_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("jedec_probe", &mbx_map);
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+		add_mtd_device(mymtd);
+                add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+		return 0;
+	}
+
+	iounmap((void *)mbx_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_mbx(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (mbx_map.map_priv_1) {
+		iounmap((void *)mbx_map.map_priv_1);
+		mbx_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_mbx);
+module_exit(cleanup_mbx);
+
+MODULE_AUTHOR("Anton Todorov <a.todorov@emness.com>");
+MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/pb1xxx-flash.c linux-2.4.19-pre5/drivers/mtd/maps/pb1xxx-flash.c
--- linux-2.4.19-pre4/drivers/mtd/maps/pb1xxx-flash.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/maps/pb1xxx-flash.c	Fri Mar 29 14:49:34 2002
@@ -3,7 +3,7 @@
  * 
  * (C) 2001 Pete Popov <ppopov@mvista.com>
  * 
- * $Id: pb1xxx-flash.c,v 1.1 2002/02/27 17:23:28 marcelo Exp $
+ * $Id: pb1xxx-flash.c,v 1.2 2002/02/14 19:36:45 ppopov Exp $
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/pci.c linux-2.4.19-pre5/drivers/mtd/maps/pci.c
--- linux-2.4.19-pre4/drivers/mtd/maps/pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/pci.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,385 @@
+/*
+ *  linux/drivers/mtd/maps/pci.c
+ *
+ *  Copyright (C) 2001 Russell King, All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $
+ * 
+ * Generic PCI memory map driver.  We support the following boards:
+ *  - Intel IQ80310 ATU.
+ *  - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+struct map_pci_info;
+
+struct mtd_pci_info {
+	int  (*init)(struct pci_dev *dev, struct map_pci_info *map);
+	void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+	unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+	const char *map_name;
+};
+
+struct map_pci_info {
+	struct map_info map;
+	void *base;
+	void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+	unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+	struct pci_dev *dev;
+};	
+
+/*
+ * Intel IOP80310 Flash driver
+ */
+
+static int
+intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+	u32 win_base;
+
+	map->map.buswidth = 1;
+	map->map.size     = 0x00800000;
+	map->base         = ioremap_nocache(pci_resource_start(dev, 0),
+					    pci_resource_len(dev, 0));
+
+	if (!map->base)
+		return -ENOMEM;
+
+	/*
+	 * We want to base the memory window at Xscale
+	 * bus address 0, not 0x1000.
+	 */
+	pci_read_config_dword(dev, 0x44, &win_base);
+	pci_write_config_dword(dev, 0x44, 0);
+
+	map->map.map_priv_2 = win_base;
+
+	return 0;
+}
+
+static void
+intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+	if (map->base)
+		iounmap((void *)map->base);
+	pci_write_config_dword(dev, 0x44, map->map.map_priv_2);
+}
+
+static unsigned long
+intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs)
+{
+	unsigned long page_addr = ofs & 0x00400000;
+
+	/*
+	 * This mundges the flash location so we avoid
+	 * the first 80 bytes (they appear to read nonsense).
+	 */
+	if (page_addr) {
+		writel(0x00000008, map->base + 0x1558);
+		writel(0x00000000, map->base + 0x1550);
+	} else {
+		writel(0x00000007, map->base + 0x1558);
+		writel(0x00800000, map->base + 0x1550);
+		ofs += 0x00800000;
+	}
+
+	return ofs;
+}
+
+static struct mtd_pci_info intel_iq80310_info = {
+	init:		intel_iq80310_init,
+	exit:		intel_iq80310_exit,
+	translate:	intel_iq80310_translate,
+	map_name:	"cfi_probe",
+};
+
+/*
+ * Intel DC21285 driver
+ */
+
+static int
+intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+	unsigned long base, len;
+
+	base = pci_resource_start(dev, PCI_ROM_RESOURCE);
+	len  = pci_resource_len(dev, PCI_ROM_RESOURCE);
+
+	if (!len || !base) {
+		/*
+		 * No ROM resource
+		 */
+		base = pci_resource_start(dev, 2);
+		len  = pci_resource_len(dev, 2);
+
+		/*
+		 * We need to re-allocate PCI BAR2 address range to the
+		 * PCI ROM BAR, and disable PCI BAR2.
+		 */
+	} else {
+		/*
+		 * Hmm, if an address was allocated to the ROM resource, but
+		 * not enabled, should we be allocating a new resource for it
+		 * or simply enabling it?
+		 */
+		if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) &
+		     PCI_ROM_ADDRESS_ENABLE)) {
+		     	u32 val;
+			pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE;
+			pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+			val |= PCI_ROM_ADDRESS_ENABLE;
+			pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+			printk("%s: enabling expansion ROM\n", dev->slot_name);
+		}
+	}
+
+	if (!len || !base)
+		return -ENXIO;
+
+	map->map.buswidth = 4;
+	map->map.size     = len;
+	map->base         = ioremap_nocache(base, len);
+
+	if (!map->base)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void
+intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+	u32 val;
+
+	if (map->base)
+		iounmap((void *)map->base);
+
+	/*
+	 * We need to undo the PCI BAR2/PCI ROM BAR address alteration.
+	 */
+	pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+	val &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+}
+
+static unsigned long
+intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs)
+{
+	return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5));
+}
+
+static struct mtd_pci_info intel_dc21285_info = {
+	init:		intel_dc21285_init,
+	exit:		intel_dc21285_exit,
+	translate:	intel_dc21285_translate,
+	map_name:	"jedec_probe",
+};
+
+/*
+ * PCI device ID table
+ */
+
+static struct pci_device_id mtd_pci_ids[] __devinitdata = {
+	{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		0x530d,
+		subvendor:	PCI_ANY_ID,
+		subdevice:	PCI_ANY_ID,
+		class:		PCI_CLASS_MEMORY_OTHER << 8,
+		class_mask:	0xffff00,
+		driver_data:	(unsigned long)&intel_iq80310_info,
+	},
+	{
+		vendor:		PCI_VENDOR_ID_DEC,
+		device:		PCI_DEVICE_ID_DEC_21285,
+		subvendor:	0,	/* DC21285 defaults to 0 on reset */
+		subdevice:	0,	/* DC21285 defaults to 0 on reset */
+		class:		0,
+		class_mask:	0,
+		driver_data:	(unsigned long)&intel_dc21285_info,
+	},
+	{ 0, }
+};
+
+/*
+ * Generic code follows.
+ */
+
+static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	u8 val = readb(map->base + map->translate(map, ofs));
+//	printk("read8 : %08lx => %02x\n", ofs, val);
+	return val;
+}
+
+static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	u16 val = readw(map->base + map->translate(map, ofs));
+//	printk("read16: %08lx => %04x\n", ofs, val);
+	return val;
+}
+
+static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	u32 val = readl(map->base + map->translate(map, ofs));
+//	printk("read32: %08lx => %08x\n", ofs, val);
+	return val;
+}
+
+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	memcpy_fromio(to, map->base + map->translate(map, from), len);
+}
+
+static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+//	printk("write8 : %08lx <= %02x\n", ofs, val);
+	writeb(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+//	printk("write16: %08lx <= %04x\n", ofs, val);
+	writew(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+//	printk("write32: %08lx <= %08x\n", ofs, val);
+	writel(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	memcpy_toio(map->base + map->translate(map, to), from, len);
+}
+
+static struct map_info mtd_pci_map = {
+	read8:		mtd_pci_read8,
+	read16:		mtd_pci_read16,
+	read32:		mtd_pci_read32,
+	copy_from:	mtd_pci_copyfrom,
+	write8:		mtd_pci_write8,
+	write16:	mtd_pci_write16,
+	write32:	mtd_pci_write32,
+	copy_to:	mtd_pci_copyto,
+};
+
+static int __devinit
+mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
+	struct map_pci_info *map = NULL;
+	struct mtd_info *mtd = NULL;
+	int err;
+
+	err = pci_enable_device(dev);
+	if (err)
+		goto out;
+
+	err = pci_request_regions(dev, "pci mtd");
+	if (err)
+		goto out;
+
+	map = kmalloc(sizeof(*map), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!map)
+		goto release;
+
+	map->map       = mtd_pci_map;
+	map->map.name  = dev->slot_name;
+	map->dev       = dev;
+	map->exit      = info->exit;
+	map->translate = info->translate;
+
+	err = info->init(dev, map);
+	if (err)
+		goto release;
+
+	/* tsk - do_map_probe should take const char * */
+	mtd = do_map_probe((char *)info->map_name, &map->map);
+	err = -ENODEV;
+	if (!mtd)
+		goto release;
+
+	mtd->module = THIS_MODULE;
+	add_mtd_device(mtd);
+
+	pci_set_drvdata(dev, mtd);
+
+	return 0;
+
+release:
+	if (mtd)
+		map_destroy(mtd);
+
+	if (map) {
+		map->exit(dev, map);
+		kfree(map);
+	}
+
+	pci_release_regions(dev);
+out:
+	return err;
+}
+
+static void __devexit
+mtd_pci_remove(struct pci_dev *dev)
+{
+	struct mtd_info *mtd = pci_get_drvdata(dev);
+	struct map_pci_info *map = mtd->priv;
+
+	del_mtd_device(mtd);
+	map_destroy(mtd);
+	map->exit(dev, map);
+	kfree(map);
+
+	pci_set_drvdata(dev, NULL);
+	pci_release_regions(dev);
+}
+
+static struct pci_driver mtd_pci_driver = {
+	name:		"MTD PCI",
+	probe:		mtd_pci_probe,
+	remove:		mtd_pci_remove,
+	id_table:	mtd_pci_ids,
+};
+
+static int __init mtd_pci_maps_init(void)
+{
+	return pci_module_init(&mtd_pci_driver);
+}
+
+static void __exit mtd_pci_maps_exit(void)
+{
+	pci_unregister_driver(&mtd_pci_driver);
+}
+
+module_init(mtd_pci_maps_init);
+module_exit(mtd_pci_maps_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Generic PCI map driver");
+MODULE_DEVICE_TABLE(pci, mtd_pci_ids);
+
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/sa1100-flash.c linux-2.4.19-pre5/drivers/mtd/maps/sa1100-flash.c
--- linux-2.4.19-pre4/drivers/mtd/maps/sa1100-flash.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/sa1100-flash.c	Fri Mar 29 14:49:34 2002
@@ -3,12 +3,13 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $
+ * $Id: sa1100-flash.c,v 1.26 2002/03/13 16:30:44 rmk Exp $
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/ioport.h>
 #include <linux/kernel.h>
 
 #include <linux/mtd/mtd.h>
@@ -66,32 +67,6 @@
 	memcpy((void *)(map->map_priv_1 + to), from, len);
 }
 
-
-#ifdef CONFIG_SA1100_H3600
-
-static void h3600_set_vpp(struct map_info *map, int vpp)
-{
-	if (vpp)
-		set_h3600_egpio(EGPIO_H3600_VPP_ON);
-	else
-		clr_h3600_egpio(EGPIO_H3600_VPP_ON);
-}
-
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA720
-
-static void jornada720_set_vpp(int vpp)
-{
-  if (vpp)
-      PPSR |= 0x80;
-  else
-      PPSR &= ~0x80;
-  PPDR |= 0x80;
-}
-
-#endif
-
 static struct map_info sa1100_map = {
 	name:		"SA1100 flash",
 	read8:		sa1100_read8,
@@ -104,6 +79,7 @@
 	copy_to:	sa1100_copy_to,
 
 	map_priv_1:	WINDOW_ADDR,
+	map_priv_2:	-1,
 };
 
 
@@ -111,425 +87,687 @@
  * Here are partition information for all known SA1100-based devices.
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
  * structure.
- * 
+ *
  * The *_max_flash_size is the maximum possible mapped flash size which
- * is not necessarily the actual flash size.  It must correspond to the 
- * value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
+ * is not necessarily the actual flash size.  It must be no more than
+ * the value specified in the "struct map_desc *_io_desc" mapping
+ * definition for the corresponding machine.
+ *
+ * Please keep these in alphabetical order, and formatted as per existing
+ * entries.  Thanks.
  */
 
-#ifdef CONFIG_SA1100_ASSABET
+#ifdef CONFIG_SA1100_ADSBITSY
+#define ADSBITSY_FLASH_SIZE		0x02000000
+static struct mtd_partition adsbitsy_partitions[] = {
+	{
+		name:		"bootROM",
+		size:		0x80000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"zImage",
+		size:		0x100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
 
+#ifdef CONFIG_SA1100_ASSABET
 /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
-static unsigned long assabet4_max_flash_size = 0x00400000;
+#define ASSABET4_FLASH_SIZE		0x00400000
 static struct mtd_partition assabet4_partitions[] = {
-        {
-                name: "bootloader",
-                size: 0x00020000,
-                offset: 0,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "bootloader params",
-                size: 0x00020000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "jffs",
-                size: MTDPART_SIZ_FULL,
-                offset: MTDPART_OFS_APPEND
-        }
+	{
+		name:		"bootloader",
+		size:		0x00020000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"bootloader params",
+		size:		0x00020000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"jffs",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
 };
 
 /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
-static unsigned long assabet5_max_flash_size = 0x02000000;
+#define ASSABET5_FLASH_SIZE		0x02000000
 static struct mtd_partition assabet5_partitions[] = {
-        {
-                name: "bootloader",
-                size: 0x00040000,
-                offset: 0,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "bootloader params",
-                size: 0x00040000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "jffs",
-                size: MTDPART_SIZ_FULL,
-                offset: MTDPART_OFS_APPEND
-        }
+	{
+		name:		"bootloader",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"bootloader params",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"jffs",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
 };
 
-#define assabet_max_flash_size assabet5_max_flash_size
-#define assabet_partitions     assabet5_partitions
-
+#define ASSABET_FLASH_SIZE	ASSABET5_FLASH_SIZE
+#define assabet_partitions	assabet5_partitions
 #endif
 
-#ifdef CONFIG_SA1100_FLEXANET
+#ifdef CONFIG_SA1100_BADGE4
 
-/* Flexanet has two 28F128J3A flash parts in bank 0: */
-static unsigned long flexanet_max_flash_size = 0x02000000;
-static struct mtd_partition flexanet_partitions[] = {
-        {
-                name: "bootloader",
-                size: 0x00040000,
-                offset: 0,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "bootloader params",
-                size: 0x00040000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "kernel",
-                size: 0x000C0000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "altkernel",
-                size: 0x000C0000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "root",
-                size: 0x00400000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "free1",
-                size: 0x00300000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "free2",
-                size: 0x00300000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "free3",
-                size: MTDPART_SIZ_FULL,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        }
+/*
+ * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit)
+ *   Eight 4 KiW Parameter Bottom Blocks (64 KiB)
+ *   Sixty-three 32 KiW Main Blocks (4032 Ki b)
+ */
+#define BADGE4_FLASH_SIZE		0x00400000
+static struct mtd_partition badge4_partitions[] = {
+	{
+		name:		"BLOB boot loader",
+		offset:		0,
+		size:		0x0000A000
+	}, {
+		name:		"params",
+		offset:		MTDPART_OFS_APPEND,
+		size:		0x00006000
+	}, {
+		name:		"kernel",
+		offset:		MTDPART_OFS_APPEND,
+		size:		0x00100000
+	}, {
+		name:		"root",
+		offset:		MTDPART_OFS_APPEND,
+		size:		MTDPART_SIZ_FULL
+	}
 };
 
 #endif
 
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-static unsigned long huw_webpanel_max_flash_size = 0x01000000;
-static struct mtd_partition huw_webpanel_partitions[] = {
-	{ 
-	  name: "Loader",
-	  size: 0x00040000,
-	  offset: 0,
-	},{
-	  name: "Sector 1",
-	  size: 0x00040000,
-	  offset: MTDPART_OFS_APPEND,
-	},{
-	  size: MTDPART_SIZ_FULL,
-	  offset: MTDPART_OFS_APPEND,
+
+#ifdef CONFIG_SA1100_CERF
+#ifdef CONFIG_SA1100_CERF_FLASH_32MB
+#define CERF_FLASH_SIZE			0x02000000
+static struct mtd_partition cerf_partitions[] = {
+	{
+		name:		"firmware",
+		size:		0x00040000,
+		offset:		0,
+	}, {
+		name:		"params",
+		size:		0x00040000,
+		offset:		0x00040000,
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
+		name:		"rootdisk",
+		size:		0x01E80000,
+		offset:		0x00180000,
 	}
 };
-#endif /* CONFIG_SA1100_HUW_WEBPANEL */
-
-
-#ifdef CONFIG_SA1100_H3600
-
-static unsigned long h3600_max_flash_size = 0x02000000;
-static struct mtd_partition h3600_partitions[] = {
+#elif defined CONFIG_SA1100_CERF_FLASH_16MB
+#define CERF_FLASH_SIZE			0x01000000
+static struct mtd_partition cerf_partitions[] = {
 	{
-		name: "H3600 boot firmware",
-		size: 0x00040000,
-		offset: 0,
-		mask_flags: MTD_WRITEABLE  /* force read-only */
-	},{
-		name: "H3600 kernel",
-		size: 0x00080000,
-		offset: 0x40000
-	},{
-		name: "H3600 params",
-		size: 0x00040000,
-		offset: 0xC0000
-	},{
-#ifdef CONFIG_JFFS2_FS
-		name: "H3600 root jffs2",
-		offset: 0x00100000,
-		size: MTDPART_SIZ_FULL
+		name:		"firmware",
+		size:		0x00020000,
+		offset:		0,
+	}, {
+		name:		"params",
+		size:		0x00020000,
+		offset:		0x00020000,
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		0x00040000,
+	}, {
+		name:		"rootdisk",
+		size:		0x00EC0000,
+		offset:		0x00140000,
+	}
+};
+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
+#   error "Unwritten type definition"
 #else
-		name: "H3600 initrd",
-		size: 0x00100000,
-		offset: 0x00100000
-	},{
-		name: "H3600 root cramfs",
-		size: 0x00300000,
-		offset: 0x00200000
-	},{
-		name: "H3600 usr cramfs",
-		size: 0x00800000,
-		offset: 0x00500000
-	},{
-		name: "H3600 usr local",
-		offset: 0x00d00000,
-		size: MTDPART_SIZ_FULL
+#   error "Undefined memory orientation for CERF in sa1100-flash.c"
 #endif
+#endif
+
+#ifdef CONFIG_SA1100_CONSUS
+#define CONSUS_FLASH_SIZE		0x02000000
+static struct mtd_partition consus_partitions[] = {
+	{
+		name:		"Consus boot firmware",
+		offset:		0,
+		size:		0x00040000,
+		mask_flags:	MTD_WRITABLE, /* force read-only */
+	}, {
+		name:		"Consus kernel",
+		offset:		0x00040000,
+		size:		0x00100000,
+		mask_flags:	0,
+	}, {
+		name:		"Consus disk",
+		offset:		0x00140000,
+		/* The rest (up to 16M) for jffs.  We could put 0 and
+		   make it find the size automatically, but right now
+		   i have 32 megs.  jffs will use all 32 megs if given
+		   the chance, and this leads to horrible problems
+		   when you try to re-flash the image because blob
+		   won't erase the whole partition. */
+		size:		0x01000000 - 0x00140000,
+		mask_flags:	0,
+	}, {
+		/* this disk is a secondary disk, which can be used as
+		   needed, for simplicity, make it the size of the other
+		   consus partition, although realistically it could be
+		   the remainder of the disk (depending on the file
+		   system used) */
+		 name:		"Consus disk2",
+		 offset:	0x01000000,
+		 size:		0x01000000 - 0x00140000,
+		 mask_flags:	0,
 	}
 };
+#endif
 
+#ifdef CONFIG_SA1100_FLEXANET
+/* Flexanet has two 28F128J3A flash parts in bank 0: */
+#define FLEXANET_FLASH_SIZE		0x02000000
+static struct mtd_partition flexanet_partitions[] = {
+	{
+		name:		"bootloader",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"bootloader params",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"kernel",
+		size:		0x000C0000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"altkernel",
+		size:		0x000C0000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"root",
+		size:		0x00400000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"free1",
+		size:		0x00300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"free2",
+		size:		0x00300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"free3",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}
+};
 #endif
+
 #ifdef CONFIG_SA1100_FREEBIRD
-static unsigned long freebird_max_flash_size = 0x02000000;
+#define FREEBIRD_FLASH_SIZE		0x02000000
 static struct mtd_partition freebird_partitions[] = {
 #if CONFIG_SA1100_FREEBIRD_NEW
-    {
-     name: "firmware",
-     size: 0x00040000,
-     offset: 0,
-     mask_flags: MTD_WRITEABLE  /* force read-only */
-    },{
-     name: "kernel",
-     size: 0x00080000,
-     offset: 0x40000
-    },{
-     name: "params",
-     size: 0x00040000,
-     offset: 0xC0000
-    },{
-     name: "initrd",
-     size: 0x00100000,
-     offset: 0x00100000
-    },{
-     name: "root cramfs",
-     size: 0x00300000,
-     offset: 0x00200000
-    },{
-     name: "usr cramfs",
-     size: 0x00C00000,
-     offset: 0x00500000
-    },{
-	 name: "local",
-	 offset: 0x01100000,
-	 size: MTDPART_SIZ_FULL 
+	{
+		name:		"firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"kernel",
+		size:		0x00080000,
+		offset:		0x00040000,
+	}, {
+		name:		"params",
+		size:		0x00040000,
+		offset:		0x000C0000,
+	}, {
+		name:		"initrd",
+		size:		0x00100000,
+		offset:		0x00100000,
+	}, {
+		name:		"root cramfs",
+		size:		0x00300000,
+		offset:		0x00200000,
+	}, {
+		name:		"usr cramfs",
+		size:		0x00C00000,
+		offset:		0x00500000,
+	}, {
+		name:		"local",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x01100000,
 	}
 #else
-	{ offset: 0,            		size: 0x00040000,   },
-	{ offset: MTDPART_OFS_APPEND,   size: 0x000c0000,   },
-	{ offset: MTDPART_OFS_APPEND,	size: 0x00400000,	},
-	{ offset: MTDPART_OFS_APPEND,   size: MTDPART_SIZ_FULL  }
+	{
+		size:		0x00040000,
+		offset:		0,
+	}, {
+		size:		0x000c0000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		0x00400000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
 #endif
-	};
+};
 #endif
-																									
 
-#ifdef CONFIG_SA1100_CERF
-
-static unsigned long cerf_max_flash_size = 0x01000000;
-static struct mtd_partition cerf_partitions[] = {
-	{ offset: 0,			size: 0x00800000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0x00800000 	}
+#ifdef CONFIG_SA1100_FRODO
+/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
+#define FRODO_FLASH_SIZE		0x02000000
+static struct mtd_partition frodo_partitions[] =
+{
+	{
+		name:		"bootloader",
+		size:		0x00040000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"bootloader params",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"ramdisk",
+		size:		0x00400000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"file system",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND
+	}
 };
-
 #endif
 
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
-
-static unsigned long graphicsclient_max_flash_size = 0x01000000;
+#define GRAPHICSCLIENT_FLASH_SIZE	0x02000000
 static struct mtd_partition graphicsclient_partitions[] = {
-	{ 
-	 name: "zImage",
-	 offset: 0,
-	 size: 0x100000
-	},
-	{ 
-         name: "ramdisk.gz",
-         offset: MTDPART_OFS_APPEND,
-         size: 0x300000 		
-	},
-	{ 
-	  name: "User FS",
-          offset: MTDPART_OFS_APPEND,	
-          size: MTDPART_SIZ_FULL
+	{
+		name:		"zImage",
+		size:		0x100000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
 	}
 };
-
 #endif
 
 #ifdef CONFIG_SA1100_GRAPHICSMASTER
-
-static unsigned long graphicsmaster_max_flash_size = 0x01000000;
+#define GRAPHICSMASTER_FLASH_SIZE	0x01000000
 static struct mtd_partition graphicsmaster_partitions[] = {
-	{ 
-	 name: "zImage",
-	 offset: 0,
-	 size: 0x100000
+	{
+		name:		"zImage",
+		size:		0x100000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
 	},
-	{ 
-         name: "ramdisk.gz",
-         offset: MTDPART_OFS_APPEND,
-         size: 0x300000 		
+	{
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
 	},
-	{ 
-	  name: "User FS",
-          offset: MTDPART_OFS_APPEND,	
-          size: MTDPART_SIZ_FULL
+	{
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
 	}
 };
+#endif
 
+#ifdef CONFIG_SA1100_H3600
+#define H3600_FLASH_SIZE		0x02000000
+static struct mtd_partition h3600_partitions[] = {
+	{
+		name:		"H3600 boot firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"H3600 kernel",
+		size:		0x00080000,
+		offset:		0x00040000,
+	}, {
+		name:		"H3600 params",
+		size:		0x00040000,
+		offset:		0x000C0000,
+	}, {
+#ifdef CONFIG_JFFS2_FS
+		name:		"H3600 root jffs2",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00100000,
+#else
+		name:		"H3600 initrd",
+		size:		0x00100000,
+		offset:		0x00100000,
+	}, {
+		name:		"H3600 root cramfs",
+		size:		0x00300000,
+		offset:		0x00200000,
+	}, {
+		name:		"H3600 usr cramfs",
+		size:		0x00800000,
+		offset:		0x00500000,
+	}, {
+		name:		"H3600 usr local",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00d00000,
 #endif
+	}
+};
 
-#ifdef CONFIG_SA1100_PANGOLIN
+static void h3600_set_vpp(struct map_info *map, int vpp)
+{
+	assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
+}
+#endif
 
-static unsigned long pangolin_max_flash_size = 0x04000000;
-static struct mtd_partition pangolin_partitions[] = {
-	{
-	  name: "boot firmware",
-	  offset: 0x00000000,
-	  size: 0x00080000,
-	  mask_flags: MTD_WRITEABLE,  /* force read-only */
-	},
-	{
-	  name: "kernel",
-	  offset: 0x00080000,
-	  size: 0x00100000,
-	},
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+#define HUW_WEBPANEL_FLASH_SIZE		0x01000000
+static struct mtd_partition huw_webpanel_partitions[] = {
 	{
-	  name: "initrd",
-	  offset: 0x00180000,
-	  size: 0x00280000,
-	},
+		name:		"Loader",
+		size:		0x00040000,
+		offset:		0,
+	}, {
+		name:		"Sector 1",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+#define JORNADA720_FLASH_SIZE		0x02000000
+static struct mtd_partition jornada720_partitions[] = {
 	{
-	  name: "initrd-test",
-	  offset: 0x00400000,
-	  size: 0x03C00000,
+		name:		"JORNADA720 boot firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"JORNADA720 kernel",
+		size:		0x000c0000,
+		offset:		0x00040000,
+	}, {
+		name:		"JORNADA720 params",
+		size:		0x00040000,
+		offset:		0x00100000,
+	}, {
+		name:		"JORNADA720 initrd",
+		size:		0x00100000,
+		offset:		0x00140000,
+	}, {
+		name:		"JORNADA720 root cramfs",
+		size:		0x00300000,
+		offset:		0x00240000,
+	}, {
+		name:		"JORNADA720 usr cramfs",
+		size:		0x00800000,
+		offset:		0x00540000,
+	}, {
+		name:		"JORNADA720 usr local",
+		size:		0  /* will expand to the end of the flash */
+		offset:		0x00d00000,
 	}
 };
 
+static void jornada720_set_vpp(int vpp)
+{
+	if (vpp)
+		PPSR |= 0x80;
+	else
+		PPSR &= ~0x80;
+	PPDR |= 0x80;
+}
+
 #endif
 
-#ifdef CONFIG_SA1100_YOPY
+#ifdef CONFIG_SA1100_PANGOLIN
+#define PANGOLIN_FLASH_SIZE		0x04000000
+static struct mtd_partition pangolin_partitions[] = {
+	{
+		name:		"boot firmware",
+		size:		0x00080000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
+		name:		"initrd",
+		size:		0x00280000,
+		offset:		0x00180000,
+	}, {
+		name:		"initrd-test",
+		size:		0x03C00000,
+		offset:		0x00400000,
+	}
+};
+#endif
 
-static unsigned long yopy_max_flash_size = 0x08000000;
-static struct mtd_partition yopy_partitions[] = {
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+/* erase size is 0x40000 == 256k partitions have to have this boundary */
+#define SYSTEM3_FLASH_SIZE		0x01000000
+static struct mtd_partition system3_partitions[] = {
+	{
+		name:		"BLOB",
+		size:		0x00040000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"config",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"root",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
+
+#ifdef CONFIG_SA1100_SHANNON
+#define SHANNON_FLASH_SIZE		0x00400000
+static struct mtd_partition shannon_partitions[] = {
 	{
-		name: "boot firmware",
-		offset: 0x00000000,
-		size: 0x00040000,
-		mask_flags: MTD_WRITEABLE,  /* force read-only */
+		name: "BLOB boot loader",
+		offset: 0,
+		size: 0x20000
 	},
 	{
 		name: "kernel",
-		offset: 0x00080000,
-		size: 0x00080000,
+		offset: MTDPART_OFS_APPEND,
+		size: 0xe0000
 	},
-	{
+	{ 
 		name: "initrd",
-		offset: 0x00100000,
-		size: 0x00300000,
-	},
-	{
-		name: "root",
-		offset: 0x00400000,
-		size: 0x01000000,
-	},
+		offset: MTDPART_OFS_APPEND,	
+		size: MTDPART_SIZ_FULL
+	}
 };
 
 #endif
 
-#ifdef CONFIG_SA1100_JORNADA720
-
-static unsigned long jornada720_max_flash_size = 0x02000000;
-static struct mtd_partition jornada720_partitions[] = {
+#ifdef CONFIG_SA1100_SHERMAN
+#define SHERMAN_FLASH_SIZE		0x02000000
+static struct mtd_partition sherman_partitions[] = {
 	{
-		name: "JORNADA720 boot firmware",
-		size: 0x00040000,
-		offset: 0,
-		mask_flags: MTD_WRITEABLE  /* force read-only */
-	},{
-		name: "JORNADA720 kernel",
-		size: 0x000c0000,
-		offset: 0x40000
-	},{
-		name: "JORNADA720 params",
-		size: 0x00040000,
-		offset: 0x100000
-	},{
-		name: "JORNADA720 initrd",
-		size: 0x00100000,
-		offset: 0x00140000
-	},{
-		name: "JORNADA720 root cramfs",
-		size: 0x00300000,
-		offset: 0x00240000
-	},{
-		name: "JORNADA720 usr cramfs",
-		size: 0x00800000,
-		offset: 0x00540000
-	},{
-		name: "JORNADA720 usr local",
-		offset: 0x00d00000,
-		size: 0  /* will expand to the end of the flash */
+		size:		0x50000,
+		offset:		0,
+	}, {
+		size:		0x70000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		0x600000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		0xA0000,
+		offset:		MTDPART_OFS_APPEND,
 	}
 };
 #endif
 
-#ifdef CONFIG_SA1100_SHERMAN
-
-static unsigned long sherman_max_flash_size = 0x02000000;
-static struct mtd_partition sherman_partitions[] = {
-	{ offset: 0,			size: 0x50000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0x70000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0x600000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0xA0000 	}
-};
-
+#ifdef CONFIG_SA1100_SIMPAD
+#define SIMPAD_FLASH_SIZE		0x02000000
+static struct mtd_partition simpad_partitions[] = {
+	{
+		name:		"SIMpad boot firmware",
+		size:		0x00080000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"SIMpad kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
+#ifdef CONFIG_JFFS2_FS
+		name:		"SIMpad root jffs2",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00180000,
+#else
+		name:		"SIMpad initrd",
+		size:		0x00300000,
+		offset:		0x00180000,
+	}, {
+		name:		"SIMpad root cramfs",
+		size:		0x00300000,
+		offset:		0x00480000,
+	}, {
+		name:		"SIMpad usr cramfs",
+		size:		0x005c0000,
+		offset:		0x00780000,
+	}, {
+		name:		"SIMpad usr local",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00d40000,
 #endif
+	}
+};
+#endif /* CONFIG_SA1100_SIMPAD */
 
 #ifdef CONFIG_SA1100_STORK
-
-static unsigned long stork_max_flash_size = 0x02000000;
+#define STORK_FLASH_SIZE		0x02000000
 static struct mtd_partition stork_partitions[] = {
 	{
-		name: "STORK boot firmware",
-		size: 0x00040000,
-		offset: 0,
-		mask_flags: MTD_WRITEABLE  /* force read-only */
-	},{
-		name: "STORK params",
-		size: 0x00040000,
-		offset: 0x40000
-	},{
-		name: "STORK kernel",
-		size: 0x00100000,
-		offset: 0x80000
-	},{
+		name:		"STORK boot firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"STORK params",
+		size:		0x00040000,
+		offset:		0x00040000,
+	}, {
+		name:		"STORK kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
 #ifdef CONFIG_JFFS2_FS
-		name: "STORK root jffs2",
-		offset: 0x00180000,
-		size: MTDPART_SIZ_FULL
+		name:		"STORK root jffs2",
+		offset:		0x00180000,
+		size:		MTDPART_SIZ_FULL,
 #else
-		name: "STORK initrd",
-		size: 0x00100000,
-		offset: 0x00180000
-	},{
-		name: "STORK root cramfs",
-		size: 0x00300000,
-		offset: 0x00280000
-	},{
-		name: "STORK usr cramfs",
-		size: 0x00800000,
-		offset: 0x00580000
-	},{
-		name: "STORK usr local",
-		offset: 0x00d80000,
-		size: MTDPART_SIZ_FULL
+		name:		"STORK initrd",
+		size:		0x00100000,
+		offset:		0x00180000,
+	}, {
+		name:		"STORK root cramfs",
+		size:		0x00300000,
+		offset:		0x00280000,
+	}, {
+		name:		"STORK usr cramfs",
+		size:		0x00800000,
+		offset:		0x00580000,
+	}, {
+		name:		"STORK usr local",
+		offset:		0x00d80000,
+		size:		MTDPART_SIZ_FULL,
 #endif
 	}
 };
-
 #endif
 
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
+#ifdef CONFIG_SA1100_YOPY
+#define YOPY_FLASH_SIZE			0x08000000
+static struct mtd_partition yopy_partitions[] = {
+	{
+		name:		"boot firmware",
+		size:		0x00040000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"kernel",
+		size:		0x00080000,
+		offset:		0x00080000,
+	}, {
+		name:		"initrd",
+		size:		0x00300000,
+		offset:		0x00100000,
+	}, {
+		name:		"root",
+		size:		0x01000000,
+		offset:		0x00400000,
+	}
+};
+#endif
 
 extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
 extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
@@ -540,10 +778,11 @@
 int __init sa1100_mtd_init(void)
 {
 	struct mtd_partition *parts;
-	int nb_parts = 0;
+	int nb_parts = 0, ret;
 	int parsed_nr_parts = 0;
-	char *part_type;
-	
+	const char *part_type;
+	unsigned long base = -1UL;
+
 	/* Default flash buswidth */
 	sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
 
@@ -551,103 +790,166 @@
 	 * Static partition definition selection
 	 */
 	part_type = "static";
+
+#ifdef CONFIG_SA1100_ADSBITSY
+	if (machine_is_adsbitsy()) {
+		parts = adsbitsy_partitions;
+		nb_parts = ARRAY_SIZE(adsbitsy_partitions);
+		sa1100_map.size = ADSBITSY_FLASH_SIZE;
+		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
+	}
+#endif
 #ifdef CONFIG_SA1100_ASSABET
 	if (machine_is_assabet()) {
 		parts = assabet_partitions;
-		nb_parts = NB_OF(assabet_partitions);
-		sa1100_map.size = assabet_max_flash_size;
+		nb_parts = ARRAY_SIZE(assabet_partitions);
+		sa1100_map.size = ASSABET_FLASH_SIZE;
 	}
 #endif
-
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-	if (machine_is_huw_webpanel()) {
-		parts = huw_webpanel_partitions;
-		nb_parts = NB_OF(huw_webpanel_partitions);
-		sa1100_map.size = huw_webpanel_max_flash_size;
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4()) {
+		parts = badge4_partitions;
+		nb_parts = ARRAY_SIZE(badge4_partitions);
+		sa1100_map.size = BADGE4_FLASH_SIZE;
 	}
 #endif
-
-#ifdef CONFIG_SA1100_H3600
-	if (machine_is_h3600()) {
-		parts = h3600_partitions;
-		nb_parts = NB_OF(h3600_partitions);
-		sa1100_map.size = h3600_max_flash_size;
-		sa1100_map.set_vpp = h3600_set_vpp;
+#ifdef CONFIG_SA1100_CERF
+	if (machine_is_cerf()) {
+		parts = cerf_partitions;
+		nb_parts = ARRAY_SIZE(cerf_partitions);
+		sa1100_map.size = CERF_FLASH_SIZE;
+	}
+#endif
+#ifdef CONFIG_SA1100_CONSUS
+	if (machine_is_consus()) {
+		parts = consus_partitions;
+		nb_parts = ARRAY_SIZE(consus_partitions);
+		sa1100_map.size = CONSUS_FLASH_SIZE;
+	}
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+	if (machine_is_flexanet()) {
+		parts = flexanet_partitions;
+		nb_parts = ARRAY_SIZE(flexanet_partitions);
+		sa1100_map.size = FLEXANET_FLASH_SIZE;
 	}
 #endif
 #ifdef CONFIG_SA1100_FREEBIRD
 	if (machine_is_freebird()) {
 		parts = freebird_partitions;
-		nb_parts = NB_OF(freebird_partitions);
-		sa1100_map.size = freebird_max_flash_size;
+		nb_parts = ARRAY_SIZE(freebird_partitions);
+		sa1100_map.size = FREEBIRD_FLASH_SIZE;
 	}
 #endif
-#ifdef CONFIG_SA1100_CERF
-	if (machine_is_cerf()) {
-		parts = cerf_partitions;
-		nb_parts = NB_OF(cerf_partitions);
-		sa1100_map.size = cerf_max_flash_size;
+#ifdef CONFIG_SA1100_FRODO
+	if (machine_is_frodo()) {
+		parts = frodo_partitions;
+		nb_parts = ARRAY_SIZE(frodo_partitions);
+		sa1100_map.size = FRODO_FLASH_SIZE;
+		base = 0x00000000;
 	}
-#endif
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	if (machine_is_graphicsclient()) {
 		parts = graphicsclient_partitions;
-		nb_parts = NB_OF(graphicsclient_partitions);
-		sa1100_map.size = graphicsclient_max_flash_size;
+		nb_parts = ARRAY_SIZE(graphicsclient_partitions);
+		sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE;
 		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
 	}
 #endif
 #ifdef CONFIG_SA1100_GRAPHICSMASTER
 	if (machine_is_graphicsmaster()) {
 		parts = graphicsmaster_partitions;
-		nb_parts = NB_OF(graphicsmaster_partitions);
-		sa1100_map.size = graphicsmaster_max_flash_size;
+		nb_parts = ARRAY_SIZE(graphicsmaster_partitions);
+		sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE;
 		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
 	}
 #endif
-#ifdef CONFIG_SA1100_PANGOLIN
-	if (machine_is_pangolin()) {
-		parts = pangolin_partitions;
-		nb_parts = NB_OF(pangolin_partitions);
-		sa1100_map.size = pangolin_max_flash_size;
+#ifdef CONFIG_SA1100_H3600
+	if (machine_is_h3600()) {
+		parts = h3600_partitions;
+		nb_parts = ARRAY_SIZE(h3600_partitions);
+		sa1100_map.size = H3600_FLASH_SIZE;
+		sa1100_map.set_vpp = h3600_set_vpp;
+	}
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+	if (machine_is_huw_webpanel()) {
+		parts = huw_webpanel_partitions;
+		nb_parts = ARRAY_SIZE(huw_webpanel_partitions);
+		sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE;
 	}
 #endif
 #ifdef CONFIG_SA1100_JORNADA720
 	if (machine_is_jornada720()) {
 		parts = jornada720_partitions;
-		nb_parts = NB_OF(jornada720_partitions);
-		sa1100_map.size = jornada720_max_flash_size;
+		nb_parts = ARRAY_SIZE(jornada720_partitions);
+		sa1100_map.size = JORNADA720_FLASH_SIZE;
 		sa1100_map.set_vpp = jornada720_set_vpp;
 	}
 #endif
-#ifdef CONFIG_SA1100_YOPY
-	if (machine_is_yopy()) {
-		parts = yopy_partitions;
-		nb_parts = NB_OF(yopy_partitions);
-		sa1100_map.size = yopy_max_flash_size;
+#ifdef CONFIG_SA1100_PANGOLIN
+	if (machine_is_pangolin()) {
+		parts = pangolin_partitions;
+		nb_parts = ARRAY_SIZE(pangolin_partitions);
+		sa1100_map.size = PANGOLIN_FLASH_SIZE;
+	}
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+	if (machine_is_pt_system3()) {
+		parts = system3_partitions;
+		nb_parts = ARRAY_SIZE(system3_partitions);
+		sa1100_map.size = SYSTEM3_FLASH_SIZE;
+	}
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+	if (machine_is_shannon()) {
+		parts = shannon_partitions;
+		nb_parts = ARRAY_SIZE(shannon_partitions);
+		sa1100_map.size = SHANNON_FLASH_SIZE;
 	}
 #endif
 #ifdef CONFIG_SA1100_SHERMAN
 	if (machine_is_sherman()) {
 		parts = sherman_partitions;
-		nb_parts = NB_OF(sherman_partitions);
-		sa1100_map.size = sherman_max_flash_size;
+		nb_parts = ARRAY_SIZE(sherman_partitions);
+		sa1100_map.size = SHERMAN_FLASH_SIZE;
 	}
 #endif
-#ifdef CONFIG_SA1100_FLEXANET
-	if (machine_is_flexanet()) {
-		parts = flexanet_partitions;
-		nb_parts = NB_OF(flexanet_partitions);
-		sa1100_map.size = flexanet_max_flash_size;
+#ifdef CONFIG_SA1100_SIMPAD
+	if (machine_is_simpad()) {
+		parts = simpad_partitions;
+		nb_parts = ARRAY_SIZE(simpad_partitions);
+		sa1100_map.size = SIMPAD_FLASH_SIZE;
 	}
 #endif
 #ifdef CONFIG_SA1100_STORK
 	if (machine_is_stork()) {
 		parts = stork_partitions;
-		nb_parts = NB_OF(stork_partitions);
-		sa1100_map.size = stork_max_flash_size;
+		nb_parts = ARRAY_SIZE(stork_partitions);
+		sa1100_map.size = STORK_FLASH_SIZE;
 	}
 #endif
+#ifdef CONFIG_SA1100_YOPY
+	if (machine_is_yopy()) {
+		parts = yopy_partitions;
+		nb_parts = ARRAY_SIZE(yopy_partitions);
+		sa1100_map.size = YOPY_FLASH_SIZE;
+	}
+#endif
+
+	/*
+	 * For simple flash devices, use ioremap to map the flash.
+	 */
+	if (base != (unsigned long)-1) {
+		if (!request_mem_region(base, sa1100_map.size, "flash"))
+			return -EBUSY;
+		sa1100_map.map_priv_2 = base;
+		sa1100_map.map_priv_1 = (unsigned long)
+				ioremap(base, sa1100_map.size);
+		ret = -ENOMEM;
+		if (!sa1100_map.map_priv_1)
+			goto out_err;
+	}
 
 	/*
 	 * Now let's probe for the actual flash.  Do it here since
@@ -655,8 +957,9 @@
 	 */
 	printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
 	mymtd = do_map_probe("cfi_probe", &sa1100_map);
+	ret = -ENXIO;
 	if (!mymtd)
-		return -ENXIO;
+		goto out_err;
 	mymtd->module = THIS_MODULE;
 
 	/*
@@ -665,7 +968,7 @@
 #ifdef CONFIG_MTD_REDBOOT_PARTS
 	if (parsed_nr_parts == 0) {
 		int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-		
+
 		if (ret > 0) {
 			part_type = "RedBoot";
 			parsed_nr_parts = ret;
@@ -695,6 +998,13 @@
 		add_mtd_partitions(mymtd, parts, nb_parts);
 	}
 	return 0;
+
+ out_err:
+	if (sa1100_map.map_priv_2 != -1) {
+		iounmap((void *)sa1100_map.map_priv_1);
+		release_mem_region(sa1100_map.map_priv_2, sa1100_map.size);
+	}
+	return ret;
 }
 
 static void __exit sa1100_mtd_cleanup(void)
@@ -705,6 +1015,10 @@
 		if (parsed_parts)
 			kfree(parsed_parts);
 	}
+	if (sa1100_map.map_priv_2 != -1) {
+		iounmap((void *)sa1100_map.map_priv_1);
+		release_mem_region(sa1100_map.map_priv_2, sa1100_map.size);
+	}
 }
 
 module_init(sa1100_mtd_init);
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/sbc_gxx.c linux-2.4.19-pre5/drivers/mtd/maps/sbc_gxx.c
--- linux-2.4.19-pre4/drivers/mtd/maps/sbc_gxx.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre5/drivers/mtd/maps/sbc_gxx.c	Fri Mar 29 14:49:34 2002
@@ -17,7 +17,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: sbc_gxx.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.20 2002/02/13 15:30:20 dwmw2 Exp $
 
 The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
 Intel StrataFlash (28F320/28F640) in x8 mode.  
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/sc520cdp.c linux-2.4.19-pre5/drivers/mtd/maps/sc520cdp.c
--- linux-2.4.19-pre4/drivers/mtd/maps/sc520cdp.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/sc520cdp.c	Fri Mar 29 14:49:34 2002
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: sc520cdp.c,v 1.9 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $
  *
  *
  * The SC520CDP is an evaluation board for the Elan SC520 processor available
@@ -25,13 +25,14 @@
  * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
-
+#include <linux/mtd/concat.h>
 
 /*
 ** The Embedded Systems BIOS decodes the first FLASH starting at
@@ -171,6 +172,7 @@
 #define NUM_FLASH_BANKS	(sizeof(sc520cdp_map)/sizeof(struct map_info))
 
 static struct mtd_info *mymtd[NUM_FLASH_BANKS];
+static struct mtd_info *merged_mtd;
 
 #ifdef REPROGRAM_PAR
 
@@ -307,19 +309,26 @@
 		}
 		mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]);
 		if(!mymtd[i])
-			mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]);
+			mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]);
 		if(!mymtd[i])
 			mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]);
 
 		if (mymtd[i]) {
 			mymtd[i]->module = THIS_MODULE;
-			add_mtd_device(mymtd[i]);
 			++devices_found;
 		}
 		else {
 			iounmap((void *)sc520cdp_map[i].map_priv_1);
 		}
 	}
+	if(devices_found >= 2) {
+		/* Combine the two flash banks into a single MTD device & register it: */
+		merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1");
+		if(merged_mtd)
+			add_mtd_device(merged_mtd);
+	}
+	if(devices_found == 3) /* register the third (DIL-Flash) device */
+		add_mtd_device(mymtd[2]);
 	return(devices_found ? 0 : -ENXIO);
 }
 
@@ -327,11 +336,16 @@
 {
 	int i;
 	
+	if (merged_mtd) {
+		del_mtd_device(merged_mtd);
+		mtd_concat_destroy(merged_mtd);
+	}
+	if (mymtd[2])
+		del_mtd_device(mymtd[2]);
+
 	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-		if (mymtd[i]) {
-			del_mtd_device(mymtd[i]);
+		if (mymtd[i])
 			map_destroy(mymtd[i]);
-		}
 		if (sc520cdp_map[i].map_priv_1) {
 			iounmap((void *)sc520cdp_map[i].map_priv_1);
 			sc520cdp_map[i].map_priv_1 = 0;
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/solutionengine.c linux-2.4.19-pre5/drivers/mtd/maps/solutionengine.c
--- linux-2.4.19-pre4/drivers/mtd/maps/solutionengine.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/maps/solutionengine.c	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: solutionengine.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $
  *
  * Flash and EPROM on Hitachi Solution Engine and similar boards.
  *
@@ -15,6 +15,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
+#include <linux/config.h>
 
 
 extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
@@ -57,20 +58,38 @@
 	write32: soleng_write32,
 };
 
+#ifdef CONFIG_MTD_SUPERH_RESERVE
+static struct mtd_partition superh_se_partitions[] = {
+	/* Reserved for boot code, read-only */
+	{
+		name: "flash_boot",
+		offset: 0x00000000,
+		size: CONFIG_MTD_SUPERH_RESERVE,
+		mask_flags: MTD_WRITEABLE,
+	},
+	/* All else is writable (e.g. JFFS) */
+	{
+		name: "Flash FS",
+		offset: MTDPART_OFS_NXTBLK,
+		size: MTDPART_SIZ_FULL,
+	}
+};
+#endif /* CONFIG_MTD_SUPERH_RESERVE */
+
 static int __init init_soleng_maps(void)
 {
-	int nr_parts;
+	int nr_parts = 0;
 
 	/* First probe at offset 0 */
 	soleng_flash_map.map_priv_1 = P2SEGADDR(0);
-	soleng_eprom_map.map_priv_1 = P1SEGADDR(0x400000);
+	soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000);
 
-	printk(KERN_NOTICE "Probing for flash chips at 0x000000:\n");
+	printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
 	flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
 	if (!flash_mtd) {
 		/* Not there. Try swapping */
-		printk(KERN_NOTICE "Probing for flash chips at 0x400000:\n");
-		soleng_flash_map.map_priv_1 = P2SEGADDR(0x400000);
+		printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n");
+		soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000);
 		soleng_eprom_map.map_priv_1 = P1SEGADDR(0);
 		flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
 		if (!flash_mtd) {
@@ -90,9 +109,23 @@
 		add_mtd_device(eprom_mtd);
 	}
 
+#ifdef CONFIG_MTD_REDBOOT_PARTS
 	nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
+	if (nr_parts > 0)
+		printk(KERN_NOTICE "Found RedBoot partition table.\n");
+	else if (nr_parts < 0)
+		printk(KERN_NOTICE "Error looking for RedBoot partitions.\n");
+#endif /* CONFIG_MTD_REDBOOT_PARTS */
+#if CONFIG_MTD_SUPERH_RESERVE
+	if (nr_parts == 0) {
+		printk(KERN_NOTICE "Using configured partition at 0x%08x.\n",
+		       CONFIG_MTD_SUPERH_RESERVE);
+		parsed_parts = superh_se_partitions;
+		nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts);
+	}
+#endif /* CONFIG_MTD_SUPERH_RESERVE */
 
-	if (nr_parts)
+	if (nr_parts > 0)
 		add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
 	else
 		add_mtd_device(flash_mtd);
diff -urN linux-2.4.19-pre4/drivers/mtd/maps/tsunami_flash.c linux-2.4.19-pre5/drivers/mtd/maps/tsunami_flash.c
--- linux-2.4.19-pre4/drivers/mtd/maps/tsunami_flash.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/maps/tsunami_flash.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,110 @@
+/*
+ * tsunami_flash.c
+ *
+ * flash chip on alpha ds10...
+ * $Id: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $
+ */
+#include <asm/io.h>
+#include <asm/core_tsunami.h>
+#include <linux/mtd/map.h>
+
+#define FLASH_ENABLE_PORT 0x00C00001
+#define FLASH_ENABLE_BYTE 0x01
+#define FLASH_DISABLE_BYTE 0x00
+
+#define MAX_TIG_FLASH_SIZE (12*1024*1024)
+static inline  __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset)
+{
+	return tsunami_tig_readb(offset);
+}
+
+static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset)
+{
+	tsunami_tig_writeb(value, offset);
+}
+
+static void tsunami_flash_copy_from(
+	struct map_info *map, void *addr, unsigned long offset, ssize_t len)
+{
+	unsigned char *dest;
+	dest = addr;
+	while(len && (offset < MAX_TIG_FLASH_SIZE)) {
+		*dest = tsunami_tig_readb(offset);
+		offset++;
+		dest++;
+		len--;
+	}
+}
+
+static void tsunami_flash_copy_to(
+	struct map_info *map, unsigned long offset, 
+	const void *addr, ssize_t len)
+{
+	const unsigned char *src;
+	src = addr;
+	while(len && (offset < MAX_TIG_FLASH_SIZE)) {
+		tsunami_tig_writeb(*src, offset);
+		offset++;
+		src++;
+		len--;
+	}
+}
+
+/*
+ * Deliberately don't provide operations wider than 8 bits.  I don't
+ * have then and it scares me to think how you could mess up if
+ * you tried to use them.   Buswidth is correctly so I'm safe.
+ */
+static struct map_info tsunami_flash_map = {
+	.name = "flash chip on the Tsunami TIG bus",
+	.size = MAX_TIG_FLASH_SIZE,
+	.buswidth = 1,
+	.read8 = tsunami_flash_read8,
+	.read16 = 0,
+	.read32 = 0, 
+	.copy_from = tsunami_flash_copy_from,
+	.write8 = tsunami_flash_write8,
+	.write16 = 0,
+	.write32 = 0,
+	.copy_to = tsunami_flash_copy_to,
+	.set_vpp = 0,
+	.map_priv_1 = 0,
+
+};
+
+static struct mtd_info *tsunami_flash_mtd;
+
+static void __exit  cleanup_tsunami_flash(void)
+{
+	struct mtd_info *mtd;
+	mtd = tsunami_flash_mtd;
+	if (mtd) {
+		del_mtd_device(mtd);
+		map_destroy(mtd);
+	}
+	tsunami_flash_mtd = 0;
+}
+
+
+static int __init init_tsunami_flash(void)
+{
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	char **type;
+
+	tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);
+	
+	tsunami_flash_mtd = 0;
+	type = rom_probe_types;
+	for(; !tsunami_flash_mtd && *type; type++) {
+		tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map);
+	}
+	if (tsunami_flash_mtd) {
+		tsunami_flash_mtd->module = THIS_MODULE;
+		add_mtd_device(tsunami_flash_mtd);
+		return 0;
+	}
+	return -ENXIO;
+}
+
+module_init(init_tsunami_flash);
+module_exit(cleanup_tsunami_flash);
diff -urN linux-2.4.19-pre4/drivers/mtd/mtdblock.c linux-2.4.19-pre5/drivers/mtd/mtdblock.c
--- linux-2.4.19-pre4/drivers/mtd/mtdblock.c	Thu Oct 25 13:58:35 2001
+++ linux-2.4.19-pre5/drivers/mtd/mtdblock.c	Fri Mar 29 14:49:34 2002
@@ -1,7 +1,7 @@
 /* 
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.47 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.51 2001/11/20 11:42:33 dwmw2 Exp $
  *
  * 02-nov-2000	Nicolas Pitre		Added read-modify-write with cache
  */
@@ -60,6 +60,13 @@
 static int mtd_sizes[MAX_MTD_DEVICES];
 static int mtd_blksizes[MAX_MTD_DEVICES];
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#else
+#define BLK_INC_USE_COUNT do {} while(0)
+#define BLK_DEC_USE_COUNT do {} while(0)
+#endif
 
 /*
  * Cache stuff...
@@ -287,11 +294,14 @@
 	if (dev >= MAX_MTD_DEVICES)
 		return -EINVAL;
 
+	BLK_INC_USE_COUNT;
+
 	mtd = get_mtd_device(NULL, dev);
 	if (!mtd)
 		return -ENODEV;
 	if (MTD_ABSENT == mtd->type) {
 		put_mtd_device(mtd);
+		BLK_DEC_USE_COUNT;
 		return -ENODEV;
 	}
 	
@@ -314,6 +324,7 @@
 	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
 	if (!mtdblk) {
 		put_mtd_device(mtd);
+		BLK_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	memset(mtdblk, 0, sizeof(*mtdblk));
@@ -329,6 +340,7 @@
 		if (!mtdblk->cache_data) {
 			put_mtd_device(mtdblk->mtd);
 			kfree(mtdblk);
+			BLK_DEC_USE_COUNT;
 			return -ENOMEM;
 		}
 	}
@@ -371,8 +383,6 @@
 	if (inode == NULL)
 		release_return(-ENODEV);
 
-	invalidate_device(inode->i_rdev, 1);
-
 	dev = MINOR(inode->i_rdev);
 	mtdblk = mtdblks[dev];
 
@@ -396,6 +406,7 @@
 
 	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
+	BLK_DEC_USE_COUNT;
 	release_return(0);
 }  
 
@@ -535,8 +546,11 @@
 	switch (cmd) {
 	case BLKGETSIZE:   /* Return device size */
 		return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg);
+
+#ifdef BLKGETSIZE64
 	case BLKGETSIZE64:
 		return put_user((u64)mtdblk->mtd->size, (u64 *)arg);
+#endif
 		
 	case BLKFLSBUF:
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
@@ -569,7 +583,9 @@
 #else
 static struct block_device_operations mtd_fops = 
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
 	owner: THIS_MODULE,
+#endif
 	open: mtdblock_open,
 	release: mtdblock_release,
 	ioctl: mtdblock_ioctl
diff -urN linux-2.4.19-pre4/drivers/mtd/mtdblock_ro.c linux-2.4.19-pre5/drivers/mtd/mtdblock_ro.c
--- linux-2.4.19-pre4/drivers/mtd/mtdblock_ro.c	Thu Oct 25 13:58:35 2001
+++ linux-2.4.19-pre5/drivers/mtd/mtdblock_ro.c	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdblock_ro.c,v 1.9 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $
  *
  * Read-only version of the mtdblock device, without the 
  * read/erase/modify/writeback stuff
@@ -37,6 +37,13 @@
 MODULE_PARM(debug, "i");
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#else
+#define BLK_INC_USE_COUNT do {} while(0)
+#define BLK_DEC_USE_COUNT do {} while(0)
+#endif
 
 static int mtd_sizes[MAX_MTD_DEVICES];
 
@@ -62,6 +69,8 @@
 		return -EINVAL;
 	}
 
+	BLK_INC_USE_COUNT;
+
 	mtd_sizes[dev] = mtd->size>>9;
 
 	DEBUG(1, "ok\n");
@@ -79,13 +88,12 @@
 	if (inode == NULL)
 		release_return(-ENODEV);
    
-	invalidate_device(inode->i_rdev, 1);
-
 	dev = MINOR(inode->i_rdev);
 	mtd = __get_mtd_device(NULL, dev);
 
 	if (!mtd) {
 		printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
+		BLK_DEC_USE_COUNT;
 		release_return(-ENODEV);
 	}
 	
@@ -96,6 +104,7 @@
 
 	DEBUG(1, "ok\n");
 
+	BLK_DEC_USE_COUNT;
 	release_return(0);
 }  
 
@@ -210,9 +219,12 @@
 	switch (cmd) {
 	case BLKGETSIZE:   /* Return device size */
 		return put_user((mtd->size >> 9), (unsigned long *) arg);
+
+#ifdef BLKGETSIZE64
 	case BLKGETSIZE64:
 		return put_user((u64)mtd->size, (u64 *)arg);
-		
+#endif
+
 	case BLKFLSBUF:
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 		if(!capable(CAP_SYS_ADMIN))  return -EACCES;
@@ -240,7 +252,9 @@
 #else
 static struct block_device_operations mtd_fops = 
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
 	owner: THIS_MODULE,
+#endif
 	open: mtdblock_open,
 	release: mtdblock_release,
 	ioctl: mtdblock_ioctl
diff -urN linux-2.4.19-pre4/drivers/mtd/mtdconcat.c linux-2.4.19-pre5/drivers/mtd/mtdconcat.c
--- linux-2.4.19-pre4/drivers/mtd/mtdconcat.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/mtd/mtdconcat.c	Fri Mar 29 14:49:34 2002
@@ -0,0 +1,672 @@
+/*
+ * MTD device concatenation layer
+ *
+ * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
+ *
+ * This code is GPL
+ *
+ * $Id: mtdconcat.c,v 1.2 2002/03/22 08:45:22 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
+
+/*
+ * Our storage structure:
+ * Subdev points to an array of pointers to struct mtd_info objects
+ * which is allocated along with this structure
+ *
+ */
+struct mtd_concat {
+	struct mtd_info mtd;
+	int             num_subdev;
+	struct mtd_info **subdev;
+};
+
+/*
+ * how to calculate the size required for the above structure,
+ * including the pointer array subdev points to:
+ */
+#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev)	\
+	((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
+
+
+/*
+ * Given a pointer to the MTD object in the mtd_concat structure,
+ * we can retrieve the pointer to that structure with this macro.
+ */
+#define CONCAT(x)  ((struct mtd_concat *)(x))
+
+	
+/* 
+ * MTD methods which look up the relevant subdevice, translate the
+ * effective address and pass through to the subdevice.
+ */
+
+static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+
+		if (from >= subdev->size)
+		{
+			size  = 0;
+			from -= subdev->size;
+		}
+		else
+		{
+			if (from + len > subdev->size)
+				size = subdev->size - from;
+			else
+				size = len;
+
+			err = subdev->read(subdev, from, size, &retsize, buf);
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+			from = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+
+		if (to >= subdev->size)
+		{
+			size  = 0;
+			to -= subdev->size;
+		}
+		else
+		{
+			if (to + len > subdev->size)
+				size = subdev->size - to;
+			else
+				size = len;
+
+			if (!(subdev->flags & MTD_WRITEABLE))
+				err = -EROFS;
+			else
+				err = subdev->write(subdev, to, size, &retsize, buf);
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+			to = 0;
+		}
+	}
+	return err;
+}
+
+static void concat_erase_callback (struct erase_info *instr)
+{
+	wake_up((wait_queue_head_t *)instr->priv);
+}
+
+static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	int err;
+	wait_queue_head_t waitq;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * This code was stol^H^H^H^Hinspired by mtdchar.c
+	 */
+	init_waitqueue_head(&waitq);
+
+	erase->mtd = mtd;
+	erase->callback = concat_erase_callback;
+	erase->priv = (unsigned long)&waitq;
+			
+	/*
+	 * FIXME: Allow INTERRUPTIBLE. Which means
+	 * not having the wait_queue head on the stack.
+	 */
+	err = mtd->erase(mtd, erase);
+	if (!err)
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&waitq, &wait);
+		if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
+			schedule();
+		remove_wait_queue(&waitq, &wait);
+		set_current_state(TASK_RUNNING);
+
+		err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;
+	}
+	return err;
+}
+
+static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	struct mtd_info *subdev;
+	int i, err;
+	u_int32_t length;
+	struct erase_info *erase;
+
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	if(instr->addr > concat->mtd.size)
+		return -EINVAL;
+
+	if(instr->len + instr->addr > concat->mtd.size)
+		return -EINVAL;
+
+	/*
+	 * Check for proper erase block alignment of the to-be-erased area.
+	 * It is easier to do this based on the super device's erase
+	 * region info rather than looking at each particular sub-device
+	 * in turn.
+	 */
+	if (!concat->mtd.numeraseregions)
+	{	/* the easy case: device has uniform erase block size */
+		if(instr->addr & (concat->mtd.erasesize - 1))
+			return -EINVAL;
+		if(instr->len & (concat->mtd.erasesize - 1))
+			return -EINVAL;
+	}
+	else
+	{	/* device has variable erase size */
+		struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
+
+		/*
+		 * Find the erase region where the to-be-erased area begins:
+		 */
+		for(i = 0; i < concat->mtd.numeraseregions && 
+		           instr->addr >= erase_regions[i].offset; i++)
+			;
+		--i;
+
+		/*
+		 * Now erase_regions[i] is the region in which the
+		 * to-be-erased area begins. Verify that the starting
+		 * offset is aligned to this region's erase size:
+		 */
+		if (instr->addr & (erase_regions[i].erasesize-1))
+			return -EINVAL;
+
+		/*
+		 * now find the erase region where the to-be-erased area ends:
+		 */
+		for(; i < concat->mtd.numeraseregions && 
+		      (instr->addr + instr->len) >=  erase_regions[i].offset ; ++i)
+			;
+		--i;
+		/*
+		 * check if the ending offset is aligned to this region's erase size
+		 */
+		if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
+			return -EINVAL;
+	}
+
+	/* make a local copy of instr to avoid modifying the caller's struct */
+	erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+
+	if (!erase)
+		return -ENOMEM;
+
+	*erase = *instr;
+	length = instr->len;
+
+	/*
+	 * find the subdevice where the to-be-erased area begins, adjust
+	 * starting offset to be relative to the subdevice start
+	 */
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		subdev = concat->subdev[i];
+		if(subdev->size <= erase->addr)
+			erase->addr -= subdev->size;
+		else
+			break;
+    }
+	if(i >= concat->num_subdev)	/* must never happen since size */
+		BUG();					/* limit has been verified above */
+
+	/* now do the erase: */
+	err = 0;
+	for(;length > 0; i++)	/* loop for all subevices affected by this request */
+	{
+		subdev = concat->subdev[i];		/* get current subdevice */
+
+		/* limit length to subdevice's size: */
+		if(erase->addr + length > subdev->size)
+			erase->len = subdev->size - erase->addr;
+		else
+			erase->len = length;
+
+		if (!(subdev->flags & MTD_WRITEABLE))
+		{
+			err = -EROFS;
+			break;
+		}
+		length -= erase->len;
+		if ((err = concat_dev_erase(subdev, erase)))
+		{
+			if(err == -EINVAL)	/* sanity check: must never happen since */
+				BUG();			/* block alignment has been checked above */
+			break;
+		}
+		/*
+		 * erase->addr specifies the offset of the area to be
+		 * erased *within the current subdevice*. It can be
+		 * non-zero only the first time through this loop, i.e.
+		 * for the first subdevice where blocks need to be erased.
+		 * All the following erases must begin at the start of the
+		 * current subdevice, i.e. at offset zero.
+		 */
+		erase->addr = 0;
+	}
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	kfree(erase);
+	return err;
+}
+
+static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, err = -EINVAL;
+
+	if ((len + ofs) > mtd->size) 
+		return -EINVAL;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size;
+
+		if (ofs >= subdev->size)
+		{
+			size  = 0;
+			ofs -= subdev->size;
+		}
+		else
+		{
+			if (ofs + len > subdev->size)
+				size = subdev->size - ofs;
+			else
+				size = len;
+
+			err = subdev->lock(subdev, ofs, size);
+
+			if(err)
+				break;
+
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			ofs = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, err = 0;
+
+	if ((len + ofs) > mtd->size) 
+		return -EINVAL;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size;
+
+		if (ofs >= subdev->size)
+		{
+			size  = 0;
+			ofs -= subdev->size;
+		}
+		else
+		{
+			if (ofs + len > subdev->size)
+				size = subdev->size - ofs;
+			else
+				size = len;
+
+			err = subdev->unlock(subdev, ofs, size);
+
+			if(err)
+				break;
+
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			ofs = 0;
+		}
+	}
+	return err;
+}
+
+static void concat_sync(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		subdev->sync(subdev);
+	}
+}
+
+static int concat_suspend(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, rc = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		if((rc = subdev->suspend(subdev)) < 0)
+			return rc;
+	}
+	return rc;
+}
+
+static void concat_resume(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		subdev->resume(subdev);
+	}
+}
+
+/*
+ * This function constructs a virtual MTD device by concatenating
+ * num_devs MTD devices. A pointer to the new device object is
+ * stored to *new_dev upon success. This function does _not_
+ * register any devices: this is the caller's responsibility.
+ */
+struct mtd_info *mtd_concat_create(
+	struct mtd_info *subdev[],	/* subdevices to concatenate */
+	int num_devs,				/* number of subdevices      */
+	char *name)					/* name for the new device   */
+{
+	int i;
+	size_t size;
+	struct mtd_concat *concat;
+	u_int32_t max_erasesize, curr_erasesize;
+	int num_erase_region;
+
+	printk(KERN_NOTICE "Concatenating MTD devices:\n");
+	for(i = 0; i < num_devs; i++)
+		printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
+	printk(KERN_NOTICE "into device \"%s\"\n", name);
+
+	/* allocate the device structure */
+	size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
+	concat = kmalloc (size, GFP_KERNEL);
+	if(!concat)
+	{
+		printk ("memory allocation error while creating concatenated device \"%s\"\n",
+				name);
+			return NULL;
+	}
+	memset(concat, 0, size);
+	concat->subdev = (struct mtd_info **)(concat + 1);
+
+	/*
+	 * Set up the new "super" device's MTD object structure, check for
+	 * incompatibilites between the subdevices.
+	 */
+	concat->mtd.type      = subdev[0]->type;
+	concat->mtd.flags     = subdev[0]->flags;
+	concat->mtd.size      = subdev[0]->size;
+	concat->mtd.erasesize = subdev[0]->erasesize;
+	concat->mtd.oobblock  = subdev[0]->oobblock;
+	concat->mtd.oobsize   = subdev[0]->oobsize;
+	concat->mtd.ecctype   = subdev[0]->ecctype;
+	concat->mtd.eccsize   = subdev[0]->eccsize;
+
+	concat->subdev[0]   = subdev[0];
+
+	for(i = 1; i < num_devs; i++)
+	{
+		if(concat->mtd.type != subdev[i]->type)
+		{
+			kfree(concat);
+			printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
+			return NULL;
+		}
+		if(concat->mtd.flags != subdev[i]->flags)
+		{	/*
+			 * Expect all flags except MTD_WRITEABLE to be equal on
+			 * all subdevices.
+			 */
+			if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
+			{
+				kfree(concat);
+				printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
+				return NULL;
+			}
+			else	/* if writeable attribute differs, make super device writeable */
+				concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
+		}
+		concat->mtd.size += subdev[i]->size;
+		if(concat->mtd.oobblock != subdev[i]->oobblock ||
+		   concat->mtd.oobsize  != subdev[i]->oobsize  ||
+		   concat->mtd.ecctype  != subdev[i]->ecctype  ||
+		   concat->mtd.eccsize  != subdev[i]->eccsize)
+		{
+			kfree(concat);
+			printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
+			return NULL;
+		}
+		concat->subdev[i] = subdev[i];
+		
+	}
+
+	concat->num_subdev  = num_devs;
+	concat->mtd.name    = name;
+
+	/*
+	 * NOTE: for now, we do not provide any readv()/writev() methods
+	 *       because they are messy to implement and they are not
+	 *       used to a great extent anyway.
+	 */
+	concat->mtd.erase   = concat_erase;
+	concat->mtd.read    = concat_read;
+	concat->mtd.write   = concat_write;
+	concat->mtd.sync    = concat_sync;
+	concat->mtd.lock    = concat_lock;
+	concat->mtd.unlock  = concat_unlock;
+	concat->mtd.suspend = concat_suspend;
+	concat->mtd.resume  = concat_resume;
+
+
+	/*
+	 * Combine the erase block size info of the subdevices:
+	 *
+	 * first, walk the map of the new device and see how
+	 * many changes in erase size we have
+	 */
+	max_erasesize = curr_erasesize = subdev[0]->erasesize;
+	num_erase_region = 1;
+	for(i = 0; i < num_devs; i++)
+	{
+		if(subdev[i]->numeraseregions == 0)
+		{	/* current subdevice has uniform erase size */
+			if(subdev[i]->erasesize != curr_erasesize)
+			{	/* if it differs from the last subdevice's erase size, count it */
+				++num_erase_region;
+				curr_erasesize = subdev[i]->erasesize;
+				if(curr_erasesize > max_erasesize)
+					max_erasesize = curr_erasesize;
+			}
+		}
+		else
+		{	/* current subdevice has variable erase size */
+			int j;
+			for(j = 0; j < subdev[i]->numeraseregions; j++)
+			{	/* walk the list of erase regions, count any changes */
+				if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+				{
+					++num_erase_region;
+					curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+					if(curr_erasesize > max_erasesize)
+						max_erasesize = curr_erasesize;
+				}
+			}
+		}
+	}
+
+	if(num_erase_region == 1)
+	{	/*
+		 * All subdevices have the same uniform erase size.
+		 * This is easy:
+		 */
+		concat->mtd.erasesize = curr_erasesize;
+		concat->mtd.numeraseregions = 0;
+	}
+	else
+	{	/*
+		 * erase block size varies across the subdevices: allocate
+		 * space to store the data describing the variable erase regions
+		 */
+		struct mtd_erase_region_info *erase_region_p;
+		u_int32_t begin, position;
+
+		concat->mtd.erasesize = max_erasesize;
+		concat->mtd.numeraseregions = num_erase_region;
+		concat->mtd.eraseregions = erase_region_p = kmalloc (
+		     num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+		if(!erase_region_p)
+		{
+			kfree(concat);
+			printk ("memory allocation error while creating erase region list"
+			        " for device \"%s\"\n", name);
+			return NULL;
+		}
+
+		/*
+		 * walk the map of the new device once more and fill in
+		 * in erase region info:
+		 */
+		curr_erasesize = subdev[0]->erasesize;
+		begin = position = 0;
+		for(i = 0; i < num_devs; i++)
+		{
+			if(subdev[i]->numeraseregions == 0)
+			{	/* current subdevice has uniform erase size */
+				if(subdev[i]->erasesize != curr_erasesize)
+				{	/*
+					 *  fill in an mtd_erase_region_info structure for the area
+					 *  we have walked so far:
+					 */
+					erase_region_p->offset    = begin;
+					erase_region_p->erasesize = curr_erasesize;
+					erase_region_p->numblocks = (position - begin) / curr_erasesize;
+					begin = position;
+
+					curr_erasesize = subdev[i]->erasesize;
+					++erase_region_p;
+				}
+				position += subdev[i]->size;
+			}
+			else
+			{	/* current subdevice has variable erase size */
+				int j;
+				for(j = 0; j < subdev[i]->numeraseregions; j++)
+				{	/* walk the list of erase regions, count any changes */
+					if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+					{
+						erase_region_p->offset    = begin;
+						erase_region_p->erasesize = curr_erasesize;
+						erase_region_p->numblocks = (position - begin) / curr_erasesize;
+						begin = position;
+
+						curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+						++erase_region_p;
+					}
+					position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
+				}
+			}
+		}
+		/* Now write the final entry */
+		erase_region_p->offset    = begin;
+		erase_region_p->erasesize = curr_erasesize;
+		erase_region_p->numblocks = (position - begin) / curr_erasesize;
+	}
+
+	return &concat->mtd;
+}
+
+/* 
+ * This function destroys an MTD object obtained from concat_mtd_devs()
+ */
+
+void mtd_concat_destroy(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	if(concat->mtd.numeraseregions)
+		kfree(concat->mtd.eraseregions);
+	kfree(concat);
+}
+
+
+EXPORT_SYMBOL(mtd_concat_create);
+EXPORT_SYMBOL(mtd_concat_destroy);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
+MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
diff -urN linux-2.4.19-pre4/drivers/mtd/mtdcore.c linux-2.4.19-pre5/drivers/mtd/mtdcore.c
--- linux-2.4.19-pre4/drivers/mtd/mtdcore.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/mtdcore.c	Fri Mar 29 14:49:34 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.31 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.32 2002/03/07 18:38:10 joern Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -296,7 +296,7 @@
 	up(&mtd_table_mutex);
         if (off >= len+begin)
                 return 0;
-        *start = page + (begin-off);
+        *start = page + (off-begin);
         return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -urN linux-2.4.19-pre4/drivers/mtd/mtdpart.c linux-2.4.19-pre5/drivers/mtd/mtdpart.c
--- linux-2.4.19-pre4/drivers/mtd/mtdpart.c	Thu Oct  4 15:14:59 2001
+++ linux-2.4.19-pre5/drivers/mtd/mtdpart.c	Fri Mar 29 14:49:34 2002
@@ -5,8 +5,12 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $
- */
+ * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $
+ * - with protection register access removed until that code is merged in 2.4.
+ *
+ * 	02-21-2002	Thomas Gleixner <gleixner@autronix.de>
+ *			added support for read_oob, write_oob
+ */	
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -28,6 +32,7 @@
 	u_int32_t offset;
 	int index;
 	struct list_head list;
+	int registered;
 };
 
 /*
@@ -54,6 +59,18 @@
 					len, retlen, buf);
 }
 
+static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->read_oob (part->master, from + part->offset, 
+					len, retlen, buf);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
@@ -68,6 +85,20 @@
 					len, retlen, buf);
 }
 
+static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->write_oob (part->master, to + part->offset, 
+					len, retlen, buf);
+}
+
 static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
 			 unsigned long count, loff_t to, size_t *retlen)
 {
@@ -148,7 +179,8 @@
 		if (slave->master == master) {
 			struct list_head *prev = node->prev;
 			__list_del(prev, node->next);
-			del_mtd_device(&slave->mtd);
+			if(slave->registered)
+				del_mtd_device(&slave->mtd);
 			kfree(slave);
 			node = prev;
 		}
@@ -198,18 +230,21 @@
 
 		slave->mtd.name = parts[i].name;
 		slave->mtd.bank_size = master->bank_size;
-
 		slave->mtd.module = master->module;
 
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
+
+		if (master->read_oob)
+			slave->mtd.read_oob = part_read_oob;
+		if (master->write_oob)
+			slave->mtd.write_oob = part_write_oob;
 		if (master->sync)
 			slave->mtd.sync = part_sync;
 		if (!i && master->suspend && master->resume) {
 				slave->mtd.suspend = part_suspend;
 				slave->mtd.resume = part_resume;
 		}
-
 		if (master->writev)
 			slave->mtd.writev = part_writev;
 		if (master->readv)
@@ -225,6 +260,15 @@
 
 		if (slave->offset == MTDPART_OFS_APPEND)
 			slave->offset = cur_offset;
+		if (slave->offset == MTDPART_OFS_NXTBLK) {
+			u_int32_t emask = master->erasesize-1;
+			slave->offset = (cur_offset + emask) & ~emask;
+			if (slave->offset != cur_offset) {
+				printk(KERN_NOTICE "Moving partition %d: "
+				       "0x%08x -> 0x%08x\n", i,
+				       cur_offset, slave->offset);
+			}
+		}
 		if (slave->mtd.size == MTDPART_SIZ_FULL)
 			slave->mtd.size = master->size - slave->offset;
 		cur_offset = slave->offset + slave->mtd.size;
@@ -279,8 +323,17 @@
 				parts[i].name);
 		}
 
-		/* register our partition */
-		add_mtd_device(&slave->mtd);
+		if(parts[i].mtdp)
+		{	/* store the object pointer (caller may or may not register it */
+			*parts[i].mtdp = &slave->mtd;
+			slave->registered = 0;
+		}
+		else
+		{
+			/* register our partition */
+			add_mtd_device(&slave->mtd);
+			slave->registered = 1;
+		}
 	}
 
 	return 0;
diff -urN linux-2.4.19-pre4/drivers/mtd/nand/nand_ecc.c linux-2.4.19-pre5/drivers/mtd/nand/nand_ecc.c
--- linux-2.4.19-pre4/drivers/mtd/nand/nand_ecc.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/mtd/nand/nand_ecc.c	Fri Mar 29 14:49:34 2002
@@ -4,7 +4,7 @@
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
  *                     Toshiba America Electronics Components, Inc.
  *
- * $Id: nand_ecc.c,v 1.6 2001/06/28 10:52:26 dwmw2 Exp $
+ * $Id: nand_ecc.c,v 1.7 2002/03/21 14:13:50 dwmw2 Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -209,3 +209,5 @@
 EXPORT_SYMBOL(nand_correct_data);
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
+MODULE_DESCRIPTION("Generic NAND ECC support");
diff -urN linux-2.4.19-pre4/drivers/mtd/nftlcore.c linux-2.4.19-pre5/drivers/mtd/nftlcore.c
--- linux-2.4.19-pre4/drivers/mtd/nftlcore.c	Thu Oct 25 13:58:35 2001
+++ linux-2.4.19-pre5/drivers/mtd/nftlcore.c	Fri Mar 29 14:49:34 2002
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.82 2001/10/02 15:05:11 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.85 2001/11/20 11:42:33 dwmw2 Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -77,6 +77,14 @@
 	sizes:		nftl_sizes,     /* block sizes */
 };
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#else
+#define BLK_INC_USE_COUNT do {} while(0)
+#define BLK_DEC_USE_COUNT do {} while(0)
+#endif
+
 struct NFTLrecord *NFTLs[MAX_NFTLS];
 
 static void NFTL_setup(struct mtd_info *mtd)
@@ -805,9 +813,12 @@
 	case BLKGETSIZE:   /* Return device size */
 		return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
                                 (unsigned long *) arg);
+
+#ifdef BLKGETSIZE64
 	case BLKGETSIZE64:
 		return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
                                 (u64 *)arg);
+#endif
 
 	case BLKFLSBUF:
 		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
@@ -984,8 +995,11 @@
 #endif /* !CONFIG_NFTL_RW */
 
 	thisNFTL->usecount++;
-	if (!get_mtd_device(thisNFTL->mtd, -1))
-		return /* -E'SBUGGEREDOFF */ -ENXIO;
+	BLK_INC_USE_COUNT;
+	if (!get_mtd_device(thisNFTL->mtd, -1)) {
+		BLK_DEC_USE_COUNT;
+		return -ENXIO;
+	}
 
 	return 0;
 }
@@ -998,11 +1012,10 @@
 
 	DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
 
-	invalidate_device(inode->i_rdev, 1);
-
 	if (thisNFTL->mtd->sync)
 		thisNFTL->mtd->sync(thisNFTL->mtd);
 	thisNFTL->usecount--;
+	BLK_DEC_USE_COUNT;
 
 	put_mtd_device(thisNFTL->mtd);
 
@@ -1020,7 +1033,9 @@
 #else
 static struct block_device_operations nftl_fops = 
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
 	owner:		THIS_MODULE,
+#endif
 	open:		nftl_open,
 	release:	nftl_release,
 	ioctl: 		nftl_ioctl
@@ -1047,7 +1062,7 @@
 	int i;
 
 #ifdef PRERELEASE 
-	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev);
+	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.85 $, nftlmount.c %s\n", nftlmountrev);
 #endif
 
 	if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
diff -urN linux-2.4.19-pre4/drivers/net/3c503.c linux-2.4.19-pre5/drivers/net/3c503.c
--- linux-2.4.19-pre4/drivers/net/3c503.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre5/drivers/net/3c503.c	Fri Mar 29 14:49:35 2002
@@ -692,9 +692,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
-MODULE_PARM_DESC(io, "EtherLink II I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink II IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr, "EtherLink II tranceiver(s) (0=internal, 1=external)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_PARM_DESC(xcvr, "tranceiver(s) (0=internal, 1=external)");
+MODULE_DESCRIPTION("3Com ISA EtherLink II, II/16 (3c503, 3c503/16) driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -742,7 +744,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.19-pre4/drivers/net/Config.in linux-2.4.19-pre5/drivers/net/Config.in
--- linux-2.4.19-pre4/drivers/net/Config.in	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/Config.in	Fri Mar 29 14:49:35 2002
@@ -289,7 +289,7 @@
       dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
    fi
    if [ ! "$CONFIG_ATM" = "n" ]; then
-      dep_tristate '  PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP
+      dep_tristate '  PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP $CONFIG_EXPERIMENTAL
    fi
 fi
 
diff -urN linux-2.4.19-pre4/drivers/net/Makefile linux-2.4.19-pre5/drivers/net/Makefile
--- linux-2.4.19-pre4/drivers/net/Makefile	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/Makefile	Fri Mar 29 14:49:35 2002
@@ -156,7 +156,6 @@
 obj-$(CONFIG_SUN3LANCE) += sun3lance.o
 obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
-obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
 obj-$(CONFIG_AT1700) += at1700.o
 obj-$(CONFIG_FMV18X) += fmv18x.o
 obj-$(CONFIG_EL1) += 3c501.o
diff -urN linux-2.4.19-pre4/drivers/net/ac3200.c linux-2.4.19-pre5/drivers/net/ac3200.c
--- linux-2.4.19-pre4/drivers/net/ac3200.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/ac3200.c	Fri Mar 29 14:49:35 2002
@@ -346,9 +346,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
-MODULE_PARM_DESC(io, "ac3200 I/O base adress(es)");
-MODULE_PARM_DESC(irq, "ac3200 IRQ number(s)");
-MODULE_PARM_DESC(mem, "ac3200 Memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base adress(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "Memory base address(es)");
+MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
@@ -395,7 +397,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.19-pre4/drivers/net/acenic.c linux-2.4.19-pre5/drivers/net/acenic.c
--- linux-2.4.19-pre4/drivers/net/acenic.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/acenic.c	Fri Mar 29 14:49:35 2002
@@ -2,7 +2,7 @@
  * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card
  *           and other Tigon based cards.
  *
- * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
+ * Copyright 1998-2002 by Jes Sorensen, <jes@trained-monkey.org>.
  *
  * Thanks to Alteon and 3Com for providing hardware and documentation
  * enabling me to write this driver.
@@ -30,6 +30,7 @@
  *   Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the
  *                              driver under Linux/Sparc64
  *   Matt Domsch <Matt_Domsch@dell.com>: Detect Alteon 1000baseT cards
+ *                                       ETHTOOL_GDRVINFO support
  *   Chip Salzenberg <chip@valinux.com>: Fix race condition between tx
  *                                       handler and close() cleanup.
  *   Ken Aaker <kdaaker@rchland.vnet.ibm.com>: Correct check for whether
@@ -64,7 +65,10 @@
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/sockios.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #include <linux/if_vlan.h>
+#endif
 
 #ifdef SIOCETHTOOL
 #include <linux/ethtool.h>
@@ -84,8 +88,10 @@
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
 #define ACE_IS_TIGON_I(ap)	0
+#define ACE_TX_RING_ENTRIES(ap)	MAX_TX_RING_ENTRIES
 #else
 #define ACE_IS_TIGON_I(ap)	(ap->version == 1)
+#define ACE_TX_RING_ENTRIES(ap)	ap->tx_ring_entries
 #endif
 
 #ifndef PCI_VENDOR_ID_ALTEON
@@ -317,9 +323,11 @@
 
 #if (defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)) && \
 	defined(NETIF_F_HW_VLAN_RX)
-#define ACENIC_DO_VLAN	1
+#define ACENIC_DO_VLAN		1
+#define ACE_RCB_VLAN_FLAG	RCB_FLG_VLAN_ASSIST
 #else
-#define ACENIC_DO_VLAN	0
+#define ACENIC_DO_VLAN		0
+#define ACE_RCB_VLAN_FLAG	0
 #endif
 
 #include "acenic.h"
@@ -560,7 +568,7 @@
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static char version[] __initdata = 
-  "acenic.c: v0.85 11/08/2001  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.89 03/15/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -627,7 +635,6 @@
 		ap = dev->priv;
 		ap->pdev = pdev;
 
-		dev->irq = pdev->irq;
 		dev->open = &ace_open;
 		dev->hard_start_xmit = &ace_start_xmit;
 		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
@@ -737,9 +744,9 @@
 		ap->name [sizeof (ap->name) - 1] = '\0';
 		printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
 #ifdef __sparc__
-		printk("irq %s\n", __irq_itoa(dev->irq));
+		printk("irq %s\n", __irq_itoa(pdev->irq));
 #else
-		printk("irq %i\n", dev->irq);
+		printk("irq %i\n", pdev->irq);
 #endif
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
@@ -972,6 +979,13 @@
 				    ap->evt_ring_dma);
 		ap->evt_ring = NULL;
 	}
+	if (ap->tx_ring != NULL && !ACE_IS_TIGON_I(ap)) {
+		size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
+		pci_free_consistent(ap->pdev, size, ap->tx_ring,
+				    ap->tx_ring_dma);
+	}
+	ap->tx_ring = NULL;
+
 	if (ap->evt_prd != NULL) {
 		pci_free_consistent(ap->pdev, sizeof(u32),
 				    (void *)ap->evt_prd, ap->evt_prd_dma);
@@ -1018,12 +1032,19 @@
 	if (ap->evt_ring == NULL)
 		goto fail;
 
-	size = (sizeof(struct tx_desc) * TX_RING_ENTRIES);
+	/*
+	 * Only allocate a host TX ring for the Tigon II, the Tigon I
+	 * has to use PCI registers for this ;-(
+	 */
+	if (!ACE_IS_TIGON_I(ap)) {
+		size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
 
-	ap->tx_ring = pci_alloc_consistent(ap->pdev, size, &ap->tx_ring_dma);
+		ap->tx_ring = pci_alloc_consistent(ap->pdev, size,
+						   &ap->tx_ring_dma);
 
-	if (ap->tx_ring == NULL)
-		goto fail;
+		if (ap->tx_ring == NULL)
+			goto fail;
+	}
 
 	ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
 					   &ap->evt_prd_dma);
@@ -1098,6 +1119,7 @@
 	struct ace_private *ap;
 	struct ace_regs *regs;
 	struct ace_info *info = NULL;
+	struct pci_dev *pdev;
 	unsigned long myjif;
 	u64 tmp_ptr;
 	u32 tig_ver, mac1, mac2, tmp, pci_state;
@@ -1156,6 +1178,7 @@
 		       tigonFwReleaseFix);
 		writel(0, &regs->LocalCtrl);
 		ap->version = 1;
+		ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES;
 		break;
 #endif
 	case 6:
@@ -1171,6 +1194,7 @@
 		writel(SRAM_BANK_512K, &regs->LocalCtrl);
 		writel(SYNC_SRAM_TIMING, &regs->MiscCfg);
 		ap->version = 2;
+		ap->tx_ring_entries = MAX_TX_RING_ENTRIES;
 		break;
 	default:
 		printk(KERN_WARNING "  Unsupported Tigon version detected "
@@ -1236,7 +1260,8 @@
 	 * Ie. having two NICs in the machine, one will have the cache
 	 * line set at boot time, the other will not.
 	 */
-	pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache_size);
+	pdev = ap->pdev;
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_size);
 	cache_size <<= 2;
 	if (cache_size != SMP_CACHE_BYTES) {
 		printk(KERN_INFO "  PCI cache line size set incorrectly "
@@ -1245,7 +1270,7 @@
 			printk("expecting %i\n", SMP_CACHE_BYTES);
 		else {
 			printk("correcting to %i\n", SMP_CACHE_BYTES);
-			pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE,
+			pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
 					      SMP_CACHE_BYTES >> 2);
 		}
 	}
@@ -1277,7 +1302,7 @@
 		    dis_pci_mem_inval[board_idx]) {
 			if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
 				ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
-				pci_write_config_word(ap->pdev, PCI_COMMAND,
+				pci_write_config_word(pdev, PCI_COMMAND,
 						      ap->pci_command);
 				printk(KERN_INFO "  Disabling PCI memory "
 				       "write and invalidate\n");
@@ -1304,7 +1329,7 @@
 				       "supported, PCI write and invalidate "
 				       "disabled\n", SMP_CACHE_BYTES);
 				ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
-				pci_write_config_word(ap->pdev, PCI_COMMAND,
+				pci_write_config_word(pdev, PCI_COMMAND,
 						      ap->pci_command);
 			}
 		}
@@ -1346,16 +1371,16 @@
 	if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) {
 		printk(KERN_INFO "  Enabling PCI Fast Back to Back\n");
 		ap->pci_command |= PCI_COMMAND_FAST_BACK;
-		pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command);
+		pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command);
 	}
 #endif
 		
 	/*
 	 * Configure DMA attributes.
 	 */
-	if (!pci_set_dma_mask(ap->pdev, 0xffffffffffffffffULL)) {
+	if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
 		ap->pci_using_dac = 1;
-	} else if (!pci_set_dma_mask(ap->pdev, 0xffffffffULL)) {
+	} else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) {
 		ap->pci_using_dac = 0;
 	} else {
 		ecode = -ENODEV;
@@ -1382,12 +1407,14 @@
 		goto init_error;
 	}
 
-	ecode = request_irq(dev->irq, ace_interrupt, SA_SHIRQ, dev->name, dev);
+	ecode = request_irq(pdev->irq, ace_interrupt, SA_SHIRQ,
+			    dev->name, dev);
 	if (ecode) {
 		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
-		       dev->name, dev->irq);
+		       dev->name, pdev->irq);
 		goto init_error;
-	}
+	} else
+		dev->irq = pdev->irq;
 
 	/*
 	 * Register the device here to be able to catch allocated
@@ -1398,7 +1425,7 @@
 
 #ifdef INDEX_DEBUG
 	spin_lock_init(&ap->debug_lock);
-	ap->last_tx = TX_RING_ENTRIES - 1;
+	ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1;
 	ap->last_std_rx = 0;
 	ap->last_mini_rx = 0;
 #endif
@@ -1439,10 +1466,8 @@
 
 	set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
 	info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
-	info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
-	info->rx_std_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+	info->rx_std_ctrl.flags =
+	  RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
 
 	memset(ap->rx_std_ring, 0,
 	       RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1457,10 +1482,8 @@
 		    (ap->rx_ring_base_dma +
 		     (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
 	info->rx_jumbo_ctrl.max_len = 0;
-	info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
-	info->rx_jumbo_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+	info->rx_jumbo_ctrl.flags =
+	  RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
 
 	memset(ap->rx_jumbo_ring, 0,
 	       RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1482,10 +1505,7 @@
 			       RX_JUMBO_RING_ENTRIES))));
 		info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
 		info->rx_mini_ctrl.flags = 
-			RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
-		info->rx_mini_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+		  RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG;
 
 		for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
 			ap->rx_mini_ring[i].flags =
@@ -1515,18 +1535,33 @@
 	*(ap->rx_ret_prd) = 0;
 
 	writel(TX_RING_BASE, &regs->WinBase);
-	memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc));
 
-	set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
+	if (ACE_IS_TIGON_I(ap)) {
+		ap->tx_ring = (struct tx_desc *)regs->Window;
+		for (i = 0; i < (TIGON_I_TX_RING_ENTRIES * 
+				 sizeof(struct tx_desc) / 4); i++) {
+			writel(0, (unsigned long)ap->tx_ring + i * 4);
+		}
 
-	info->tx_ctrl.max_len = TX_RING_ENTRIES;
-	tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING;
+		set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
+	} else {
+		memset(ap->tx_ring, 0,
+		       MAX_TX_RING_ENTRIES * sizeof(struct tx_desc));
+
+		set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
+	}
+
+	info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
+	tmp = RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
+
+	/*
+	 * The Tigon I does not like having the TX ring in host memory ;-(
+	 */
+	if (!ACE_IS_TIGON_I(ap))
+		tmp |= RCB_FLG_TX_HOST_RING;
 #if TX_COAL_INTS_ONLY
 	tmp |= RCB_FLG_COAL_INT_ONLY;
 #endif
-#if ACENIC_DO_VLAN
-	tmp |= RCB_FLG_VLAN_ASSIST;
-#endif
 	info->tx_ctrl.flags = tmp;
 
 	set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma);
@@ -1552,7 +1587,7 @@
 	ace_set_rxtx_parms(dev, 0);
 
 	if (board_idx == BOARD_IDX_OVERFLOW) {
-		printk(KERN_WARNING "%s: more then %i NICs detected, "
+		printk(KERN_WARNING "%s: more than %i NICs detected, "
 		       "ignoring module parameters!\n",
 		       dev->name, ACE_MAX_MOD_PARMS);
 	} else if (board_idx >= 0) {
@@ -2141,14 +2176,6 @@
 }
 
 
-#if ACENIC_DO_VLAN
-static int ace_vlan_rx(struct ace_private *ap, struct sk_buff *skb, u16 vlan_tag)
-{
-	return vlan_hwaccel_rx(skb, ap->vlgrp, vlan_tag);
-}
-#endif
-
-
 static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 {
 	struct ace_private *ap = dev->priv;
@@ -2234,11 +2261,9 @@
 		}
 
 		/* send it up */
-
 #if ACENIC_DO_VLAN
-		if (ap->vlgrp != NULL &&
-		    (bd_flags & BD_FLG_VLAN_TAG)) {
-			ace_vlan_rx(ap, skb, retdesc->vlan);
+		if (ap->vlgrp && (bd_flags & BD_FLG_VLAN_TAG)) {
+			vlan_hwaccel_rx(skb, ap->vlgrp, retdesc->vlan);
 		} else
 #endif
 			netif_rx(skb);
@@ -2300,7 +2325,7 @@
 			info->skb = NULL;
 		}
 
-		idx = (idx + 1) % TX_RING_ENTRIES;
+		idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 	} while (idx != txcsm);
 
 	if (netif_queue_stopped(dev))
@@ -2393,7 +2418,7 @@
 		 * update releases enough of space, otherwise we just
 		 * wait for device to make more work.
 		 */
-		if (!tx_ring_full(txcsm, ap->tx_prd))
+		if (!tx_ring_full(ap, txcsm, ap->tx_prd))
 			ace_tx_int(dev, txcsm, idx);
 	}
 
@@ -2598,7 +2623,7 @@
 	save_flags(flags);
 	cli();
 
-	for (i = 0; i < TX_RING_ENTRIES; i++) {
+	for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
 		struct sk_buff *skb;
 		dma_addr_t mapping;
 		struct tx_ring_info *info;
@@ -2608,7 +2633,13 @@
 		mapping = pci_unmap_addr(info, mapping);
 
 		if (mapping) {
-			memset(ap->tx_ring + i, 0, sizeof(struct tx_desc));
+			if (ACE_IS_TIGON_I(ap)) {
+				writel(0, &ap->tx_ring[i].addr.addrhi);
+				writel(0, &ap->tx_ring[i].addr.addrlo);
+				writel(0, &ap->tx_ring[i].flagsize);
+			} else
+				memset(ap->tx_ring + i, 0,
+				       sizeof(struct tx_desc));
 			pci_unmap_page(ap->pdev, mapping,
 				       pci_unmap_len(info, maplen),
 				       PCI_DMA_TODEVICE);
@@ -2633,6 +2664,7 @@
 	return 0;
 }
 
+
 static inline dma_addr_t
 ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
 	       struct sk_buff *tail, u32 idx)
@@ -2653,18 +2685,28 @@
 
 
 static inline void
-ace_load_tx_bd(struct tx_desc *desc, u64 addr, u32 flagsize, u32 vlan_tag)
+ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr,
+	       u32 flagsize, u32 vlan_tag)
 {
 #if !USE_TX_COAL_NOW
 	flagsize &= ~BD_FLG_COAL_NOW;
 #endif
 
-	desc->addr.addrhi = addr >> 32;
-	desc->addr.addrlo = addr;
-	desc->flagsize = flagsize;
+	if (!ACE_IS_TIGON_I(ap)) {
+		writel(addr >> 32, &desc->addr.addrhi);
+		writel(addr & 0xffffffff, &desc->addr.addrlo);
+		writel(flagsize, &desc->flagsize);
+#if ACENIC_DO_VLAN
+		writel(vlan_tag, &desc->vlanres);
+#endif
+	} else {
+		desc->addr.addrhi = addr >> 32;
+		desc->addr.addrlo = addr;
+		desc->flagsize = flagsize;
 #if ACENIC_DO_VLAN
-	desc->vlanres = vlan_tag;
+		desc->vlanres = vlan_tag;
 #endif
+	}
 }
 
 
@@ -2681,11 +2723,10 @@
 	if (early_stop_netif_stop_queue(dev))
  		return 1;
 
-
 restart:
 	idx = ap->tx_prd;
 
-	if (tx_ring_full(ap->tx_ret_csm, idx))
+	if (tx_ring_full(ap, ap->tx_ret_csm, idx))
 		goto overflow;
 
 #if MAX_SKB_FRAGS
@@ -2706,13 +2747,13 @@
 		}
 #endif
 		desc = ap->tx_ring + idx;
-		idx = (idx + 1) % TX_RING_ENTRIES;
+		idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 
 		/* Look at ace_tx_int for explanations. */
-		if (tx_ring_full(ap->tx_ret_csm, idx))
+		if (tx_ring_full(ap, ap->tx_ret_csm, idx))
 			flagsize |= BD_FLG_COAL_NOW;
 
-		ace_load_tx_bd(desc, mapping, flagsize, vlan_tag);
+		ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag);
 	}
 #if MAX_SKB_FRAGS
 	else {
@@ -2731,9 +2772,9 @@
 		}
 #endif
 
-		ace_load_tx_bd(ap->tx_ring + idx, mapping, flagsize, vlan_tag);
+		ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize, vlan_tag);
 
-		idx = (idx + 1) % TX_RING_ENTRIES;
+		idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 
 		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2750,11 +2791,11 @@
 			flagsize = (frag->size << 16);
 			if (skb->ip_summed == CHECKSUM_HW)
 				flagsize |= BD_FLG_TCP_UDP_SUM;
-			idx = (idx + 1) % TX_RING_ENTRIES;
+			idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 
 			if (i == skb_shinfo(skb)->nr_frags - 1) {
 				flagsize |= BD_FLG_END;
-				if (tx_ring_full(ap->tx_ret_csm, idx))
+				if (tx_ring_full(ap, ap->tx_ret_csm, idx))
 					flagsize |= BD_FLG_COAL_NOW;
 
 				/*
@@ -2767,7 +2808,7 @@
 			}
 			pci_unmap_addr_set(info, mapping, mapping);
 			pci_unmap_len_set(info, maplen, frag->size);
-			ace_load_tx_bd(desc, mapping, flagsize, vlan_tag);
+			ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag);
 		}
 	}
 #endif
@@ -2785,7 +2826,7 @@
 		 * serialized, this is the only situation we have to
 		 * re-test.
 		 */
-		if (!tx_ring_full(ap->tx_ret_csm, idx))
+		if (!tx_ring_full(ap, ap->tx_ret_csm, idx))
 			netif_wake_queue(dev);
 	}
 
@@ -2864,8 +2905,8 @@
 		return -EOPNOTSUPP;
 	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
 		return -EFAULT;
-
-	if (ecmd.cmd == ETHTOOL_GSET) {
+	switch (ecmd.cmd) {
+	case ETHTOOL_GSET:
 		ecmd.supported =
 			(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
 			 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
@@ -2913,7 +2954,8 @@
 		if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
 			return -EFAULT;
 		return 0;
-	} else if (ecmd.cmd == ETHTOOL_SSET) {
+
+	case ETHTOOL_SSET:
 		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
@@ -2970,7 +3012,24 @@
 			ace_issue_cmd(regs, &cmd);
 		}
 		return 0;
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "acenic", sizeof(info.driver) - 1);
+		sprintf(info.fw_version, "%i.%i.%i", 
+			 tigonFwReleaseMajor, tigonFwReleaseMinor,
+			 tigonFwReleaseFix);
+		strncpy(info.version, version, sizeof(info.version) - 1);
+		if (ap && ap->pdev)
+			strcpy(info.bus_info, ap->pdev->slot_name);
+		if (copy_to_user(ifr->ifr_data, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	default:
+		break;
 	}
+	
 #endif
 
 	return -EOPNOTSUPP;
diff -urN linux-2.4.19-pre4/drivers/net/acenic.h linux-2.4.19-pre5/drivers/net/acenic.h
--- linux-2.4.19-pre4/drivers/net/acenic.h	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/acenic.h	Fri Mar 29 14:49:35 2002
@@ -446,11 +446,12 @@
 
 
 /*
- * TX ring
+ * TX ring - maximum TX ring entries for Tigon I's is 128
  */
-#define TX_RING_ENTRIES	256	
-#define TX_RING_SIZE	(TX_RING_ENTRIES * sizeof(struct tx_desc))
-#define TX_RING_BASE	0x3800
+#define MAX_TX_RING_ENTRIES	256
+#define TIGON_I_TX_RING_ENTRIES	128
+#define TX_RING_SIZE		(MAX_TX_RING_ENTRIES * sizeof(struct tx_desc))
+#define TX_RING_BASE		0x3800
 
 struct tx_desc{
         aceaddr	addr;
@@ -617,7 +618,7 @@
  */
 struct ace_skb
 {
-	struct tx_ring_info	tx_skbuff[TX_RING_ENTRIES];
+	struct tx_ring_info	tx_skbuff[MAX_TX_RING_ENTRIES];
 	struct ring_info	rx_std_skbuff[RX_STD_RING_ENTRIES];
 	struct ring_info	rx_mini_skbuff[RX_MINI_RING_ENTRIES];
 	struct ring_info	rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES];
@@ -641,10 +642,6 @@
 	struct ace_skb		*skb;
 	dma_addr_t		info_dma;	/* 32/64 bit */
 
-#if ACENIC_DO_VLAN
-	struct vlan_group	*vlgrp;
-#endif
-
 	int			version, link;
 	int			promisc, mcast_all;
 
@@ -654,7 +651,7 @@
 	struct tx_desc		*tx_ring;
 	u32			tx_prd;
 	volatile u32		tx_ret_csm;
-	struct timer_list	timer;
+	int			tx_ring_entries;
 
 	/*
 	 * RX elements
@@ -673,6 +670,10 @@
 	struct rx_desc		*rx_mini_ring;
 	struct rx_desc		*rx_return_ring;
 
+#if ACENIC_DO_VLAN
+	struct vlan_group	*vlgrp;
+#endif
+
 	int			tasklet_pending, jumbo;
 	struct tasklet_struct	ace_tasklet;
 
@@ -705,17 +706,17 @@
 
 #define TX_RESERVED	MAX_SKB_FRAGS
 
-static inline int tx_space (u32 csm, u32 prd)
+static inline int tx_space (struct ace_private *ap, u32 csm, u32 prd)
 {
-	return (csm - prd - 1) & (TX_RING_ENTRIES - 1);
+	return (csm - prd - 1) & (ACE_TX_RING_ENTRIES(ap) - 1);
 }
 
-#define tx_free(ap) 		tx_space((ap)->tx_ret_csm, (ap)->tx_prd)
+#define tx_free(ap) 		tx_space((ap)->tx_ret_csm, (ap)->tx_prd, ap)
 
 #if MAX_SKB_FRAGS
-#define tx_ring_full(csm, prd)	(tx_space(csm, prd) <= TX_RESERVED)
+#define tx_ring_full(ap, csm, prd)	(tx_space(ap, csm, prd) <= TX_RESERVED)
 #else
-#define tx_ring_full		0
+#define tx_ring_full			0
 #endif
 
 
@@ -724,7 +725,7 @@
 	u64 baddr = (u64) addr;
 	aa->addrlo = baddr & 0xffffffff;
 	aa->addrhi = baddr >> 32;
-	mb();
+	wmb();
 }
 
 
diff -urN linux-2.4.19-pre4/drivers/net/arlan.c linux-2.4.19-pre5/drivers/net/arlan.c
--- linux-2.4.19-pre4/drivers/net/arlan.c	Fri Nov  9 13:45:35 2001
+++ linux-2.4.19-pre5/drivers/net/arlan.c	Fri Mar 29 14:49:36 2002
@@ -677,7 +677,7 @@
 		arlan_retransmit_now(dev);
 	}
 	if (!registrationBad(dev) &&
-		priv->tx_done_delayed < jiffies &&
+		time_after(jiffies, priv->tx_done_delayed) &&
 		priv->tx_done_delayed != 0)
 	{
 		TXLAST(dev).offset = 0;
diff -urN linux-2.4.19-pre4/drivers/net/at1700.c linux-2.4.19-pre5/drivers/net/at1700.c
--- linux-2.4.19-pre4/drivers/net/at1700.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/at1700.c	Fri Mar 29 14:49:36 2002
@@ -836,6 +836,7 @@
 			 i++, mclist = mclist->next)
 			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26,
 					mc_filter);
+		outb(0x02, ioaddr + RX_MODE);	/* Use normal mode. */
 	}
 
 	save_flags(flags);
diff -urN linux-2.4.19-pre4/drivers/net/bmac.c linux-2.4.19-pre5/drivers/net/bmac.c
--- linux-2.4.19-pre4/drivers/net/bmac.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/bmac.c	Fri Mar 29 14:49:36 2002
@@ -17,6 +17,7 @@
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
diff -urN linux-2.4.19-pre4/drivers/net/bonding.c linux-2.4.19-pre5/drivers/net/bonding.c
--- linux-2.4.19-pre4/drivers/net/bonding.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.19-pre5/drivers/net/bonding.c	Fri Mar 29 14:49:36 2002
@@ -161,6 +161,16 @@
  *     - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr 
  *     - Handle hot swap ethernet interface deregistration events to remove
  *       kernel oops following hot swap of enslaved interface
+ *
+ * 2002/1/2 - Chad N. Tindel <ctindel at ieee dot org>
+ *     - Restore original slave flags at release time.
+ *
+ * 2002/02/18 - Erik Habbinga <erik_habbinga at hp dot com>
+ *     - bond_release(): calling kfree on our_slave after call to
+ *       bond_restore_slave_flags, not before
+ *     - bond_enslave(): saving slave flags into original_flags before
+ *       call to netdev_set_master, so the IFF_SLAVE flag doesn't end
+ *       up in original_flags
  */
 
 #include <linux/config.h>
@@ -208,11 +218,8 @@
 #define MII_ENDOF_NWAY	0x20
 
 #undef  MII_LINK_READY
-/*#define MII_LINK_READY	(MII_LINK_UP | MII_ENDOF_NWAY)*/
 #define MII_LINK_READY	(MII_LINK_UP)
 
-#define MAX_BOND_ADDR 256
-
 #ifndef BOND_LINK_ARP_INTERV
 #define BOND_LINK_ARP_INTERV	0
 #endif
@@ -223,7 +230,7 @@
 static u32 my_ip = 0;
 char *arp_target_hw_addr = NULL;
 
-static int max_bonds	= MAX_BONDS;
+static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
 static int miimon	= BOND_LINK_MON_INTERV;
 static int mode		= BOND_MODE_ROUNDROBIN;
 static int updelay	= 0;
@@ -234,7 +241,7 @@
 static struct bonding *these_bonds =  NULL;
 static struct net_device *dev_bonds = NULL;
 
-MODULE_PARM(max_bonds, "1-" __MODULE_STRING(INT_MAX) "i");
+MODULE_PARM(max_bonds, "i");
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
 MODULE_PARM(miimon, "i");
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
@@ -260,6 +267,7 @@
 static void bond_mii_monitor(struct net_device *dev);
 static void bond_arp_monitor(struct net_device *dev);
 static int bond_event(struct notifier_block *this, unsigned long event, void *ptr);
+static void bond_restore_slave_flags(slave_t *slave);
 static void bond_set_slave_inactive_flags(slave_t *slave);
 static void bond_set_slave_active_flags(slave_t *slave);
 static int bond_enslave(struct net_device *master, struct net_device *slave);
@@ -282,6 +290,11 @@
 #define IS_UP(dev)	((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \
 			(netif_running(dev) && netif_carrier_ok(dev)))
 
+static void bond_restore_slave_flags(slave_t *slave)
+{
+	slave->dev->flags = slave->original_flags;
+}
+
 static void bond_set_slave_inactive_flags(slave_t *slave)
 {
 	slave->state = BOND_STATE_BACKUP;
@@ -513,6 +526,8 @@
 	}
 	memset(new_slave, 0, sizeof(slave_t));
 
+	/* save flags before call to netdev_set_master */
+	new_slave->original_flags = slave_dev->flags;
 	err = netdev_set_master(slave_dev, master_dev);
 
 	if (err) {
@@ -838,7 +853,6 @@
 			} else {
 				printk(".\n");
 			}
-			kfree(our_slave);
 
 			/* release the slave from its bond */
 			 
@@ -854,6 +868,9 @@
 					dev_close(slave);
 			}
 
+			bond_restore_slave_flags(our_slave);
+			kfree(our_slave);
+
 			if (bond->current_slave == NULL) {
 				printk(KERN_INFO
 					"%s: now running without any active interface !\n",
@@ -2038,6 +2055,13 @@
 	/* Find a name for this unit */
 	static struct net_device *dev_bond = NULL;
 
+	if (max_bonds < 1 || max_bonds > INT_MAX) {
+		printk(KERN_WARNING 
+		       "bonding_init(): max_bonds (%d) not in range %d-%d, "
+		       "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)",
+		       max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
+		max_bonds = BOND_DEFAULT_MAX_BONDS;
+	}
 	dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), 
 					GFP_KERNEL);
 	if (dev_bond == NULL) {
diff -urN linux-2.4.19-pre4/drivers/net/de4x5.c linux-2.4.19-pre5/drivers/net/de4x5.c
--- linux-2.4.19-pre4/drivers/net/de4x5.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/de4x5.c	Fri Mar 29 14:49:36 2002
@@ -657,15 +657,15 @@
 ** DESC_ALIGN. ALIGN aligns the start address of the private memory area
 ** and hence the RX descriptor ring's first entry. 
 */
-#define ALIGN4      ((u_long)4 - 1)     /* 1 longword align */
-#define ALIGN8      ((u_long)8 - 1)     /* 2 longword align */
-#define ALIGN16     ((u_long)16 - 1)    /* 4 longword align */
-#define ALIGN32     ((u_long)32 - 1)    /* 8 longword align */
-#define ALIGN64     ((u_long)64 - 1)    /* 16 longword align */
-#define ALIGN128    ((u_long)128 - 1)   /* 32 longword align */
+#define DE4X5_ALIGN4      ((u_long)4 - 1)     /* 1 longword align */
+#define DE4X5_ALIGN8      ((u_long)8 - 1)     /* 2 longword align */
+#define DE4X5_ALIGN16     ((u_long)16 - 1)    /* 4 longword align */
+#define DE4X5_ALIGN32     ((u_long)32 - 1)    /* 8 longword align */
+#define DE4X5_ALIGN64     ((u_long)64 - 1)    /* 16 longword align */
+#define DE4X5_ALIGN128    ((u_long)128 - 1)   /* 32 longword align */
 
-#define ALIGN         ALIGN32           /* Keep the DC21040 happy... */
-#define CACHE_ALIGN   CAL_16LONG
+#define DE4X5_ALIGN         DE4X5_ALIGN32           /* Keep the DC21040 happy... */
+#define DE4X5_CACHE_ALIGN   CAL_16LONG
 #define DESC_SKIP_LEN DSL_0             /* Must agree with DESC_ALIGN */
 /*#define DESC_ALIGN    u32 dummy[4];  / * Must agree with DESC_SKIP_LEN */
 #define DESC_ALIGN
@@ -1202,7 +1202,7 @@
 	** Reserve a section of kernel memory for the adapter
 	** private area and the TX/RX descriptor rings.
 	*/
-	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, 
+	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + DE4X5_ALIGN, 
 				     GFP_KERNEL);
 	if (dev->priv == NULL) {
 	    return -ENOMEM;
@@ -1212,7 +1212,7 @@
 	** Align to a longword boundary
 	*/
 	tmp = dev->priv;
-	dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
+	dev->priv = (void *)(((u_long)dev->priv + DE4X5_ALIGN) & ~DE4X5_ALIGN);
 	lp = (struct de4x5_private *)dev->priv;
 	memset(dev->priv, 0, sizeof(struct de4x5_private));
 	lp->bus = bus.bus;
@@ -1248,7 +1248,7 @@
 
 	lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc);
 #if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY)
-	lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + ALIGN;
+	lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN;
 #endif
 	lp->rx_ring = pci_alloc_consistent(pdev, lp->dma_size, &lp->dma_rings);
 	if (lp->rx_ring == NULL) {
@@ -1278,9 +1278,9 @@
 
 		dma_rx_bufs = lp->dma_rings + (NUM_RX_DESC + NUM_TX_DESC)
 		      	* sizeof(struct de4x5_desc);
-		dma_rx_bufs = (dma_rx_bufs + ALIGN) & ~ALIGN;
+		dma_rx_bufs = (dma_rx_bufs + DE4X5_ALIGN) & ~DE4X5_ALIGN;
 		lp->rx_bufs = (char *)(((long)(lp->rx_ring + NUM_RX_DESC
-		      	+ NUM_TX_DESC) + ALIGN) & ~ALIGN);
+		      	+ NUM_TX_DESC) + DE4X5_ALIGN) & ~DE4X5_ALIGN);
 		for (i=0; i<NUM_RX_DESC; i++) {
 	    		lp->rx_ring[i].status = 0;
 	    		lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
@@ -1489,7 +1489,7 @@
     ** Fasternet chips and 4 longwords for all others: DMA errors result
     ** without these values. Cache align 16 long.
     */
-    bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
+    bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | DE4X5_CACHE_ALIGN;
     bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
     outl(bmr, DE4X5_BMR);
 
@@ -3638,12 +3638,12 @@
     struct sk_buff *ret;
     u_long i=0, tmp;
 
-    p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
+    p = dev_alloc_skb(IEEE802_3_SZ + DE4X5_ALIGN + 2);
     if (!p) return NULL;
 
     p->dev = dev;
     tmp = virt_to_bus(p->data);
-    i = ((tmp + ALIGN) & ~ALIGN) - tmp;
+    i = ((tmp + DE4X5_ALIGN) & ~DE4X5_ALIGN) - tmp;
     skb_reserve(p, i);
     lp->rx_ring[index].buf = cpu_to_le32(tmp + i);
 
diff -urN linux-2.4.19-pre4/drivers/net/de620.c linux-2.4.19-pre5/drivers/net/de620.c
--- linux-2.4.19-pre4/drivers/net/de620.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/de620.c	Fri Mar 29 14:49:36 2002
@@ -449,11 +449,17 @@
 		return ret;
 	}
 
-	if (adapter_init(dev))
-		return -EIO;
+	if (adapter_init(dev)) {
+		ret = -EIO;
+		goto out_free_irq;
+	}
 
 	netif_start_queue(dev);
 	return 0;
+
+out_free_irq:
+	free_irq(dev->irq, dev);
+	return ret;
 }
 
 /************************************************
@@ -850,7 +856,10 @@
 		return -EBUSY;
 	}
 #endif
-	request_region(dev->base_addr, 3, "de620");
+	if (!request_region(dev->base_addr, 3, "de620")) {
+		printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr);
+		return -EBUSY;
+	}
 
 	/* else, got it! */
 	printk(", Ethernet Address: %2.2X",
diff -urN linux-2.4.19-pre4/drivers/net/dl2k.c linux-2.4.19-pre5/drivers/net/dl2k.c
--- linux-2.4.19-pre4/drivers/net/dl2k.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/dl2k.c	Fri Mar 29 14:49:37 2002
@@ -1,6 +1,6 @@
 /*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
 /*
-    Copyright (c) 2001 by D-Link Corporation
+    Copyright (c) 2001,2002 by D-Link Corporation
     Written by Edward Peng.<edward_peng@dlink.com.tw>
     Created 03-May-2001, base on Linux' sundance.c.
 
@@ -27,12 +27,14 @@
 				Added tx_coalesce paramter.
     1.07	2002/01/03	Fixed miscount of RX frame error.
     1.08	2002/01/17	Fixed the multicast bug.
+    1.09	2002/03/07	Move rx-poll-now to re-fill loop.	
+    				Added rio_timer() to watch rx buffers. 
  */
 
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n";
+    KERN_INFO "D-Link DL2000-based linux driver v1.09 2002/03/07\n";
 
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
@@ -42,9 +44,10 @@
 static int tx_flow[MAX_UNITS];
 static int rx_flow[MAX_UNITS];
 static int copy_thresh;
-static int rx_coalesce = DEFAULT_RXC;
-static int rx_timeout = DEFAULT_RXT;	
-static int tx_coalesce = DEFAULT_TXC;	
+static int rx_coalesce;			/* Rx frame count each interrupt */
+static int rx_timeout; 			/* Rx DMA wait time in 64ns increments */
+static int tx_coalesce = DEFAULT_TXC; 	/* HW xmit count each TxComplete [1-8] */
+
 
 MODULE_AUTHOR ("Edward Peng");
 MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
@@ -71,6 +74,7 @@
 static int multicast_filter_limit = 0x40;
 
 static int rio_open (struct net_device *dev);
+static void rio_timer (unsigned long data);
 static void tx_timeout (struct net_device *dev);
 static void alloc_list (struct net_device *dev);
 static int start_xmit (struct sk_buff *skb, struct net_device *dev);
@@ -146,6 +150,7 @@
 	np->chip_id = chip_idx;
 	np->pdev = pdev;
 	spin_lock_init (&np->lock);
+	spin_lock_init (&np->rx_lock);
 
 	/* Parse manual configuration */
 	np->an_enable = 1;
@@ -260,6 +265,7 @@
 			np->an_enable = 1;
 		mii_set_media (dev);
 	}
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
 
 	/* Reset all logic functions */
 	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
@@ -340,7 +346,7 @@
 	}
 
 	/* Check CRC */
- 	crc = ~ether_crc_le(256-4, sromdata);
+ 	crc = ~ether_crc_le(256 - 4, sromdata);
 	if (psrom->crc != crc) {
 		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
 		return -1;
@@ -421,8 +427,10 @@
 			ioaddr + RxDMAIntCtrl);
 	}
 	/* Set RIO to poll every N*320nsec. */
-	writeb (0xff, ioaddr + RxDMAPollPeriod);
+	writeb (0x20, ioaddr + RxDMAPollPeriod);
 	writeb (0xff, ioaddr + TxDMAPollPeriod);
+	writeb (0x30, ioaddr + RxDMABurstThresh);
+	writeb (0x30, ioaddr + RxDMAUrgentThresh);
 	netif_start_queue (dev);
 	writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
 	/* VLAN supported */
@@ -445,9 +453,59 @@
 
 	/* clear statistics */
 	get_stats (dev);
+	init_timer (&np->timer);
+	np->timer.expires = jiffies + 1*HZ;
+	np->timer.data = (unsigned long) dev;
+	np->timer.function = &rio_timer;
+	add_timer (&np->timer);
 	return 0;
 }
+static void 
+rio_timer (unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	unsigned int entry;
+	int next_tick = 1*HZ;
+	unsigned long flags;
 
+	/* Recover rx ring exhausted error */
+	if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
+		printk(KERN_INFO "Try to recover rx ring exhausted...\n");
+		spin_lock_irqsave(&np->rx_lock, flags);
+		/* Re-allocate skbuffs to fill the descriptor ring */
+		for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+			struct sk_buff *skb;
+			entry = np->old_rx % RX_RING_SIZE;
+			/* Dropped packets don't need to re-allocate */
+			if (np->rx_skbuff[entry] == NULL) {
+				skb = dev_alloc_skb (np->rx_buf_sz);
+				if (skb == NULL) {
+					np->rx_ring[entry].fraginfo = 0;
+					printk (KERN_INFO
+						"%s: Still unable to re-allocate Rx skbuff.#%d\n",
+						dev->name, entry);
+					break;
+				}
+				np->rx_skbuff[entry] = skb;
+				skb->dev = dev;
+				/* 16 byte align the IP header */
+				skb_reserve (skb, 2);
+				np->rx_ring[entry].fraginfo =
+				    cpu_to_le64 (pci_map_single
+					 (np->pdev, skb->tail, np->rx_buf_sz,
+					  PCI_DMA_FROMDEVICE));
+			}
+			np->rx_ring[entry].fraginfo |=
+			    cpu_to_le64 (np->rx_buf_sz) << 48;
+			np->rx_ring[entry].status = 0;
+		} /* end for */
+		spin_unlock_irqrestore (&np->rx_lock, flags);
+	} /* end if */
+	np->timer.expires = jiffies + next_tick;
+	add_timer(&np->timer);
+}
+	
 static void
 tx_timeout (struct net_device *dev)
 {
@@ -499,16 +557,14 @@
 		np->tx_ring[i].status = cpu_to_le64 (TFDDone);
 		np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
 					      ((i+1)%TX_RING_SIZE) *
-					      sizeof (struct
-					      netdev_desc));
+					      sizeof (struct netdev_desc));
 	}
 
 	/* Initialize Rx descriptors */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
 						((i + 1) % RX_RING_SIZE) *
-						sizeof (struct
-						netdev_desc));
+						sizeof (struct netdev_desc));
 		np->rx_ring[i].status = 0;
 		np->rx_ring[i].fraginfo = 0;
 		np->rx_skbuff[i] = 0;
@@ -529,8 +585,8 @@
 		skb_reserve (skb, 2);	/* 16 byte align the IP header. */
 		/* Rubicon now supports 40 bits of addressing space. */
 		np->rx_ring[i].fraginfo =
-		    cpu_to_le64 (pci_map_single
-				 (np->pdev, skb->tail, np->rx_buf_sz,
+		    cpu_to_le64 ( pci_map_single (
+			 	  np->pdev, skb->tail, np->rx_buf_sz,
 				  PCI_DMA_FROMDEVICE));
 		np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
 	}
@@ -773,6 +829,8 @@
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
 	int rx_shift;
+
+	spin_lock (&np->rx_lock);
 	if (np->old_rx > RX_RING_SIZE) {
 		rx_shift = RX_RING_SIZE;
 		np->old_rx -= rx_shift;
@@ -828,12 +886,14 @@
 				skb_put (skb, pkt_len);
 			}
 			skb->protocol = eth_type_trans (skb, dev);
-#if 0
+#if 0			
 			/* Checksum done by hw, but csum value unavailable. */
-			if (!(frame_status & (TCPError | UDPError | IPError))) {
+			if (np->pci_rev_id >= 0x0c && 
+				!(frame_status & (TCPError | UDPError | IPError))) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
-			}
+			} 
 #endif
+					
 			netif_rx (skb);
 			dev->last_rx = jiffies;
 		}
@@ -849,9 +909,10 @@
 			skb = dev_alloc_skb (np->rx_buf_sz);
 			if (skb == NULL) {
 				np->rx_ring[entry].fraginfo = 0;
-				printk (KERN_ERR
-					"%s: Allocate Rx buffer error!",
-					dev->name);
+				printk (KERN_INFO
+					"%s: receive_packet: "
+					"Unable to re-allocate Rx skbuff.#%d\n",
+					dev->name, entry);
 				break;
 			}
 			np->rx_skbuff[entry] = skb;
@@ -866,13 +927,12 @@
 		np->rx_ring[entry].fraginfo |=
 		    cpu_to_le64 (np->rx_buf_sz) << 48;
 		np->rx_ring[entry].status = 0;
+		/* RxDMAPollNow */
+		writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+			dev->base_addr + DMACtrl);
 	}
-
-	/* RxDMAPollNow */
-	writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
-		dev->base_addr + DMACtrl);
-
 	DEBUG_RFD_DUMP (np, 2);
+	spin_unlock(&np->rx_lock);
 	return 0;
 }
 
@@ -1006,7 +1066,7 @@
 	
 	hash_table[0] = hash_table[1] = 0;
 	/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
-	hash_table[1] |= 0x02000000;
+	hash_table[1] |= cpu_to_le32(0x02000000);
 	if (dev->flags & IFF_PROMISC) {
 		/* Receive all frames promiscuously. */
 		rx_mode = ReceiveAllFrames;
@@ -1020,11 +1080,16 @@
 		rx_mode =
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
-				i++, mclist=mclist->next) {
+			i++, mclist=mclist->next) {
+
 			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
-			for (index=0, bit=0; bit<6; bit++, crc<<=1) {
-				if (crc & 0x80000000) index |= 1 << bit;
-			}
+
+			/* The inverted high significant 6 bits of CRC are
+			   used as an index to hashtable */
+			for (index = 0, bit = 0; bit < 6; bit++)
+				if (test_bit(31 - bit, &crc))
+					set_bit(bit, &index);
+
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
 	} else {
@@ -1094,6 +1159,7 @@
 		     np->old_rx);
 		break;
 	case SIOCDEVPRIVATE + 8:
+		printk("TX ring:\n");
 		for (i = 0; i < TX_RING_SIZE; i++) {
 			desc = &np->tx_ring[i];
 			printk
@@ -1629,7 +1695,8 @@
 	writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
 	synchronize_irq ();
 	free_irq (dev->irq, dev);
-
+	del_timer_sync (&np->timer);
+	
 	/* Free all the skbuffs in the queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].status = 0;
@@ -1679,10 +1746,10 @@
 }
 
 static struct pci_driver rio_driver = {
-	name:"dl2k",
-	id_table:rio_pci_tbl,
-	probe:rio_probe1,
-	remove:__devexit_p(rio_remove1),
+	name:		"dl2k",
+	id_table:	rio_pci_tbl,
+	probe:		rio_probe1,
+	remove:		__devexit_p(rio_remove1),
 };
 
 static int __init
diff -urN linux-2.4.19-pre4/drivers/net/dl2k.h linux-2.4.19-pre5/drivers/net/dl2k.h
--- linux-2.4.19-pre4/drivers/net/dl2k.h	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/dl2k.h	Fri Mar 29 14:49:37 2002
@@ -1,6 +1,6 @@
 /*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
 /*  
-    Copyright (c) 2001 by D-Link Corporation
+    Copyright (c) 2001, 2002 by D-Link Corporation
     Written by Edward Peng.<edward_peng@dlink.com.tw>
     Created 03-May-2001, base on Linux' sundance.c.
 
@@ -649,6 +649,7 @@
 	dma_addr_t rx_ring_dma;
 	struct pci_dev *pdev;
 	spinlock_t lock;
+	spinlock_t rx_lock;
 	struct net_device_stats stats;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
 	unsigned int speed;		/* Operating speed */
@@ -664,9 +665,11 @@
 	unsigned int tx_flow:1;		/* Tx flow control enable */
 	unsigned int rx_flow:1;		/* Rx flow control enable */
 	unsigned int phy_media:1;	/* 1: fiber, 0: copper */
+	unsigned char pci_rev_id;	/* PCI revision ID */
 	struct netdev_desc *last_tx;	/* Last Tx descriptor used. */
 	unsigned long cur_rx, old_rx;	/* Producer/consumer ring indices */
 	unsigned long cur_tx, old_tx;
+	struct timer_list timer;
 	int wake_polarity;
 	char name[256];		/* net device description */
 	u8 duplex_polarity;
diff -urN linux-2.4.19-pre4/drivers/net/e2100.c linux-2.4.19-pre5/drivers/net/e2100.c
--- linux-2.4.19-pre4/drivers/net/e2100.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/e2100.c	Fri Mar 29 14:49:37 2002
@@ -388,10 +388,12 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
-MODULE_PARM_DESC(io, "E2100 I/O base address(es)");
-MODULE_PARM_DESC(irq, "E2100 IRQ number(s)");
-MODULE_PARM_DESC(mem, " E2100 memory base address(es)");
-MODULE_PARM_DESC(xcvr, "E2100 tranceiver(s) (0=internal, 1=external)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, " memory base address(es)");
+MODULE_PARM_DESC(xcvr, "tranceiver(s) (0=internal, 1=external)");
+MODULE_DESCRIPTION("Cabletron E2100 ISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -440,7 +442,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.19-pre4/drivers/net/eepro100.c linux-2.4.19-pre5/drivers/net/eepro100.c
--- linux-2.4.19-pre4/drivers/net/eepro100.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/eepro100.c	Fri Mar 29 14:49:37 2002
@@ -64,8 +64,8 @@
 
 /* A few values that may be tweaked. */
 /* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE	32
-#define RX_RING_SIZE	32
+#define TX_RING_SIZE	64
+#define RX_RING_SIZE	64
 /* How much slots multicast filter setup may take.
    Do not descrease without changing set_rx_mode() implementaion. */
 #define TX_MULTICAST_SIZE   2
@@ -114,7 +114,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
-#include <linux/delay.h>
 
 MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
 MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver");
@@ -130,17 +129,17 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(multicast_filter_limit, "i");
-MODULE_PARM_DESC(debug, "eepro100 debug level (0-6)");
-MODULE_PARM_DESC(options, "eepro100: Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps");
-MODULE_PARM_DESC(full_duplex, "eepro100 full duplex setting(s) (1)");
-MODULE_PARM_DESC(congenb, "eepro100  Enable congestion control (1)");
-MODULE_PARM_DESC(txfifo, "eepro100 Tx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(rxfifo, "eepro100 Rx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(txdmaccount, "eepro100 Tx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rxdmaccount, "eepro100 Rx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rx_copybreak, "eepro100 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "eepro100 maximum events handled per interrupt");
-MODULE_PARM_DESC(multicast_filter_limit, "eepro100 maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(debug, "debug level (0-6)");
+MODULE_PARM_DESC(options, "Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
+MODULE_PARM_DESC(congenb, "Enable congestion control (1)");
+MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)");
+MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)");
+MODULE_PARM_DESC(txdmaccount, "Tx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rxdmaccount, "Rx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
+MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses");
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -570,6 +569,19 @@
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
+	/* save power state before pci_enable_device overwrites it */
+	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm) {
+		u16 pwr_command;
+		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
+		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+	}
+
+	if (pci_enable_device(pdev))
+		goto err_out_free_mmio_region;
+
+	pci_set_master(pdev);
+
 	if (!request_region(pci_resource_start(pdev, 1),
 			pci_resource_len(pdev, 1), "eepro100")) {
 		printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
@@ -600,18 +612,6 @@
 			   pci_resource_start(pdev, 0), irq);
 #endif
 
-	/* save power state b4 pci_enable_device overwrites it */
-	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (pm) {
-		u16 pwr_command;
-		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
-		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
-	}
-
-	if (pci_enable_device(pdev))
-		goto err_out_free_mmio_region;
-
-	pci_set_master(pdev);
 
 	if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0)
 		cards_found++;
@@ -1074,6 +1074,51 @@
 	outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
 }
 
+/*
+ * Sometimes the receiver stops making progress.  This routine knows how to
+ * get it going again, without losing packets or being otherwise nasty like
+ * a chip reset would be.  Previously the driver had a whole sequence
+ * of if RxSuspended, if it's no buffers do one thing, if it's no resources,
+ * do another, etc.  But those things don't really matter.  Separate logic
+ * in the ISR provides for allocating buffers--the other half of operation
+ * is just making sure the receiver is active.  speedo_rx_soft_reset does that.
+ * This problem with the old, more involved algorithm is shown up under
+ * ping floods on the order of 60K packets/second on a 100Mbps fdx network.
+ */
+static void
+speedo_rx_soft_reset(struct net_device *dev)
+{
+	struct speedo_private *sp = dev->priv;
+	struct RxFD *rfd;
+	long ioaddr;
+
+	ioaddr = dev->base_addr;
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	if (inb(ioaddr + SCBCmd) != 0) {
+		printk("%s: previous command stalled\n", dev->name);
+		return;
+	}
+	/*
+	* Put the hardware into a known state.
+	*/
+	outb(RxAbort, ioaddr + SCBCmd);
+
+	rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
+
+	rfd->rx_buf_addr = 0xffffffff;
+
+	wait_for_cmd_done(ioaddr + SCBCmd);
+
+	if (inb(ioaddr + SCBCmd) != 0) {
+		printk("%s: RxAbort command stalled\n", dev->name);
+		return;
+	}
+	outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+		ioaddr + SCBPointer);
+	outb(RxStart, ioaddr + SCBCmd);
+}
+
+
 /* Media monitoring and control. */
 static void speedo_timer(unsigned long data)
 {
@@ -1377,9 +1422,10 @@
 
 	/* workaround for hardware bug on 10 mbit half duplex */
 
-	if ((sp->partner==0) && (sp->chip_id==1)) {
+	if ((sp->partner == 0) && (sp->chip_id == 1)) {
 		wait_for_cmd_done(ioaddr + SCBCmd);
 		outb(0 , ioaddr + SCBCmd);
+		udelay(1);
 	}
 
 	/* Trigger the command unit resume. */
@@ -1507,82 +1553,39 @@
 		if ((status & 0xfc00) == 0)
 			break;
 
-		/* Always check if all rx buffers are allocated.  --SAW */
-		speedo_refill_rx_buffers(dev, 0);
 
 		if ((status & 0x5000) ||	/* Packet received, or Rx error. */
 			(sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
 									/* Need to gather the postponed packet. */
 			speedo_rx(dev);
 
-		if (status & 0x1000) {
-			spin_lock(&sp->lock);
-			if ((status & 0x003c) == 0x0028) {		/* No more Rx buffers. */
-				struct RxFD *rxf;
-				printk(KERN_WARNING "%s: card reports no RX buffers.\n",
-						dev->name);
-				rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-				if (rxf == NULL) {
-					if (speedo_debug > 2)
-						printk(KERN_DEBUG
-								"%s: NULL cur_rx in speedo_interrupt().\n",
-								dev->name);
-					sp->rx_ring_state |= RrNoMem|RrNoResources;
-				} else if (rxf == sp->last_rxf) {
-					if (speedo_debug > 2)
-						printk(KERN_DEBUG
-								"%s: cur_rx is last in speedo_interrupt().\n",
-								dev->name);
-					sp->rx_ring_state |= RrNoMem|RrNoResources;
-				} else
-					outb(RxResumeNoResources, ioaddr + SCBCmd);
-			} else if ((status & 0x003c) == 0x0008) { /* No resources. */
-				struct RxFD *rxf;
-				printk(KERN_WARNING "%s: card reports no resources.\n",
-						dev->name);
-				rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-				if (rxf == NULL) {
-					if (speedo_debug > 2)
-						printk(KERN_DEBUG
-								"%s: NULL cur_rx in speedo_interrupt().\n",
-								dev->name);
-					sp->rx_ring_state |= RrNoMem|RrNoResources;
-				} else if (rxf == sp->last_rxf) {
-					if (speedo_debug > 2)
-						printk(KERN_DEBUG
-								"%s: cur_rx is last in speedo_interrupt().\n",
-								dev->name);
-					sp->rx_ring_state |= RrNoMem|RrNoResources;
-				} else {
-					/* Restart the receiver. */
-					outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
-						 ioaddr + SCBPointer);
-					outb(RxStart, ioaddr + SCBCmd);
-				}
-			}
-			sp->stats.rx_errors++;
-			spin_unlock(&sp->lock);
-		}
-
-		if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) {
-			printk(KERN_WARNING
-					"%s: restart the receiver after a possible hang.\n",
-					dev->name);
-			spin_lock(&sp->lock);
-			/* Restart the receiver.
-			   I'm not sure if it's always right to restart the receiver
-			   here but I don't know another way to prevent receiver hangs.
-			   1999/12/25 SAW */
-			outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
-				 ioaddr + SCBPointer);
-			outb(RxStart, ioaddr + SCBCmd);
-			sp->rx_ring_state &= ~RrNoResources;
-			spin_unlock(&sp->lock);
+		/* Always check if all rx buffers are allocated.  --SAW */
+		speedo_refill_rx_buffers(dev, 0);
+		
+		spin_lock(&sp->lock);
+		/*
+		 * The chip may have suspended reception for various reasons.
+		 * Check for that, and re-prime it should this be the case.
+		 */
+		switch ((status >> 2) & 0xf) {
+		case 0: /* Idle */
+			break;
+		case 1:	/* Suspended */
+		case 2:	/* No resources (RxFDs) */
+		case 9:	/* Suspended with no more RBDs */
+		case 10: /* No resources due to no RBDs */
+		case 12: /* Ready with no RBDs */
+			speedo_rx_soft_reset(dev);
+			break;
+		case 3:  case 5:  case 6:  case 7:  case 8:
+		case 11:  case 13:  case 14:  case 15:
+			/* these are all reserved values */
+			break;
 		}
-
+		
+		
 		/* User interrupt, Command/Tx unit interrupt or CU not active. */
 		if (status & 0xA400) {
-			spin_lock(&sp->lock);
 			speedo_tx_buffer_gc(dev);
 			if (sp->tx_full
 				&& (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
@@ -1590,8 +1593,9 @@
 				sp->tx_full = 0;
 				netif_wake_queue(dev); /* Attention: under a spinlock.  --SAW */
 			}
-			spin_unlock(&sp->lock);
 		}
+		
+		spin_unlock(&sp->lock);
 
 		if (--boguscnt < 0) {
 			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
@@ -2205,6 +2209,8 @@
 
 	if (!netif_running(dev))
 		return 0;
+		
+	del_timer_sync(&sp->timer);
 
 	netif_device_detach(dev);
 	outl(PortPartialReset, ioaddr + SCBPort);
@@ -2237,6 +2243,8 @@
 	sp->rx_mode = -1;
 	sp->flow_ctrl = sp->partner = 0;
 	set_rx_mode(dev);
+	sp->timer.expires = RUN_AT(2*HZ);
+	add_timer(&sp->timer);
 	return 0;
 }
 #endif /* CONFIG_PM */
diff -urN linux-2.4.19-pre4/drivers/net/epic100.c linux-2.4.19-pre5/drivers/net/epic100.c
--- linux-2.4.19-pre4/drivers/net/epic100.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/epic100.c	Fri Mar 29 14:49:37 2002
@@ -60,11 +60,14 @@
 	LK1.1.12:
 	* fix power-up sequence
 
+	LK1.1.13:
+	* revert version 1.1.12, power-up sequence "fix"
+
 */
 
 #define DRV_NAME	"epic100"
-#define DRV_VERSION	"1.11+LK1.1.12"
-#define DRV_RELDATE	"Jan 18, 2002"
+#define DRV_VERSION	"1.11+LK1.1.13"
+#define DRV_RELDATE	"Mar 20, 2002"
 
 
 /* The user-configurable values.
@@ -678,8 +681,9 @@
 	   required by the details of which bits are reset and the transceiver
 	   wiring on the Ositech CardBus card.
 	*/
-
-	outl(0x12, ioaddr + MIICfg);
+#if 0
+	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+#endif
 	if (ep->chip_flags & MII_PWRDWN)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 
diff -urN linux-2.4.19-pre4/drivers/net/es3210.c linux-2.4.19-pre5/drivers/net/es3210.c
--- linux-2.4.19-pre4/drivers/net/es3210.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/es3210.c	Fri Mar 29 14:49:37 2002
@@ -383,9 +383,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
-MODULE_PARM_DESC(io, "ES3210 I/O base address(es)");
-MODULE_PARM_DESC(irq, "ES3210 IRQ number(s)");
-MODULE_PARM_DESC(mem, "ES3210 memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "memory base address(es)");
+MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
@@ -429,5 +431,4 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
diff -urN linux-2.4.19-pre4/drivers/net/fc/iph5526.c linux-2.4.19-pre5/drivers/net/fc/iph5526.c
--- linux-2.4.19-pre4/drivers/net/fc/iph5526.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.19-pre5/drivers/net/fc/iph5526.c	Fri Mar 29 14:49:37 2002
@@ -3871,8 +3871,11 @@
 		/* Wait for the Link to come up and the login process 
 		 * to complete. 
 		 */
-		for(timeout = jiffies + 10*HZ; (timeout > jiffies) && ((fi->g.link_up == FALSE) || (fi->g.port_discovery == TRUE) || (fi->g.explore_fabric == TRUE) || (fi->g.perform_adisc == TRUE));)
+		for(timeout = jiffies + 10*HZ; time_before(jiffies, timeout) && ((fi->g.link_up == FALSE) || (fi->g.port_discovery == TRUE) || (fi->g.explore_fabric == TRUE) || (fi->g.perform_adisc == TRUE));)
+		{
+			cpu_relax();
 			barrier();
+		}
 		
 		count++;
 		no_of_hosts++;
diff -urN linux-2.4.19-pre4/drivers/net/hp-plus.c linux-2.4.19-pre5/drivers/net/hp-plus.c
--- linux-2.4.19-pre4/drivers/net/hp-plus.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/hp-plus.c	Fri Mar 29 14:49:37 2002
@@ -408,8 +408,10 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
-MODULE_PARM_DESC(io, "HP PC-LAN+ I/O port address(es)");
-MODULE_PARM_DESC(irq, "HP PC-LAN+ IRQ number(s); ignored if properly detected");
+MODULE_PARM_DESC(io, "I/O port address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
+MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -457,7 +459,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.19-pre4/drivers/net/hp.c linux-2.4.19-pre5/drivers/net/hp.c
--- linux-2.4.19-pre4/drivers/net/hp.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/hp.c	Fri Mar 29 14:49:37 2002
@@ -380,8 +380,10 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
-MODULE_PARM_DESC(io, "HP PC-LAN I/O base address(es)");
-MODULE_PARM_DESC(irq, "HP PC-LAN IRQ number(s) (assigned)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_DESCRIPTION("HP PC-LAN ISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -429,7 +431,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.19-pre4/drivers/net/hp100.c linux-2.4.19-pre5/drivers/net/hp100.c
--- linux-2.4.19-pre4/drivers/net/hp100.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.19-pre5/drivers/net/hp100.c	Fri Mar 29 14:49:37 2002
@@ -210,8 +210,8 @@
 	hp100_ring_t rxring[MAX_RX_PDL];
 	hp100_ring_t txring[MAX_TX_PDL];
 
-	u_int *page_vaddr;	/* Virtual address of allocated page */
 	u_int *page_vaddr_algn;	/* Aligned virtual address of allocated page */
+	u_long whatever_offset;	/* Offset to bus/phys/dma address */
 	int rxrcommit;		/* # Rx PDLs commited to adapter */
 	int txrcommit;		/* # Tx PDLs commited to adapter */
 };
@@ -348,6 +348,18 @@
 static void hp100_RegisterDump(struct net_device *dev);
 #endif
 
+/* Conversion to new PCI API :
+ * Convert an address in a kernel buffer to a bus/phys/dma address.
+ * This work *only* for memory fragments part of lp->page_vaddr,
+ * because it was properly DMA allocated via pci_alloc_consistent(),
+ * so we just need to "retreive" the original mapping to bus/phys/dma
+ * address - Jean II */
+static inline dma_addr_t virt_to_whatever(struct net_device *dev, u32 * ptr)
+{
+  return ((u_long) ptr) +
+    ((struct hp100_private *) (dev->priv))->whatever_offset;
+}
+
 /* TODO: This function should not really be needed in a good design... */
 static void wait(void)
 {
@@ -625,9 +637,20 @@
 			local_mode = 3;
 		} else if (chip == HP100_CHIPID_LASSEN &&
 			   (lsw & (HP100_BM_WRITE | HP100_BM_READ)) == (HP100_BM_WRITE | HP100_BM_READ)) {
+			/* Conversion to new PCI API :
+			 * I don't have the doc, but I assume that the card
+			 * can map the full 32bit address space.
+			 * Also, we can have EISA Busmaster cards (not tested),
+			 * so beware !!! - Jean II */
+			if((bus == HP100_BUS_PCI) &&
+			   (pci_set_dma_mask(pci_dev, 0xffffffff))) {
+				/* Gracefully fallback to shared memory */
+				goto busmasterfail;
+			}
 			printk("hp100: %s: Busmaster mode enabled.\n", dev->name);
 			hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
 		} else {
+		busmasterfail:
 #ifdef HP100_DEBUG
 			printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name);
 			printk("hp100: %s: Trying shared memory mode.\n", dev->name);
@@ -770,11 +793,14 @@
 	 * in the cards shared memory area. But currently, busmaster has been
 	 * implemented/tested only with the lassen chip anyway... */
 	if (lp->mode == 1) {	/* busmaster */
+		dma_addr_t page_baddr;
 		/* Get physically continous memory for TX & RX PDLs    */
-		if ((lp->page_vaddr = kmalloc(MAX_RINGSIZE + 0x0f, GFP_KERNEL)) == NULL)
+		/* Conversion to new PCI API :
+		 * Pages are always aligned and zeroed, no need to it ourself.
+		 * Doc says should be OK for EISA bus as well - Jean II */
+		if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL)
 			return -ENOMEM;
-		lp->page_vaddr_algn = ((u_int *) (((u_int) (lp->page_vaddr) + 0x0f) & ~0x0f));
-		memset(lp->page_vaddr, 0, MAX_RINGSIZE + 0x0f);
+		lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn);
 
 #ifdef HP100_DEBUG_BM
 		printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", dev->name, (u_int) lp->page_vaddr_algn, (u_int) lp->page_vaddr_algn + MAX_RINGSIZE);
@@ -1187,7 +1213,7 @@
 {
 	struct hp100_private *lp = (struct hp100_private *) dev->priv;
 	hp100_ring_t *ringptr;
-	u_int *pageptr;
+	u_int *pageptr;		/* Warning : increment by 4 - Jean II */
 	int i;
 
 #ifdef HP100_DEBUG_B
@@ -1244,7 +1270,7 @@
 		       dev->name, (unsigned) pdlptr);
 
 	ringptr->pdl = pdlptr + 1;
-	ringptr->pdl_paddr = virt_to_bus(pdlptr + 1);
+	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
 	ringptr->skb = (void *) NULL;
 
 	/* 
@@ -1255,7 +1281,7 @@
 	 */
 	/* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
 
-	*(pdlptr + 2) = (u_int) virt_to_bus(pdlptr);	/* Address Frag 1 */
+	*(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr);	/* Address Frag 1 */
 	*(pdlptr + 3) = 4;	/* Length  Frag 1 */
 
 	return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4);
@@ -1270,7 +1296,7 @@
 		printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n", dev->name, (unsigned) pdlptr);
 
 	ringptr->pdl = pdlptr;	/* +1; */
-	ringptr->pdl_paddr = virt_to_bus(pdlptr);	/* +1 */
+	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr);	/* +1 */
 	ringptr->skb = (void *) NULL;
 
 	return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4);
@@ -1329,8 +1355,10 @@
 				     (unsigned int) ringptr->skb->data);
 #endif
 
+		/* Conversion to new PCI API : map skbuf data to PCI bus.
+		 * Doc says it's OK for EISA as well - Jean II */
 		ringptr->pdl[0] = 0x00020000;	/* Write PDH */
-		ringptr->pdl[3] = ((u_int) virt_to_bus(ringptr->skb->data));
+		ringptr->pdl[3] = ((u_int) pci_map_single(((struct hp100_private *) (dev->priv))->pci_dev, ringptr->skb->data, MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE));
 		ringptr->pdl[4] = MAX_ETHER_SIZE;	/* Length of Data */
 
 #ifdef HP100_DEBUG_BM
@@ -1583,7 +1611,6 @@
 
 	ringptr->skb = skb;
 	ringptr->pdl[0] = ((1 << 16) | i);	/* PDH: 1 Fragment & length */
-	ringptr->pdl[1] = (u32) virt_to_bus(skb->data);	/* 1st Frag: Adr. of data */
 	if (lp->chip == HP100_CHIPID_SHASTA) {
 		/* TODO:Could someone who has the EISA card please check if this works? */
 		ringptr->pdl[2] = i;
@@ -1591,6 +1618,9 @@
 		/* In the PDL, don't use the padded size but the real packet size: */
 		ringptr->pdl[2] = skb->len;	/* 1st Frag: Length of frag */
 	}
+	/* Conversion to new PCI API : map skbuf data to PCI bus.
+	 * Doc says it's OK for EISA as well - Jean II */
+	ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE));	/* 1st Frag: Adr. of data */
 
 	/* Hand this PDL to the card. */
 	hp100_outl(ringptr->pdl_paddr, TX_PDA_L);	/* Low Prio. Queue */
@@ -1639,6 +1669,8 @@
 				dev->name, (u_int) lp->txrhead->skb->data,
 				lp->txrcommit, hp100_inb(TX_PDL), donecount);
 #endif
+		/* Conversion to new PCI API : NOP */
+		pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE);
 		dev_kfree_skb_any(lp->txrhead->skb);
 		lp->txrhead->skb = (void *) NULL;
 		lp->txrhead = lp->txrhead->next;
@@ -1948,6 +1980,9 @@
 		header = *(ptr->pdl - 1);
 		pkt_len = (header & HP100_PKT_LEN_MASK);
 
+		/* Conversion to new PCI API : NOP */
+		pci_unmap_single(lp->pci_dev, (dma_addr_t) ptr->pdl[3], MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
+
 #ifdef HP100_DEBUG_BM
 		printk("hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
 				dev->name, (u_int) (ptr->pdl - 1), (u_int) header,
@@ -2908,7 +2943,7 @@
 	release_region(d->base_addr, HP100_REGION_SIZE);
 
 	if (p->mode == 1)	/* busmaster */
-		kfree(p->page_vaddr);
+		pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, p->page_vaddr_algn, virt_to_whatever(d, p->page_vaddr_algn));
 	if (p->mem_ptr_virt)
 		iounmap(p->mem_ptr_virt);
 	kfree(d->priv);
diff -urN linux-2.4.19-pre4/drivers/net/lance.c linux-2.4.19-pre5/drivers/net/lance.c
--- linux-2.4.19-pre4/drivers/net/lance.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/lance.c	Fri Mar 29 14:49:38 2002
@@ -383,7 +383,7 @@
 					return 0;
 				}
 			}
-			release_resource(r);
+			release_region(ioaddr, LANCE_TOTAL_SIZE);
 		}
 	}
 	return -ENODEV;
diff -urN linux-2.4.19-pre4/drivers/net/lne390.c linux-2.4.19-pre5/drivers/net/lne390.c
--- linux-2.4.19-pre4/drivers/net/lne390.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.19-pre5/drivers/net/lne390.c	Fri Mar 29 14:49:38 2002
@@ -381,9 +381,10 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
-MODULE_PARM_DESC(io, "LNE390 I/O base address(es)");
-MODULE_PARM_DESC(irq, "LNE390 IRQ number(s)");
-MODULE_PARM_DESC(mem, "LNE390 memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "memory base address(es)");
+MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
 MODULE_LICENSE("GPL");
 
 int init_module(void)
diff -urN linux-2.4.19-pre4/drivers/net/ne.c linux-2.4.19-pre5/drivers/net/ne.c
--- linux-2.4.19-pre4/drivers/net/ne.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre5/drivers/net/ne.c	Fri Mar 29 14:49:40 2002
@@ -734,9 +734,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
-MODULE_PARM_DESC(io, "NEx000 I/O base address(es),required");
-MODULE_PARM_DESC(irq, "NEx000 IRQ number(s)");
-MODULE_PARM_DESC(bad, "NEx000 accept bad clone(s)");
+MODULE_PARM_DESC(io, "I/O base address(es),required");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that no ISA autoprobe takes place. We can't guarantee
 that the ne2k probe is the last 8390 based probe to take place (as it
@@ -788,7 +790,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.19-pre4/drivers/net/ne2k-pci.c linux-2.4.19-pre5/drivers/net/ne2k-pci.c
--- linux-2.4.19-pre4/drivers/net/ne2k-pci.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/net/ne2k-pci.c	Fri Mar 29 14:49:40 2002
@@ -82,9 +82,9 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(debug, "PCI NE2000 debug level (1-2)");
-MODULE_PARM_DESC(options, "PCI NE2000: Bit 5: full duplex");
-MODULE_PARM_DESC(full_duplex, "PCI NE2000 full duplex setting(s) (1)");
+MODULE_PARM_DESC(debug, "debug level (1-2)");
+MODULE_PARM_DESC(options, "Bit 5: full duplex");
+MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
 
 /* Some defines that people can play with if so inclined. */
 
diff -urN linux-2.4.19-pre4/drivers/net/ne3210.c linux-2.4.19-pre5/drivers/net/ne3210.c
--- linux-2.4.19-pre4/drivers/net/ne3210.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre5/drivers/net/ne3210.c	Fri Mar 29 14:49:40 2002
@@ -370,9 +370,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
-MODULE_PARM_DESC(io, "NE3210 I/O base address(es)");
-MODULE_PARM_DESC(irq, "NE3210 IRQ number(s)");
-MODULE_PARM_DESC(mem, "NE3210 memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "memory base address(es)");
+MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
@@ -415,7 +417,6 @@
 		}
 	}
 }
-MODULE_LICENSE("GPL");
 
 #endif /* MODULE */
 
diff -urN linux-2.4.19-pre4/drivers/net/pcmcia/wavelan_cs.c linux-2.4.19-pre5/drivers/net/pcmcia/wavelan_cs.c
--- linux-2.4.19-pre4/drivers/net/pcmcia/wavelan_cs.c	Fri Nov  9 15:22:54 2001
+++ linux-2.4.19-pre5/drivers/net/pcmcia/wavelan_cs.c	Fri Mar 29 14:49:40 2002
@@ -22,7 +22,7 @@
 #ifdef WAVELAN_ROAMING	
  * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
  * based on patch by Joe Finney from Lancaster University.
-#endif :-)
+#endif
  *
  * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
  * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
diff -urN linux-2.4.19-pre4/drivers/net/pcmcia/xircom_cb.c linux-2.4.19-pre5/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.19-pre4/drivers/net/pcmcia/xircom_cb.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre5/drivers/net/pcmcia/xircom_cb.c	Fri Mar 29 14:49:41 2002
@@ -1,37 +1,45 @@
 /*
  * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards 
  *
- * This software is Copyright 2001 by the respective authors, and licensed under the GPL
+ * This software is (C) by the respective authors, and licensed under the GPL
  * License.
  *
  * Written by Arjan van de Ven for Red Hat, Inc.
- * Based on work by Jeff Garzik, Doug Ledford, Donald Becker and Ion Badulescu
+ * Based on work by Jeff Garzik, Doug Ledford and Donald Becker 
  *
  *  	This software may be used and distributed according to the terms
  *      of the GNU General Public License, incorporated herein by reference.
  *
  *
- * 	$Id: xircom_cb.c,v 1.11 2001/06/05 09:50:57 fenrus Exp $
+ * 	$Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $
  */
 
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
 #include <asm/io.h>
 
 
 
 #ifdef DEBUG
-#define enter()   printk("Enter: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)
-#define leave()   printk("Leave: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)
+#define enter(x)   printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)
+#define leave(x)   printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__)
 #else
-#define enter()   do {} while (0)
-#define leave()   do {} while (0)
+#define enter(x)   do {} while (0)
+#define leave(x)   do {} while (0)
 #endif
 
 
@@ -66,52 +74,27 @@
 /* Offsets of the buffers within the descriptor pages, in bytes */
 
 #define NUMDESCRIPTORS 4
-#define RXTXBUFSIZE 8192
-#define MAX_PACKETSIZE 1536
 
-
-#define DescOwnedCard	0x80000000
-#define DescOwnedDriver	0x00000000
-
-#define PromiscBit		(1<<6)
-#define CollisionBit 		(1<<8)
-#define TxActiveBit		(1<<13)
-#define RxActiveBit		(1<<1)
-#define LastDescBit	 	(1<<25)
-#define LinkStatusBit 		(1<<27)
-
-#define PowerMgmtBits		( (1<<31)|(1<<30) )
-
-static const unsigned int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};
-
-/* note: this struct is assumed to be packed as this is the "hardware" layout */
-struct descriptor {
-	u32	status;
-	u32	control;
-	u32	address1;
-	u32	address2;
-};
+static int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};
 
 
 struct xircom_private {
 	/* Send and receive buffers, kernel-addressable and dma addressable forms */
 
-	unsigned char *rx_buffer;
-	unsigned char *tx_buffer;
-	
-	struct descriptor *rx_desc;
-	struct descriptor *tx_desc;
+	unsigned int *rx_buffer;
+	unsigned int *tx_buffer;
 
 	dma_addr_t rx_dma_handle;
 	dma_addr_t tx_dma_handle;
 
-	struct sk_buff *tx_skb[NUMDESCRIPTORS];
+	struct sk_buff *tx_skb[4];
 
 	unsigned long io_port;
+	int open;
 	
 	/* transmit_used is the rotating counter that indicates which transmit
 	   descriptor has to be used next */
-	unsigned int transmit_used;
+	int transmit_used;
 
 	/* Spinlock to serialize register operations.
 	   It must be helt while manipulating the following registers:
@@ -136,16 +119,16 @@
 static void xircom_up(struct xircom_private *card);
 static struct net_device_stats *xircom_get_stats(struct net_device *dev);
 
-static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);
-static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset);
+static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);
+static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset);
 static void read_mac_address(struct xircom_private *card);
 static void tranceiver_voodoo(struct xircom_private *card);
 static void initialize_card(struct xircom_private *card);
-static inline void trigger_transmit(struct xircom_private *card);
-static inline void trigger_receive(struct xircom_private *card);
+static void trigger_transmit(struct xircom_private *card);
+static void trigger_receive(struct xircom_private *card);
 static void setup_descriptors(struct xircom_private *card);
-static inline void remove_descriptors(struct xircom_private *card);
-static inline unsigned int link_status_changed(struct xircom_private *card);
+static void remove_descriptors(struct xircom_private *card);
+static int link_status_changed(struct xircom_private *card);
 static void activate_receiver(struct xircom_private *card);
 static void deactivate_receiver(struct xircom_private *card);
 static void activate_transmitter(struct xircom_private *card);
@@ -154,9 +137,7 @@
 static void enable_receive_interrupt(struct xircom_private *card);
 static void enable_link_interrupt(struct xircom_private *card);
 static void disable_all_interrupts(struct xircom_private *card);
-static inline unsigned int link_status(struct xircom_private *card);
-static int mdio_read(struct xircom_private *card, int phy_id, int location);
-static void mdio_write(struct xircom_private *card, int phy_id, int location, int value);
+static int link_status(struct xircom_private *card);
 
 
 
@@ -170,7 +151,7 @@
 	name:		"xircom_cb", 
 	id_table:	xircom_pci_table, 
 	probe:		xircom_probe, 
-	remove:		__devexit_p(xircom_remove), 
+	remove:		__devexit_p(xircom_remove),
 };
 
 
@@ -204,25 +185,20 @@
 {
 	struct net_device *dev = NULL;
 	struct xircom_private *private;
-	u8 chip_rev;
+	unsigned char chip_rev;
 	unsigned long flags;
-	u32 tmp32;
-	u16 tmp16;
-	int ret;
-	enter();
+	unsigned short tmp16;
+	enter("xircom_probe");
 	
 	/* First do the PCI initialisation */
 
-	ret = pci_enable_device(pdev);
-	if (ret)
-		return ret;
+	if (pci_enable_device(pdev))
+		return -ENODEV;
 
 	/* disable all powermanagement */
-	pci_read_config_dword(pdev, PCI_POWERMGMT,&tmp32);
-	tmp32 &= ~PowerMgmtBits; 
-	pci_write_config_dword(pdev, PCI_POWERMGMT, tmp32);
+	pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000);
 	
-	pci_set_master(pdev); 
+	pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/
 
 	/* clear PCI status, if any */ 
 	pci_read_config_word (pdev,PCI_STATUS, &tmp16); 
@@ -236,39 +212,38 @@
 	}
 
 	
-	dev = init_etherdev(dev, sizeof(*private));
-	if (dev == NULL) {
-		printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
-		return -ENODEV;
-	}
-	SET_MODULE_OWNER(dev);
-	private = dev->priv;
-	if (private==NULL) {
-		printk(KERN_ERR "xircom_probe: failed to allocate private device struct\n");
-		return -ENODEV;
-	}
-		
+	/* 
+	   Before changing the hardware, allocate the memory.
+	   This way, we can fail gracefully if not enough memory
+	   is available. 
+	 */
+	private = kmalloc(sizeof(*private),GFP_KERNEL);
+	memset(private, 0, sizeof(struct xircom_private));
+	
 	/* Allocate the send/receive buffers */
-	private->rx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->rx_dma_handle);
+	private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle);
+	
 	if (private->rx_buffer == NULL) {
  		printk(KERN_ERR "xircom_probe: no memory for rx buffer \n");
  		kfree(private);
 		return -ENODEV;
 	}	
-	/* the descriptors are stored in the first bytes of the rx_buffer, hence the ugly cast */
-	private->rx_desc = (struct descriptor *)private->rx_buffer;
-
-	private->tx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->tx_dma_handle);
+	private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle);
 	if (private->tx_buffer == NULL) {
 		printk(KERN_ERR "xircom_probe: no memory for tx buffer \n");
 		kfree(private->rx_buffer);
 		kfree(private);
 		return -ENODEV;
 	}
-	/* the descriptors are stored in the first bytes of the tx_buffer, hence the ugly cast */
-	private->tx_desc = (struct descriptor *)private->tx_buffer;
-	
-	
+	dev = init_etherdev(dev, 0);
+	if (dev == NULL) {
+		printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
+		kfree(private->rx_buffer);
+		kfree(private->tx_buffer);
+		kfree(private);
+		return -ENODEV;
+	}
+	SET_MODULE_OWNER(dev);
 	printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
 
 	private->dev = dev;
@@ -288,25 +263,21 @@
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
 	dev->priv = private;
-	pci_set_drvdata(pdev,dev);
+	pdev->driver_data = dev;
 
 	
-	/* start the transmitter to get a heartbeat; don't do
-	   that when there already is one though; Cisco's 
-	   really don't like that. */
-	if (!link_status(private))
-		tranceiver_voodoo(private);
+	/* start the transmitter to get a heartbeat */
+	/* TODO: send 2 dummy packets here */
+	tranceiver_voodoo(private);
 	
 	spin_lock_irqsave(&private->lock,flags);
 	  activate_transmitter(private);
 	  activate_receiver(private);
 	spin_unlock_irqrestore(&private->lock,flags);
-
-	/* TODO: send 2 dummy packets here */
 	
 	trigger_receive(private);
 	
-	leave();
+	leave("xircom_probe");
 	return 0;
 }
 
@@ -319,138 +290,131 @@
  */
 static void __devexit xircom_remove(struct pci_dev *pdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
+	struct net_device *dev = pdev->driver_data;
 	struct xircom_private *card;
-	enter();
-	
-	card=dev->priv;
-
-	if (card->rx_buffer!=NULL)
-		pci_free_consistent(pdev,RXTXBUFSIZE,card->rx_buffer,card->rx_dma_handle);
-	card->rx_buffer = NULL;
-	card->rx_desc = NULL;
-	if (card->tx_buffer!=NULL)
-		pci_free_consistent(pdev,RXTXBUFSIZE,card->tx_buffer,card->tx_dma_handle);
-	card->tx_buffer = NULL;			
-	card->tx_desc = NULL;
-
+	enter("xircom_remove");
+	if (dev!=NULL) {
+		card=dev->priv;
+		if (card!=NULL) {	
+			if (card->rx_buffer!=NULL)
+				pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
+			card->rx_buffer = NULL;
+			if (card->tx_buffer!=NULL)
+				pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
+			card->tx_buffer = NULL;			
+		}
+		kfree(card);
+	}
 	release_region(dev->base_addr, 128);
 	unregister_netdev(dev);
 	kfree(dev);
-	pci_set_drvdata(pdev,NULL);
-	leave();
+	leave("xircom_remove");
 } 
 
 static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
-	struct net_device *dev = dev_instance;
-	struct xircom_private *card = dev->priv;
-	u32 status;
-	unsigned int xmit_free_count;
-	unsigned int i;
-
-	enter();
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct xircom_private *card = (struct xircom_private *) dev->priv;
+	unsigned int status;
+	int i;
 
+	enter("xircom_interrupt\n");
 
 	spin_lock(&card->lock);
 	status = inl(card->io_port+CSR5);
-	if (status==0xffffffff) {/* card has been ejected / powered down */
-		spin_unlock(&card->lock);
-		return;
-	}
 
-	/* Todo: check if there were any events at all; to speed up
-	   returning if we're on a shared interrupt */	
+#if DEBUG	
+	print_binary(status);
+	printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]);
+	printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]);
+#endif	
 
 	if (link_status_changed(card)) {
 		int newlink;
 		printk(KERN_DEBUG "xircom_cb: Link status has changed \n");
 		newlink = link_status(card);
-		if (newlink) {
-			printk(KERN_INFO  "xircom_cb: Link is %i mbit \n",newlink);
+		printk(KERN_INFO  "xircom_cb: Link is %i mbit \n",newlink);
+		if (newlink)
 			netif_carrier_on(dev);
-		} else {
-			printk(KERN_INFO  "xircom_cb: Link is absent \n");
+		else
 			netif_carrier_off(dev);
-		}
+		
 	}
 
-	/* Clear all remaining interrupt events */	
+	/* Clear all remaining interrupts */	
 	status |= 0xffffffff; /* FIXME: make this clear only the
 				        real existing bits */
 	outl(status,card->io_port+CSR5);
 	
-	xmit_free_count = 0;
 
 	for (i=0;i<NUMDESCRIPTORS;i++) 
-		xmit_free_count += investigate_tx_descriptor(dev,card,i,bufferoffsets[i]);
+		investigate_write_descriptor(dev,card,i,bufferoffsets[i]);
 	for (i=0;i<NUMDESCRIPTORS;i++) 
-		investigate_rx_descriptor(dev,card,i,bufferoffsets[i]);
+		investigate_read_descriptor(dev,card,i,bufferoffsets[i]);
 
 	
-	if (xmit_free_count)
-		netif_start_queue(dev);
-		
 	spin_unlock(&card->lock);
-	leave();
+	leave("xircom_interrupt");
 }
 
 static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct xircom_private *card;
 	unsigned long flags;
-	unsigned int nextdescriptor;
-	unsigned int desc;
-	enter();
+	int nextdescriptor;
+	int desc;
+	enter("xircom_start_xmit");
 	
 	card = (struct xircom_private*)dev->priv;
-
 	spin_lock_irqsave(&card->lock,flags);
 	
+	/* First see if we can free some descriptors */
+	for (desc=0;desc<NUMDESCRIPTORS;desc++) 
+		investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]);
+	
+	
 	nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS);
 	desc = card->transmit_used;
 	
 	/* only send the packet if the descriptor is free */
-	if (card->tx_desc[desc].status==0) {
+	if (card->tx_buffer[4*desc]==0) {
 			/* Copy the packet data; zero the memory first as the card
 			   sometimes sends more than you ask it to. */
 			
-			memset(&card->tx_buffer[bufferoffsets[desc]],0,MAX_PACKETSIZE);
-			memcpy(&(card->tx_buffer[bufferoffsets[desc]]),skb->data,skb->len);
+			memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536);
+			memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len);
 	
 	
 			/* FIXME: The specification tells us that the length we send HAS to be a multiple of
 			   4 bytes. */
 			   
-			card->tx_desc[desc].control = skb->len;
+			card->tx_buffer[4*desc+1] = skb->len;
 			if (desc == NUMDESCRIPTORS-1)
-				card->tx_desc[desc].control |= LastDescBit;  /* bit 25: last descriptor of the ring */
+				card->tx_buffer[4*desc+1] |= (1<<25);  /* bit 25: last descriptor of the ring */
 
-			card->tx_desc[desc].control |= 0xF0000000;
+			card->tx_buffer[4*desc+1] |= 0xF0000000;
 						 /* 0xF0... means want interrupts*/ 
 			card->tx_skb[desc] = skb;
 			
 			wmb();
 			/* This gives the descriptor to the card */
-			card->tx_desc[desc].status = DescOwnedCard;
+			card->tx_buffer[4*desc] = 0x80000000;
 			trigger_transmit(card);
-			if (((int)card->tx_desc[nextdescriptor].status)<0) {	/* next descriptor is occupied... */
+			if (((int)card->tx_buffer[nextdescriptor*4])<0) {	/* next descriptor is occupied... */
 				netif_stop_queue(dev);
 			}
 			card->transmit_used = nextdescriptor;
+			leave("xircom-start_xmit - sent");	
 			spin_unlock_irqrestore(&card->lock,flags);
-			leave();
 			return 0;
 	}
 	
 
 
 	/* Uh oh... no free descriptor... drop the packet */
-	/* This should not happen in theory...*/
 	netif_stop_queue(dev);
 	spin_unlock_irqrestore(&card->lock,flags);
 	trigger_transmit(card);
-	leave();
 	
 	return -EIO;
 }
@@ -462,17 +426,17 @@
 {
 	struct xircom_private *xp = (struct xircom_private *) dev->priv;
 	int retval;
-	enter();
-	printk(KERN_INFO "Xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
+	enter("xircom_open");
+	printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
 	retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev);
 	if (retval) {
-		printk(KERN_ERR "xircom_cb: Unable to aquire IRQ %i, aborting.\n",dev->irq);
-		leave();
+		leave("xircom_open - No IRQ");
 		return retval;
 	}
 	
 	xircom_up(xp);
-	leave();
+	xp->open = 1;
+	leave("xircom_open");
 	return 0;
 }
 
@@ -481,9 +445,9 @@
 	struct xircom_private *card;
 	unsigned long flags;
 	
-	enter();
+	enter("xircom_close");
 	card = dev->priv;
-	netif_stop_queue(dev); /* we don't want to send new packets */
+	netif_stop_queue(dev); /* we don't want new packets */
 
 	
 	spin_lock_irqsave(&card->lock,flags);
@@ -498,10 +462,11 @@
 	
 	spin_unlock_irqrestore(&card->lock,flags);
 	
+	card->open = 0;
 	free_irq(dev->irq,dev);
 	
-	leave();
-		
+	leave("xircom_close");
+	
 	return 0;
 	
 }
@@ -521,7 +486,7 @@
 {
 	unsigned int val;
 	unsigned long flags;
-	enter();
+	enter("initialize_card");
 
 
 	spin_lock_irqsave(&card->lock, flags);
@@ -549,7 +514,7 @@
 
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	leave();
+	leave("initialize_card");
 }
 
 /*
@@ -558,11 +523,15 @@
 claims that the act of writing is sufficient and that the value is
 ignored; I chose zero.
 */
-static inline void trigger_transmit(struct xircom_private *card)
+static void trigger_transmit(struct xircom_private *card)
 {
-	enter();
-	outl(0, card->io_port + CSR1);
-	leave();
+	unsigned int val;
+	enter("trigger_transmit");
+
+	val = 0;
+	outl(val, card->io_port + CSR1);
+
+	leave("trigger_transmit");
 }
 
 /*
@@ -572,11 +541,15 @@
 claims that the act of writing is sufficient and that the value is
 ignored; I chose zero.
 */
-static inline void trigger_receive(struct xircom_private *card)
+static void trigger_receive(struct xircom_private *card)
 {
-	enter();
-	outl(0, card->io_port + CSR2);
-	leave();
+	unsigned int val;
+	enter("trigger_receive");
+
+	val = 0;
+	outl(val, card->io_port + CSR2);
+
+	leave("trigger_receive");
 }
 
 /*
@@ -586,9 +559,9 @@
 static void setup_descriptors(struct xircom_private *card)
 {
 	unsigned int val;
-	u32 address;
-	unsigned int i;
-	enter();
+	unsigned int address;
+	int i;
+	enter("setup_descriptors");
 
 
 	if (card->rx_buffer == NULL)
@@ -597,75 +570,74 @@
 		BUG();
 
 	/* Receive descriptors */
-	memset(card->rx_desc, 0, 128);	/* clear the descriptors */
+	memset(card->rx_buffer, 0, 128);	/* clear the descriptors */
 	for (i=0;i<NUMDESCRIPTORS;i++ ) {
 
 		/* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */
-		card->rx_desc[i].status = DescOwnedCard;
+		card->rx_buffer[i*4 + 0] = 0x80000000;
 		/* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
-		card->rx_desc[i].control = MAX_PACKETSIZE;
+		card->rx_buffer[i*4 + 1] = 1536;
 		if (i==NUMDESCRIPTORS-1)
-			card->rx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */
+			card->rx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
 
 		/* Rx Descr2: address of the buffer
 		   we store the buffer at the 2nd half of the page */
 	
-		address = card->rx_dma_handle;
-		
-		card->rx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]);
+		address = (unsigned long) card->rx_dma_handle;
+		card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
 		/* Rx Desc3: address of 2nd buffer -> 0 */
-		card->rx_desc[i].address2 = 0;
+		card->rx_buffer[i*4 + 3] = 0;
 	}
 	
 	wmb();
 	/* Write the receive descriptor ring address to the card */
-	address = card->rx_dma_handle;
+	address = (unsigned long) card->rx_dma_handle;
 	val = cpu_to_le32(address); 
 	outl(val, card->io_port + CSR3);	/* Receive descr list address */
 
 
 	/* transmit descriptors */
-	memset(card->tx_desc, 0, 128);	/* clear the descriptors */
+	memset(card->tx_buffer, 0, 128);	/* clear the descriptors */
 	
 	for (i=0;i<NUMDESCRIPTORS;i++ ) {
 		/* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */
-		card->tx_desc[i].status = DescOwnedDriver;
+		card->tx_buffer[i*4 + 0] = 0x00000000;
 		/* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
-		card->tx_desc[i].control = MAX_PACKETSIZE;
+		card->tx_buffer[i*4 + 1] = 1536;
 		if (i==NUMDESCRIPTORS-1)
-			card->tx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */
+			card->tx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
 		
 		/* Tx Descr2: address of the buffer
 		   we store the buffer at the 2nd half of the page */
-		address = card->tx_dma_handle;
-		card->tx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]);
+		address = (unsigned long) card->tx_dma_handle;
+		card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
 		/* Tx Desc3: address of 2nd buffer -> 0 */
-		card->tx_desc[i].address2 = 0;
+		card->tx_buffer[i*4 + 3] = 0;
 	}
 
 	wmb();
 	/* wite the transmit descriptor ring to the card */
-	address = card->tx_dma_handle;
+	address = (unsigned long) card->tx_dma_handle;
 	val =cpu_to_le32(address);
 	outl(val, card->io_port + CSR4);	/* xmit descr list address */
 
-	leave();
+	leave("setup_descriptors");
 }
 
 /*
 remove_descriptors informs the card the descriptors are no longer
 valid by setting the address in the card to 0x00.
 */
-static inline void remove_descriptors(struct xircom_private *card)
+static void remove_descriptors(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("remove_descriptors");
 
 	val = 0;
 	outl(val, card->io_port + CSR3);	/* Receive descriptor address */
 	outl(val, card->io_port + CSR4);	/* Send descriptor address */
 
-	leave();
+	leave("remove_descriptors");
 }
 
 /*
@@ -674,24 +646,24 @@
 
 This function also clears the status-bit.
 */
-static inline unsigned int link_status_changed(struct xircom_private *card)
+static int link_status_changed(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("link_status_changed");
 
 	val = inl(card->io_port + CSR5);	/* Status register */
 
-	if ((val & LinkStatusBit) == 0) {	/* no change */
-		leave();
+	if ((val & (1 << 27)) == 0) {	/* no change */
+		leave("link_status_changed - nochange");
 		return 0;
 	}
 
 	/* clear the event by writing a 1 to the bit in the
 	   status register. */
-	val = LinkStatusBit;
+	val = (1 << 27);
 	outl(val, card->io_port + CSR5);
 
-	leave();
+	leave("link_status_changed - changed");
 	return 1;
 }
 
@@ -700,19 +672,19 @@
 transmit_active returns 1 if the transmitter on the card is
 in a non-stopped state.
 */
-static inline int transmit_active(struct xircom_private *card)
+static int transmit_active(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("transmit_active");
 
 	val = inl(card->io_port + CSR5);	/* Status register */
 
 	if ((val & (7 << 20)) == 0) {	/* transmitter disabled */
-		leave();
+		leave("transmit_active - inactive");
 		return 0;
 	}
 
-	leave();
+	leave("transmit_active - active");
 	return 1;
 }
 
@@ -720,20 +692,20 @@
 receive_active returns 1 if the receiver on the card is
 in a non-stopped state.
 */
-static inline unsigned int receive_active(struct xircom_private *card)
+static int receive_active(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("receive_active");
 
 
 	val = inl(card->io_port + CSR5);	/* Status register */
 
 	if ((val & (7 << 17)) == 0) {	/* receiver disabled */
-		leave();
+		leave("receive_active - inactive");
 		return 0;
 	}
 
-	leave();
+	leave("receive_active - active");
 	return 1;
 }
 
@@ -751,18 +723,18 @@
 {
 	unsigned int val;
 	int counter;
-	enter();
+	enter("activate_receiver");
 
 
 	val = inl(card->io_port + CSR6);	/* Operation mode */
 	
-	/* If the "active" bit (1) is set and the receiver is already
+	/* If the "active" bit is set and the receiver is already
 	   active, no need to do the expensive thing */
-	if ((val& RxActiveBit) && (receive_active(card)))
+	if ((val&2) && (receive_active(card)))
 		return;
 	
 	
-	val = val & ~RxActiveBit;		/* disable the receiver */
+	val = val & ~2;		/* disable the receiver */
 	outl(val, card->io_port + CSR6);
 
 	counter = 10;
@@ -778,7 +750,7 @@
 
 	/* enable the receiver */
 	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val | RxActiveBit;		/* enable the receiver */
+	val = val | 2;				/* enable the receiver */
 	outl(val, card->io_port + CSR6);
 
 	/* now wait for the card to activate again */
@@ -793,7 +765,7 @@
 			printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n");
 	}
 
-	leave();
+	leave("activate_receiver");
 }
 
 /*
@@ -807,10 +779,10 @@
 {
 	unsigned int val;
 	int counter;
-	enter();
+	enter("deactivate_receiver");
 
 	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val & ~RxActiveBit;		/* disable the receiver */
+	val = val & ~2;				/* disable the receiver */
 	outl(val, card->io_port + CSR6);
 
 	counter = 10;
@@ -825,7 +797,7 @@
 	}
 
 
-	leave();
+	leave("deactivate_receiver");
 }
 
 
@@ -843,17 +815,17 @@
 {
 	unsigned int val;
 	int counter;
-	enter();
+	enter("activate_transmitter");
 
 
 	val = inl(card->io_port + CSR6);	/* Operation mode */
 
-	/* If the "active" bit (13) is set and the receiver is already
+	/* If the "active" bit is set and the receiver is already
 	   active, no need to do the expensive thing */	 
-	if ((val & TxActiveBit) && (transmit_active(card)))
+	if ((val&(1<<13)) && (transmit_active(card)))
 		return;
 
-	val = val & ~TxActiveBit;	/* disable the transmitter */
+	val = val & ~(1 << 13);	/* disable the transmitter */
 	outl(val, card->io_port + CSR6);
 
 	counter = 10;
@@ -869,7 +841,7 @@
 
 	/* enable the transmitter */
 	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val | TxActiveBit;	/* enable the transmitter */
+	val = val | (1 << 13);	/* enable the transmitter */
 	outl(val, card->io_port + CSR6);
 
 	/* now wait for the card to activate again */
@@ -884,7 +856,7 @@
 			printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n");
 	}
 
-	leave();
+	leave("activate_transmitter");
 }
 
 /*
@@ -898,10 +870,10 @@
 {
 	unsigned int val;
 	int counter;
-	enter();
+	enter("deactivate_transmitter");
 
 	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val & ~TxActiveBit;		/* disable the transmitter */
+	val = val & ~2;		/* disable the transmitter */
 	outl(val, card->io_port + CSR6);
 
 	counter = 20;
@@ -916,7 +888,7 @@
 	}
 
 
-	leave();
+	leave("deactivate_transmitter");
 }
 
 
@@ -928,13 +900,13 @@
 static void enable_transmit_interrupt(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("enable_transmit_interrupt");
 
 	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
 	val |= 1;				/* enable the transmit interrupt */
 	outl(val, card->io_port + CSR7);
 
-	leave();
+	leave("enable_transmit_interrupt");
 }
 
 
@@ -946,13 +918,13 @@
 static void enable_receive_interrupt(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("enable_receive_interrupt");
 
 	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
 	val = val | (1 << 6);			/* enable the receive interrupt */
 	outl(val, card->io_port + CSR7);
 
-	leave();
+	leave("enable_receive_interrupt");
 }
 
 /*
@@ -963,13 +935,13 @@
 static void enable_link_interrupt(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("enable_link_interrupt");
 
 	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
-	val = val | LinkStatusBit;			/* enable the link status chage interrupt */
+	val = val | (1 << 27);			/* enable the link status chage interrupt */
 	outl(val, card->io_port + CSR7);
 
-	leave();
+	leave("enable_link_interrupt");
 }
 
 
@@ -982,12 +954,12 @@
 static void disable_all_interrupts(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("enable_all_interrupts");
 	
 	val = 0;				/* disable all interrupts */
 	outl(val, card->io_port + CSR7);
 
-	leave();
+	leave("disable_all_interrupts");
 }
 
 /*
@@ -998,7 +970,7 @@
 static void enable_common_interrupts(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("enable_link_interrupt");
 
 	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
 	val |= (1<<16); /* Normal Interrupt Summary */
@@ -1011,7 +983,7 @@
 	val |= (1<<1);  /* Transmit Process Stopped */
 	outl(val, card->io_port + CSR7);
 
-	leave();
+	leave("enable_link_interrupt");
 }
 
 /*
@@ -1019,32 +991,31 @@
 
 must be called with the lock held and interrupts disabled.
 */
-static inline void enable_promisc(struct xircom_private *card)
+static int enable_promisc(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("enable_promisc");
 
 	val = inl(card->io_port + CSR6);	
-	val = val | PromiscBit;	 /* Bit 6 */
+	val = val | (1 << 6);	
 	outl(val, card->io_port + CSR6);
 
-	printk(KERN_INFO "xircom_cb: enabling promiscuous mode \n");
-	leave();
+	leave("enable_promisc");
+	return 1;
 }
 
 
 
 
 /* 
-link_status() checks the the links status and will return 0 for no link, 
-10 for 10mbit link and 100 for.. guess what.
+link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
 
 Must be called in locked state with interrupts disabled
 */
-static inline unsigned int link_status(struct xircom_private *card)
+static int link_status(struct xircom_private *card)
 {
 	unsigned int val;
-	enter();
+	enter("link_status");
 	
 	val = inb(card->io_port + CSR12);
 	
@@ -1055,59 +1026,12 @@
 		
 	/* If we get here -> no link at all */	
 
-	leave();
+	leave("link_status");
 	return 0;
 }
 
 
 
-/* 
-
-set_half_duplex() sets the card to half duplex mode. In order to do this,
-set_half_duplex() has to deactivate the transmitter and receiver first. It
-will re-enable the transmitter and receiver if those were active from the
-beginning.
-
-Update: the above is not enough. It doesn't touch the MII, in fact it ensures
-the main chipset and the MII are never in sync if a full-duplex connection
-is negotiated. The proper fix is to tell the MII to force a half-duplex
-connection. -Ion
-
-Must be called in locked state
-*/
-static void set_half_duplex(struct xircom_private *card)
-{
-	unsigned int val;
-	int rx,tx,tmp;
-	enter();
-	
-	rx=receive_active(card);
-	tx=transmit_active(card);
-	
-	deactivate_transmitter(card);
-	deactivate_receiver(card);
-	
-	val = inb(card->io_port + CSR6);
-	val &= ~(1<<9);
-	outb(val,card->io_port + CSR6);
-
-	/* tell the MII not to advertise 10/100FDX */
-	tmp = mdio_read(card, 0, 4);
-	printk("xircom_cb: capabilities changed from %#x to %#x\n",
-	       tmp, tmp & ~0x140);
-	tmp &= ~0x140;
-	mdio_write(card, 0, 4, tmp);
-	/* restart autonegotiation */
-	tmp = mdio_read(card, 0, 0);
-	mdio_write(card, 0, 0, tmp | 0x1200);
-
-	if (rx)
-		activate_receiver(card);
-	if (tx)
-		activate_transmitter(card);	
-
-	leave();
-}
 
 
 /*
@@ -1121,7 +1045,7 @@
 	unsigned long flags;
 	int i;
 
-	enter();
+	enter("read_mac_address");
 		
 	spin_lock_irqsave(&card->lock, flags);
 
@@ -1154,92 +1078,7 @@
 		printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
 	printk("\n");
 #endif
-	leave();
-}
-
-
-/* MII transceiver control section.
-   Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
-
-/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues or future 66Mhz PCI. */
-#define mdio_delay() inl(mdio_addr)
-
-/* Read and write the MII registers using software-generated serial
-   MDIO protocol.  It is just different enough from the EEPROM protocol
-   to not share code.  The maxium data clock rate is 2.5 Mhz. */
-#define MDIO_SHIFT_CLK	0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB	0x00000		/* Ignore the 0x02000 databook setting. */
-#define MDIO_ENB_IN	0x40000
-#define MDIO_DATA_READ	0x80000
-
-static int mdio_read(struct xircom_private *card, int phy_id, int location)
-{
-	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	int retval = 0;
-	long mdio_addr = card->io_port + CSR9;
-
-	/* Establish sync by sending at least 32 logic ones. */
-	for (i = 32; i >= 0; i--) {
-		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Shift the read command bits out. */
-	for (i = 15; i >= 0; i--) {
-		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-
-		outl(MDIO_ENB | dataval, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outl(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct xircom_private *card, int phy_id, int location, int value)
-{
-	int i;
-	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-	long mdio_addr = card->io_port + CSR9;
-
-	/* Establish sync by sending 32 logic ones. */
-	for (i = 32; i >= 0; i--) {
-		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-		outl(MDIO_ENB | dataval, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Clear out extra bits. */
-	for (i = 2; i > 0; i--) {
-		outl(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
+	leave("read_mac_address");
 }
 
 
@@ -1251,14 +1090,11 @@
 static void tranceiver_voodoo(struct xircom_private *card)
 {
 	unsigned long flags;
-	u32 tmp32;
 
-	enter();
+	enter("tranceiver_voodoo");
 
 	/* disable all powermanagement */
-	pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32);
-	tmp32 &= ~PowerMgmtBits; 
-	pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32);
+	pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000);
 
 	setup_descriptors(card);
 
@@ -1274,7 +1110,7 @@
         spin_unlock_irqrestore(&card->lock, flags);
 
 	netif_start_queue(card->dev);
-	leave();
+	leave("tranceiver_voodoo");
 }
 
 
@@ -1282,14 +1118,11 @@
 {
 	unsigned long flags;
 	int i;
-	u32 tmp32;
 
-	enter();
+	enter("xircom_up");
 
 	/* disable all powermanagement */
-	pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32);
-	tmp32 &= ~PowerMgmtBits; 
-	pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32);
+	pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000);
 
 	setup_descriptors(card);
 
@@ -1304,23 +1137,23 @@
 	
 	/* The card can have received packets already, read them away now */
 	for (i=0;i<NUMDESCRIPTORS;i++) 
-		investigate_rx_descriptor(card->dev,card,i,bufferoffsets[i]);
+		investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]);
 
 
-	set_half_duplex(card);
 	spin_unlock_irqrestore(&card->lock, flags);
 	trigger_receive(card);
 	trigger_transmit(card);
 	netif_start_queue(card->dev);
-	leave();
+	leave("xircom_up");
 }
 
-static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
+/* Bufferoffset is in BYTES */
+static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
 {
 		int status;		
 		
-		enter();
-		status = card->rx_desc[descnr].status;
+		enter("investigate_read_descriptor");
+		status = card->rx_buffer[4*descnr];
 		
 		if ((status > 0)) {	/* packet received */
 		
@@ -1341,7 +1174,7 @@
 			}
 			skb->dev = dev;
 			skb_reserve(skb, 2);
-			eth_copy_and_sum(skb, &card->rx_buffer[bufferoffset], pkt_len, 0);
+			eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0);
 			skb_put(skb, pkt_len);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
@@ -1351,48 +1184,46 @@
 			
 		      out:
 			/* give the buffer back to the card */
-			card->rx_desc[descnr].status = DescOwnedCard;
+			card->rx_buffer[4*descnr] =  0x80000000;
 			trigger_receive(card);
 		}
 
-		leave();
+		leave("investigate_read_descriptor");
 
 }
 
 
-/* Returns 1 if the descriptor is free or became free */
-static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset)
+/* Bufferoffset is in BYTES */
+static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset)
 {
-		int status,retval = 0;
-		enter();
-		
-		status = card->tx_desc[descnr].status;
+		int status;
+
+		enter("investigate_write_descriptor");
 		
-		if (status == DescOwnedDriver)
-			return 1;
+		status = card->tx_buffer[4*descnr];
 #if 0		
 		if (status & 0x8000) {	/* Major error */
 			printk(KERN_ERR "Major transmit error status %x \n", status);
-			card->tx_desc[descnr].status = 0;
+			card->tx_buffer[4*descnr] = 0;
 			netif_wake_queue (dev);
 		}
 #endif
 		if (status > 0) {	/* bit 31 is 0 when done */
-			card->stats.tx_packets++;
 			if (card->tx_skb[descnr]!=NULL) {
 				card->stats.tx_bytes += card->tx_skb[descnr]->len;
 				dev_kfree_skb_irq(card->tx_skb[descnr]);
 			}
 			card->tx_skb[descnr] = NULL;
 			/* Bit 8 in the status field is 1 if there was a collision */
-			if (status & CollisionBit)
+			if (status&(1<<8))
 				card->stats.collisions++;
-			card->tx_desc[descnr].status = DescOwnedDriver; /* descriptor is free again */
-			retval = 1;
+			card->tx_buffer[4*descnr] = 0; /* descriptor is free again */
+			netif_wake_queue (dev);
+			card->stats.tx_packets++;
 		}
 
-		leave();
-		return retval;		
+		leave("investigate_write_descriptor");
+		
 }
 
 
@@ -1409,3 +1240,4 @@
 
 module_init(xircom_init) 
 module_exit(xircom_exit)
+
diff -urN linux-2.4.19-pre4/drivers/net/pcnet32.c linux-2.4.19-pre5/drivers/net/pcnet32.c
--- linux-2.4.19-pre4/drivers/net/pcnet32.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/pcnet32.c	Fri Mar 29 14:49:41 2002
@@ -22,8 +22,9 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.25kf"
-#define DRV_RELDATE	"17.11.2001"
+#define DRV_VERSION	"1.27a"
+#define DRV_RELDATE	"10.02.2002"
+#define PFX		DRV_NAME ": "
 
 static const char *version =
 DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n";
@@ -54,8 +55,6 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 
-static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
-
 /*
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
@@ -65,13 +64,26 @@
     { 0, }
 };
 
+MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
+
+int cards_found __initdata;
+
+/* 
+ * VLB I/O addresses 
+ */
+static unsigned int pcnet32_portlist[] __initdata = 
+	{ 0x300, 0x320, 0x340, 0x360, 0 };
+
+
+
 static int pcnet32_debug = 1;
 static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
+static int pcnet32vlb;	 /* check for VLB cards ? */
 
 static struct net_device *pcnet32_dev;
 
-static const int max_interrupt_work = 80;
-static const int rx_copybreak = 200;
+static int max_interrupt_work = 80;
+static int rx_copybreak = 200;
 
 #define PCNET32_PORT_AUI      0x00
 #define PCNET32_PORT_10BT     0x01
@@ -94,21 +106,21 @@
     PCNET32_PORT_AUI,			   /*  1 BNC/AUI	  */
     PCNET32_PORT_AUI,			   /*  2 AUI/BNC	  */ 
     PCNET32_PORT_ASEL,			   /*  3 not supported	  */
-    PCNET32_PORT_10BT | PCNET32_PORT_FD,	   /*  4 10baseT-FD	  */
+    PCNET32_PORT_10BT | PCNET32_PORT_FD,   /*  4 10baseT-FD	  */
     PCNET32_PORT_ASEL,			   /*  5 not supported	  */
     PCNET32_PORT_ASEL,			   /*  6 not supported	  */
     PCNET32_PORT_ASEL,			   /*  7 not supported	  */
     PCNET32_PORT_ASEL,			   /*  8 not supported	  */
     PCNET32_PORT_MII,			   /*  9 MII 10baseT	  */
-    PCNET32_PORT_MII | PCNET32_PORT_FD,		   /* 10 MII 10baseT-FD	  */
+    PCNET32_PORT_MII | PCNET32_PORT_FD,	   /* 10 MII 10baseT-FD	  */
     PCNET32_PORT_MII,			   /* 11 MII (autosel)	  */
     PCNET32_PORT_10BT,			   /* 12 10BaseT	  */
-    PCNET32_PORT_MII | PCNET32_PORT_100,	   /* 13 MII 100BaseTx	  */
+    PCNET32_PORT_MII | PCNET32_PORT_100,   /* 13 MII 100BaseTx	  */
     PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */
     PCNET32_PORT_ASEL			   /* 15 not supported	  */
 };
 
-#define MAX_UNITS 8
+#define MAX_UNITS 8	/* More are supported, limit only on options */
 static int options[MAX_UNITS];
 static int full_duplex[MAX_UNITS];
 
@@ -187,7 +199,19 @@
  * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
  * v1.26   Converted to pci_alloc_consistent, Jamey Hicks / George France
  *                                           <jamey@crl.dec.com>
- * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
+ * -	   Fixed a few bugs, related to running the controller in 32bit mode.
+ *	   23 Oct, 2000.  Carsten Langgaard, carstenl@mips.com
+ *	   Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ * v1.26p  Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
+ * v1.27   improved CSR/PROM address detection, lots of cleanups,
+ * 	   new pcnet32vlb module option, HP-PARISC support,
+ * 	   added module parameter descriptions, 
+ * 	   initial ethtool support - Helge Deller <deller@gmx.de>
+ * v1.27a  Sun Feb 10 2002 Go Taniguchi <go@turbolinux.co.jp>
+ *	   use alloc_etherdev and register_netdev
+ *	   fix pci probe not increment cards_found
+ *	   FD auto negotiate error workaround for xSeries250
+ *	   clean up and using new mii module
  */
 
 
@@ -201,13 +225,13 @@
 #define PCNET32_LOG_RX_BUFFERS 5
 #endif
 
-#define TX_RING_SIZE			(1 << (PCNET32_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS		((PCNET32_LOG_TX_BUFFERS) << 12)
-
-#define RX_RING_SIZE			(1 << (PCNET32_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS		((PCNET32_LOG_RX_BUFFERS) << 4)
+#define TX_RING_SIZE		(1 << (PCNET32_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK	(TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS	((PCNET32_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE		(1 << (PCNET32_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK	(RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS	((PCNET32_LOG_RX_BUFFERS) << 4)
 
 #define PKT_BUF_SZ		1544
 
@@ -222,7 +246,7 @@
 #define PCNET32_DWIO_RESET	0x18
 #define PCNET32_DWIO_BDP	0x1C
 
-#define PCNET32_TOTAL_SIZE 0x20
+#define PCNET32_TOTAL_SIZE	0x20
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
@@ -270,37 +294,36 @@
  */
 struct pcnet32_private {
     /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
-    struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
-    struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
-    struct pcnet32_init_block	init_block;
-    dma_addr_t dma_addr;		/* DMA address of beginning of this object, returned by pci_alloc_consistent */
-    struct pci_dev *pci_dev;		/* Pointer to the associated pci device structure */
-    const char *name;
+    struct pcnet32_rx_head    rx_ring[RX_RING_SIZE];
+    struct pcnet32_tx_head    tx_ring[TX_RING_SIZE];
+    struct pcnet32_init_block init_block;
+    dma_addr_t 		dma_addr;	/* DMA address of beginning of this object, 
+					   returned by pci_alloc_consistent */
+    struct pci_dev	*pci_dev;	/* Pointer to the associated pci device structure */
+    const char		*name;
     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-    struct sk_buff *tx_skbuff[TX_RING_SIZE];
-    struct sk_buff *rx_skbuff[RX_RING_SIZE];
-    dma_addr_t tx_dma_addr[TX_RING_SIZE];
-    dma_addr_t rx_dma_addr[RX_RING_SIZE];
+    struct sk_buff	*tx_skbuff[TX_RING_SIZE];
+    struct sk_buff	*rx_skbuff[RX_RING_SIZE];
+    dma_addr_t		tx_dma_addr[TX_RING_SIZE];
+    dma_addr_t		rx_dma_addr[RX_RING_SIZE];
     struct pcnet32_access a;
-    spinlock_t lock;					/* Guard lock */
-    unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-    unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+    spinlock_t		lock;		/* Guard lock */
+    unsigned int	cur_rx, cur_tx;	/* The next free ring entry */
+    unsigned int	dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
     struct net_device_stats stats;
-    char tx_full;
-    int	 options;
-    int	 shared_irq:1,			/* shared irq possible */
-	ltint:1,
-#ifdef DO_DXSUFLO
-      dxsuflo:1,			    /* disable transmit stop on uflo */
-#endif
-	mii:1;					/* mii port available */
-    struct net_device *next;
+    char		tx_full;
+    int			options;
+    int	shared_irq:1,			/* shared irq possible */
+	ltint:1,			/* enable TxDone-intr inhibitor */
+	dxsuflo:1,			/* disable transmit stop on uflo */
+	mii:1;				/* mii port available */
+    struct net_device	*next;
     struct mii_if_info mii_if;
 };
 
-static int  pcnet32_probe_vlbus(int cards_found);
+static void pcnet32_probe_vlbus(void);
 static int  pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
-static int  pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *);
+static int  pcnet32_probe1(unsigned long, unsigned int, int, struct pci_dev *);
 static int  pcnet32_open(struct net_device *);
 static int  pcnet32_init_ring(struct net_device *);
 static int  pcnet32_start_xmit(struct sk_buff *, struct net_device *);
@@ -319,15 +342,6 @@
     PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
 
-struct pcnet32_pci_id_info {
-    const char *name;
-    u16 vendor_id, device_id, svid, sdid, flags;
-    int io_size;
-    int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *);
-};
-
-
-MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
 
 static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
 {
@@ -375,13 +389,13 @@
 }
 
 static struct pcnet32_access pcnet32_wio = {
-    pcnet32_wio_read_csr,
-    pcnet32_wio_write_csr,
-    pcnet32_wio_read_bcr,
-    pcnet32_wio_write_bcr,
-    pcnet32_wio_read_rap,
-    pcnet32_wio_write_rap,
-    pcnet32_wio_reset
+    read_csr:	pcnet32_wio_read_csr,
+    write_csr:	pcnet32_wio_write_csr,
+    read_bcr:	pcnet32_wio_read_bcr,
+    write_bcr:	pcnet32_wio_write_bcr,
+    read_rap:	pcnet32_wio_read_rap,
+    write_rap:	pcnet32_wio_write_rap,
+    reset:	pcnet32_wio_reset
 };
 
 static u16 pcnet32_dwio_read_csr (unsigned long addr, int index)
@@ -430,82 +444,61 @@
 }
 
 static struct pcnet32_access pcnet32_dwio = {
-    pcnet32_dwio_read_csr,
-    pcnet32_dwio_write_csr,
-    pcnet32_dwio_read_bcr,
-    pcnet32_dwio_write_bcr,
-    pcnet32_dwio_read_rap,
-    pcnet32_dwio_write_rap,
-    pcnet32_dwio_reset
-
+    read_csr:	pcnet32_dwio_read_csr,
+    write_csr:	pcnet32_dwio_write_csr,
+    read_bcr:	pcnet32_dwio_read_bcr,
+    write_bcr:	pcnet32_dwio_write_bcr,
+    read_rap:	pcnet32_dwio_read_rap,
+    write_rap:	pcnet32_dwio_write_rap,
+    reset:	pcnet32_dwio_reset
 };
 
-
 
-/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/
-static int __init pcnet32_probe_vlbus(int cards_found)
+
+/* only probes for non-PCI devices, the rest are handled by 
+ * pci_register_driver via pcnet32_probe_pci */
+
+static void __devinit
+pcnet32_probe_vlbus(void)
 {
-    unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0;
-    unsigned int  irq_line = 0; // FIXME dev ? dev->irq : 0;
-    int *port;
-    
-    printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found);
-#ifndef __powerpc__
-    if (ioaddr > 0x1ff) {
-	if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0)
-	    return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL);
-	else
-	    return -ENODEV;
-    } else
-#endif
-	if (ioaddr != 0)
-	    return -ENXIO;
+    unsigned int *port, ioaddr;
     
-    /* now look for PCnet32 VLB cards */
-    for (port = pcnet32_portlist; *port; port++) {
-	unsigned long ioaddr = *port;
-	
-	if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
+    /* search for PCnet32 VLB cards at known addresses */
+    for (port = pcnet32_portlist; (ioaddr = *port); port++) {
+	if (!check_region(ioaddr, PCNET32_TOTAL_SIZE)) {
 	    /* check if there is really a pcnet chip on that ioaddr */
-	    if ((inb(ioaddr + 14) == 0x57) &&
-		(inb(ioaddr + 15) == 0x57) &&
-		(pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0))
-		cards_found++;
+	    if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57))
+		pcnet32_probe1(ioaddr, 0, 0, NULL);
 	}
     }
-    return cards_found ? 0: -ENODEV;
 }
 
 
-
 static int __devinit
 pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-    static int card_idx;
-    long ioaddr;
-    int err = 0;
-
-    printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
+    unsigned long ioaddr;
+    int err;
 
-    if ((err = pci_enable_device(pdev)) < 0) {
-	printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err);
+    err = pci_enable_device(pdev);
+    if (err < 0) {
+	printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err);
 	return err;
     }
     pci_set_master(pdev);
 
     ioaddr = pci_resource_start (pdev, 0);
-    printk(KERN_INFO "    ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
     if (!ioaddr) {
-        printk (KERN_ERR "no PCI IO resources, aborting\n");
+        printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n");
         return -ENODEV;
     }
-	
+    
     if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
-	printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n");
+	printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n");
 	return -ENODEV;
     }
 
-    return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev);
+    return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev);
 }
 
 
@@ -514,41 +507,44 @@
  *  pdev will be NULL when called from pcnet32_probe_vlbus.
  */
 static int __devinit
-pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
+pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
+		struct pci_dev *pdev)
 {
     struct pcnet32_private *lp;
     struct resource *res;
     dma_addr_t lp_dma_addr;
-    int i,media,fdx = 0, mii = 0, fset = 0;
-#ifdef DO_DXSUFLO
-    int dxsuflo = 0;
-#endif
-    int ltint = 0;
+    int i, media;
+    int fdx, mii, fset, dxsuflo, ltint;
     int chip_version;
     char *chipname;
     struct net_device *dev;
     struct pcnet32_access *a = NULL;
+    u8 promaddr[6];
 
     /* reset the chip */
-    pcnet32_dwio_reset(ioaddr);
     pcnet32_wio_reset(ioaddr);
 
     /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */
-    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
+    if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) {
 	a = &pcnet32_wio;
     } else {
-	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+	pcnet32_dwio_reset(ioaddr);
+	if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
 	    a = &pcnet32_dwio;
 	} else
 	    return -ENODEV;
     }
 
-    chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
+    chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16);
     if (pcnet32_debug > 2)
 	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
 	return -ENODEV;
+    
+    /* initialize variables */
+    fdx = mii = fset = dxsuflo = ltint = 0;
     chip_version = (chip_version >> 12) & 0xffff;
+
     switch (chip_version) {
     case 0x2420:
 	chipname = "PCnet/PCI 79C970"; /* PCI */
@@ -587,23 +583,24 @@
 	 * mode by which the card should operate
 	 */
 	/* switch to home wiring mode */
-	media = a->read_bcr (ioaddr, 49);
+	media = a->read_bcr(ioaddr, 49);
 #if 0
 	if (pcnet32_debug > 2)
-	    printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n",  media);
+	    printk(KERN_DEBUG PFX "media value %#x.\n",  media);
 	media &= ~3;
 	media |= 1;
 #endif
 	if (pcnet32_debug > 2)
-	    printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n",  media);
-	a->write_bcr (ioaddr, 49, media);
+	    printk(KERN_DEBUG PFX "media reset to %#x.\n",  media);
+	a->write_bcr(ioaddr, 49, media);
 	break;
     case 0x2627:
 	chipname = "PCnet/FAST III 79C975"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
     default:
-	printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+	printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n",
+			chip_version);
 	return -ENODEV;
     }
 
@@ -618,17 +615,15 @@
     {
 	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
 	a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);
-#ifdef DO_DXSUFLO
 	dxsuflo = 1;
-#endif
 	ltint = 1;
     }
     
-    dev = init_etherdev(NULL, 0);
-    if(dev==NULL)
+    dev = alloc_etherdev(0);
+    if(!dev)
 	return -ENOMEM;
 
-    printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
+    printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
 
     /* In most chips, after a chip reset, the ethernet address is read from the
      * station address PROM at the base address and programmed into the
@@ -644,31 +639,28 @@
 	dev->dev_addr[2*i] = val & 0x0ff;
 	dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff;
     }
-    {
-	u8 promaddr[6];
-	for (i = 0; i < 6; i++) {
-	    promaddr[i] = inb(ioaddr + i);
-	}
-	if( memcmp( promaddr, dev->dev_addr, 6) )
-	{
-	    printk(" warning PROM address does not match CSR address\n");
-#if defined(__i386__)
-	    printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name);
-	    memcpy(dev->dev_addr, promaddr, 6);
-#elif defined(__powerpc__)
-	    if (!is_valid_ether_addr(dev->dev_addr)
-		&& is_valid_ether_addr(promaddr)) {
-		    printk("\n" KERN_WARNING "%s: using PROM address:",
-			   dev->name);
-		    memcpy(dev->dev_addr, promaddr, 6);
-	    }
+
+    /* read PROM address and compare with CSR address */
+    for (i = 0; i < 6; i++)
+	promaddr[i] = inb(ioaddr + i);
+    
+    if( memcmp( promaddr, dev->dev_addr, 6)
+	|| !is_valid_ether_addr(dev->dev_addr) ) {
+#ifndef __powerpc__
+	if( is_valid_ether_addr(promaddr) ){
+#else
+	if( !is_valid_ether_addr(dev->dev_addr)
+	    && is_valid_ether_addr(promaddr)) {
 #endif
-	}	    	    
+	    printk(" warning: CSR address invalid,\n");
+	    printk(KERN_INFO "    using instead PROM address of");
+	    memcpy(dev->dev_addr, promaddr, 6);
+	}
     }
+
     /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
     if( !is_valid_ether_addr(dev->dev_addr) )
-	for (i = 0; i < 6; i++)
-	    dev->dev_addr[i]=0;
+	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
 
     for (i = 0; i < 6; i++)
 	printk(" %2.2x", dev->dev_addr[i] );
@@ -698,7 +690,7 @@
 
     dev->base_addr = ioaddr;
     res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
-    if (res == NULL)
+    if (!res)
 	return -EBUSY;
     
     /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
@@ -710,7 +702,6 @@
     memset(lp, 0, sizeof(*lp));
     lp->dma_addr = lp_dma_addr;
     lp->pci_dev = pdev;
-    printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr);
 
     spin_lock_init(&lp->lock);
     
@@ -718,24 +709,23 @@
     lp->name = chipname;
     lp->shared_irq = shared;
     lp->mii_if.full_duplex = fdx;
-#ifdef DO_DXSUFLO
     lp->dxsuflo = dxsuflo;
-#endif
     lp->ltint = ltint;
     lp->mii = mii;
-    if (options[card_idx] > sizeof (options_mapping))
+    if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping)))
 	lp->options = PCNET32_PORT_ASEL;
     else
-	lp->options = options_mapping[options[card_idx]];
+	lp->options = options_mapping[options[cards_found]];
     lp->mii_if.dev = dev;
     lp->mii_if.mdio_read = mdio_read;
     lp->mii_if.mdio_write = mdio_write;
     
-    if (fdx && !(lp->options & PCNET32_PORT_ASEL) && full_duplex[card_idx])
+    if (fdx && !(lp->options & PCNET32_PORT_ASEL) && 
+		((cards_found>=MAX_UNITS) || full_duplex[cards_found]))
 	lp->options |= PCNET32_PORT_FD;
     
-    if (a == NULL) {
-      printk(KERN_ERR "pcnet32: No access methods\n");
+    if (!a) {
+      printk(KERN_ERR PFX "No access methods\n");
       pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
       release_resource(res);
       return -ENODEV;
@@ -790,8 +780,6 @@
 	}
     }
 
-    if (pcnet32_debug > 0)
-	printk(KERN_INFO "%s", version);
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -801,17 +789,19 @@
     dev->set_multicast_list = &pcnet32_set_multicast_list;
     dev->do_ioctl = &pcnet32_ioctl;
     dev->tx_timeout = pcnet32_tx_timeout;
-    dev->watchdog_timeo = (HZ >> 1);
+    dev->watchdog_timeo = (5*HZ);
 
     lp->next = pcnet32_dev;
     pcnet32_dev = dev;
 
     /* Fill in the generic fields of the device structure. */
-    ether_setup(dev);
+    register_netdev(dev);
+    printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name);
+    cards_found++;
     return 0;
 }
 
-
+
 static int
 pcnet32_open(struct net_device *dev)
 {
@@ -856,6 +846,9 @@
 	    val |= 1;
 	    if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI))
 		val |= 2;
+	} else if (lp->options & PCNET32_PORT_ASEL) {
+	/* workaround for xSeries250 */
+	    val |= 3;
 	}
 	lp->a.write_bcr (ioaddr, 9, val);
     }
@@ -888,6 +881,7 @@
 	lp->a.write_csr (ioaddr, 3, val);
     }
 #endif
+
     if (lp->ltint) { /* Enable TxDone-intr inhibitor */
 	val = lp->a.read_csr (ioaddr, 5);
 	val |= (1<<14);
@@ -922,7 +916,7 @@
     if (pcnet32_debug > 2)
 	printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
 	       dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)),
-	       lp->a.read_csr (ioaddr, 0));
+	       lp->a.read_csr(ioaddr, 0));
 
 
     MOD_INC_USE_COUNT;
@@ -952,7 +946,7 @@
     for (i = 0; i < TX_RING_SIZE; i++) {
 	if (lp->tx_skbuff[i]) {
             pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
-	    dev_kfree_skb(lp->tx_skbuff[i]); 
+	    dev_kfree_skb_any(lp->tx_skbuff[i]); 
 	    lp->tx_skbuff[i] = NULL;
             lp->tx_dma_addr[i] = 0;
 	}
@@ -1028,11 +1022,12 @@
 pcnet32_tx_timeout (struct net_device *dev)
 {
     struct pcnet32_private *lp = dev->priv;
-    unsigned int ioaddr = dev->base_addr;
+    unsigned long ioaddr = dev->base_addr, flags;
 
+    spin_lock_irqsave(&lp->lock, flags);
     /* Transmitter timeout, serious problems. */
 	printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n",
-	       dev->name, lp->a.read_csr (ioaddr, 0));
+	       dev->name, lp->a.read_csr(ioaddr, 0));
 	lp->a.write_csr (ioaddr, 0, 0x0004);
 	lp->stats.tx_errors++;
 	if (pcnet32_debug > 2) {
@@ -1054,6 +1049,8 @@
 
 	dev->trans_start = jiffies;
 	netif_start_queue(dev);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 
@@ -1061,14 +1058,14 @@
 pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct pcnet32_private *lp = dev->priv;
-    unsigned int ioaddr = dev->base_addr;
+    unsigned long ioaddr = dev->base_addr;
     u16 status;
     int entry;
     unsigned long flags;
 
     if (pcnet32_debug > 3) {
 	printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
-	       dev->name, lp->a.read_csr (ioaddr, 0));
+	       dev->name, lp->a.read_csr(ioaddr, 0));
     }
 
     spin_lock_irqsave(&lp->lock, flags);
@@ -1135,8 +1132,9 @@
     int boguscnt =  max_interrupt_work;
     int must_restart;
 
-    if (dev == NULL) {
-	printk (KERN_DEBUG "pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+    if (!dev) {
+	printk (KERN_DEBUG "%s(): irq %d for unknown device\n",
+		__FUNCTION__, irq);
 	return;
     }
 
@@ -1207,7 +1205,8 @@
 
 		/* We must free the original skb */
 		if (lp->tx_skbuff[entry]) {
-                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry],
+			lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
 		    dev_kfree_skb_irq(lp->tx_skbuff[entry]);
 		    lp->tx_skbuff[entry] = 0;
                     lp->tx_dma_addr[entry] = 0;
@@ -1215,13 +1214,12 @@
 		dirty_tx++;
 	    }
 
-#ifndef final_version
 	    if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-		       dirty_tx, lp->cur_tx, lp->tx_full);
+		printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+			dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
 		dirty_tx += TX_RING_SIZE;
 	    }
-#endif
+
 	    if (lp->tx_full &&
 		netif_queue_stopped(dev) &&
 		dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
@@ -1262,7 +1260,7 @@
 
     /* Clear any other interrupt, and set interrupt enable. */
     lp->a.write_csr (ioaddr, 0, 0x7940);
-    lp->a.write_rap(ioaddr,rap);
+    lp->a.write_rap (ioaddr,rap);
     
     if (pcnet32_debug > 4)
 	printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
@@ -1312,10 +1310,13 @@
 		    if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
 			skb_reserve (newskb, 2);
 			skb = lp->rx_skbuff[entry];
+			pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], skb->len, PCI_DMA_FROMDEVICE);
 			skb_put (skb, pkt_len);
 			lp->rx_skbuff[entry] = newskb;
 			newskb->dev = dev;
-                        lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);
+                        lp->rx_dma_addr[entry] = 
+				pci_map_single(lp->pci_dev, newskb->tail,
+					newskb->len, PCI_DMA_FROMDEVICE);
 			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		    } else
@@ -1349,6 +1350,7 @@
 		lp->stats.rx_bytes += skb->len;
 		skb->protocol=eth_type_trans(skb,dev);
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
 	    }
 	}
@@ -1445,13 +1447,13 @@
 	
     /* set all multicast bits */
     if (dev->flags & IFF_ALLMULTI){ 
-	ib->filter [0] = 0xffffffff;
-	ib->filter [1] = 0xffffffff;
+	ib->filter[0] = 0xffffffff;
+	ib->filter[1] = 0xffffffff;
 	return;
     }
     /* clear the multicast filter */
-    ib->filter [0] = 0;
-    ib->filter [1] = 0;
+    ib->filter[0] = 0;
+    ib->filter[1] = 0;
 
     /* Add addresses */
     for (i = 0; i < dev->mc_count; i++){
@@ -1475,9 +1477,10 @@
  */
 static void pcnet32_set_multicast_list(struct net_device *dev)
 {
-    unsigned long ioaddr = dev->base_addr;
+    unsigned long ioaddr = dev->base_addr, flags;
     struct pcnet32_private *lp = dev->priv;	 
 
+    spin_lock_irqsave(&lp->lock, flags);
     if (dev->flags&IFF_PROMISC) {
 	/* Log any net taps. */
 	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
@@ -1490,6 +1493,7 @@
     lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
 
     pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
+    spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
@@ -1628,17 +1632,14 @@
     if (lp->mii) {
 	switch(cmd) {
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 	    data->phy_id = (phyaddr >> 5) & 0x1f;
 	    /* Fall Through */
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 	    lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f));
 	    data->val_out = lp->a.read_bcr (ioaddr, 34);
 	    lp->a.write_bcr (ioaddr, 33, phyaddr);
 	    return 0;
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 	    if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 	    lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f));
@@ -1651,20 +1652,28 @@
     }
     return -EOPNOTSUPP;
 }
-					    
+
 static struct pci_driver pcnet32_driver = {
-	name:		DRV_NAME,
-	probe:		pcnet32_probe_pci,
-	remove:		NULL,
-	id_table:	pcnet32_pci_tbl,
+    name:	DRV_NAME,
+    probe:	pcnet32_probe_pci,
+    id_table:	pcnet32_pci_tbl,
 };
 
 MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)");
 MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt");  
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); 
 MODULE_PARM(tx_start_pt, "i");
+MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); 
+MODULE_PARM(pcnet32vlb, "i");
+MODULE_PARM_DESC(pcnet32vlb, DRV_NAME " Vesa local bus (VLB) support (0/1)"); 
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)"); 
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)");
+
 MODULE_AUTHOR("Thomas Bogendoerfer");
 MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");
 MODULE_LICENSE("GPL");
@@ -1675,36 +1684,25 @@
 
 static int __init pcnet32_init_module(void)
 {
-    int cards_found = 0;
-    int err;
+    printk(KERN_INFO "%s", version);
 
     if (debug > 0)
 	pcnet32_debug = debug;
+
     if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
 	tx_start = tx_start_pt;
-    
-    pcnet32_dev = NULL;
+
     /* find the PCI devices */
-#define USE_PCI_REGISTER_DRIVER
-#ifdef USE_PCI_REGISTER_DRIVER
-    if ((err = pci_module_init(&pcnet32_driver)) < 0 )
-       return err;
-#else
-    {
-        struct pci_device_id *devid = pcnet32_pci_tbl;
-        for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) {
-            struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL);
-            if (pdev != NULL) {
-                if (pcnet32_probe_pci(pdev, devid) >= 0) {
-                    cards_found++;
-                }
-            }
-        }
-    }
-#endif
-    return 0;
-    /* find any remaining VLbus devices */
-    return pcnet32_probe_vlbus(cards_found);
+    pci_module_init(&pcnet32_driver);
+
+    /* should we find any remaining VLbus devices ? */
+    if (pcnet32vlb)
+	pcnet32_probe_vlbus();
+
+    if (cards_found)
+	printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
+    
+    return cards_found ? 0 : -ENODEV;
 }
 
 static void __exit pcnet32_cleanup_module(void)
@@ -1713,13 +1711,13 @@
 
     /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
     while (pcnet32_dev) {
-        struct pcnet32_private *lp = pcnet32_dev->priv;
+	struct pcnet32_private *lp = pcnet32_dev->priv;
 	next_dev = lp->next;
 	unregister_netdev(pcnet32_dev);
 	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-	if (lp->pci_dev != NULL)
+	if (lp->pci_dev)
 	    pci_unregister_driver(&pcnet32_driver);
-        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+	pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
 	kfree(pcnet32_dev);
 	pcnet32_dev = next_dev;
     }
diff -urN linux-2.4.19-pre4/drivers/net/sk98lin/skge.c linux-2.4.19-pre5/drivers/net/sk98lin/skge.c
--- linux-2.4.19-pre4/drivers/net/sk98lin/skge.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.19-pre5/drivers/net/sk98lin/skge.c	Fri Mar 29 14:49:41 2002
@@ -541,6 +541,48 @@
 
 		boards_found++;
 
+		/* More then one port found */
+		if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+			if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) {
+				printk(KERN_ERR "Unable to allocate etherdev "
+					"structure!\n");
+				break;
+			}
+
+			pAC->dev[1] = dev;
+			pNet = dev->priv;
+			pNet->PortNr = 1;
+			pNet->NetNr = 1;
+			pNet->pAC = pAC;
+			pNet->Mtu = 1500;
+			pNet->Up = 0;
+
+			dev->open =		&SkGeOpen;
+			dev->stop =		&SkGeClose;
+			dev->hard_start_xmit =	&SkGeXmit;
+			dev->get_stats =	&SkGeStats;
+			dev->set_multicast_list = &SkGeSetRxMode;
+			dev->set_mac_address =	&SkGeSetMacAddr;
+			dev->do_ioctl =		&SkGeIoctl;
+			dev->change_mtu =	&SkGeChangeMtu;
+
+			pProcFile = create_proc_entry(dev->name, 
+				S_IFREG | 0444, pSkRootDir);
+			pProcFile->read_proc = proc_read;
+			pProcFile->write_proc = NULL;
+			pProcFile->nlink = 1;
+			pProcFile->size = sizeof(dev->name+1);
+			pProcFile->data = (void*)pProcFile;
+
+			memcpy((caddr_t) &dev->dev_addr,
+			(caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6);
+	
+			printk("%s: %s\n", dev->name, pAC->DeviceStr);
+			printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+		
+		}
+
+
 		/*
 		 * This is bollocks, but we need to tell the net-init
 		 * code that it shall go for the next device.
diff -urN linux-2.4.19-pre4/drivers/net/smc-ultra.c linux-2.4.19-pre5/drivers/net/smc-ultra.c
--- linux-2.4.19-pre4/drivers/net/smc-ultra.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre5/drivers/net/smc-ultra.c	Fri Mar 29 14:49:41 2002
@@ -501,8 +501,10 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
-MODULE_PARM_DESC(io, "SMC Ultra I/O base address(es)");
-MODULE_PARM_DESC(irq, "SMC Ultra IRQ number(s) (assigned)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver");
+MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
 
@@ -557,7 +559,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 
diff -urN linux-2.4.19-pre4/drivers/net/smc-ultra32.c linux-2.4.19-pre5/drivers/net/smc-ultra32.c
--- linux-2.4.19-pre4/drivers/net/smc-ultra32.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre5/drivers/net/smc-ultra32.c	Fri Mar 29 14:49:41 2002
@@ -379,6 +379,9 @@
 #define MAX_ULTRA32_CARDS   4	/* Max number of Ultra cards per module */
 static struct net_device dev_ultra[MAX_ULTRA32_CARDS];
 
+MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	int this_dev, found = 0;
@@ -415,5 +418,4 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
diff -urN linux-2.4.19-pre4/drivers/net/sungem.c linux-2.4.19-pre5/drivers/net/sungem.c
--- linux-2.4.19-pre4/drivers/net/sungem.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/sungem.c	Fri Mar 29 14:49:41 2002
@@ -1,7 +1,7 @@
 /* $Id: sungem.c,v 1.44.2.22 2002/03/13 01:18:12 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
- * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com)
  * 
  * Support for Apple GMAC and assorted PHYs by
  * Benjamin Herrenscmidt (benh@kernel.crashing.org)
@@ -40,6 +40,7 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/crc32.h>
+#include <linux/random.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -69,8 +70,8 @@
 			 NETIF_MSG_LINK)
 
 #define DRV_NAME	"sungem"
-#define DRV_VERSION	"0.96"
-#define DRV_RELDATE	"11/17/01"
+#define DRV_VERSION	"0.97"
+#define DRV_RELDATE	"3/20/02"
 #define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
 
 static char version[] __devinitdata =
@@ -2761,13 +2762,74 @@
 	return rc;
 }
 
+#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC))
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr)
+{
+	int this_offset;
+
+	for (this_offset = 0x20; this_offset < len; this_offset++) {
+		void *p = rom_base + this_offset;
+		int i;
+
+		if (readb(p + 0) != 0x90 ||
+		    readb(p + 1) != 0x00 ||
+		    readb(p + 2) != 0x09 ||
+		    readb(p + 3) != 0x4e ||
+		    readb(p + 4) != 0x41 ||
+		    readb(p + 5) != 0x06)
+			continue;
+
+		this_offset += 6;
+		p += 6;
+
+		for (i = 0; i < 6; i++)
+			dev_addr[i] = readb(p + i);
+		break;
+	}
+}
+
+static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+	u32 rom_reg_orig;
+	void *p;
+
+	if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+		if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+			goto use_random;
+	}
+
+	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+	pci_write_config_dword(pdev, pdev->rom_base_reg,
+			       rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+	p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+	if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+		find_eth_addr_in_vpd(p, (64 * 1024), dev_addr);
+
+	if (p != NULL)
+		iounmap(p);
+
+	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+	return;
+
+use_random:
+	/* Sun MAC prefix then 3 random bytes. */
+	dev_addr[0] = 0x08;
+	dev_addr[1] = 0x00;
+	dev_addr[2] = 0x20;
+	get_random_bytes(dev_addr, 3);
+	return;
+}
+#endif /* not Sparc and not PPC */
+
 static int __devinit gem_get_device_address(struct gem *gp)
 {
 #if defined(__sparc__) || defined(CONFIG_ALL_PPC)
 	struct net_device *dev = gp->dev;
 #endif
 
-#ifdef __sparc__
+#if defined(__sparc__)
 	struct pci_dev *pdev = gp->pdev;
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	int node = -1;
@@ -2782,8 +2844,7 @@
 	}
 	if (node == -1)
 		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#endif
-#ifdef CONFIG_ALL_PPC
+#elif defined(CONFIG_ALL_PPC)
 	unsigned char *addr;
 
 	addr = get_property(gp->of_node, "local-mac-address", NULL);
@@ -2793,6 +2854,8 @@
 		return -1;
 	}
 	memcpy(dev->dev_addr, addr, MAX_ADDR_LEN);
+#else
+	get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr);
 #endif
 	return 0;
 }
@@ -2855,21 +2918,21 @@
 		return -ENODEV;
 	}
 
-	dev = init_etherdev(NULL, sizeof(*gp));
+	dev = alloc_etherdev(sizeof(*gp));
 	if (!dev) {
-		printk(KERN_ERR PFX "Etherdev init failed, aborting.\n");
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
 
-	if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) {
-		printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, "
-		       "aborting.\n", gemreg_base, gemreg_len);
+	gp = dev->priv;
+
+	if (pci_request_regions(pdev, dev->name)) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+		       "aborting.\n");
 		goto err_out_free_netdev;
 	}
 
-	gp = dev->priv;
-
 	gp->pdev = pdev;
 	dev->base_addr = (long) pdev;
 	gp->dev = dev;
@@ -2902,7 +2965,7 @@
 	if (gp->regs == 0UL) {
 		printk(KERN_ERR PFX "Cannot map device registers, "
 		       "aborting.\n");
-		goto err_out_free_mmio_res;
+		goto err_out_free_res;
 	}
 
 	/* On Apple, we power the chip up now in order for check
@@ -2938,22 +3001,28 @@
 		goto err_out_iounmap;
 	}
 
-	pci_set_drvdata(pdev, dev);
-
-	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
-	       dev->name);
-
 #ifdef CONFIG_ALL_PPC
 	gp->of_node = pci_device_to_OF_node(pdev);
 #endif	
 	if (gem_get_device_address(gp))
-		goto err_out_iounmap;
+		goto err_out_free_consistent;
+
+	if (register_netdev(dev)) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_free_consistent;
+	}
+
+	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
+	       dev->name);
 
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
 		       i == 5 ? ' ' : ':');
 	printk("\n");
 
+	pci_set_drvdata(pdev, dev);
+
 	dev->open = gem_open;
 	dev->stop = gem_close;
 	dev->hard_start_xmit = gem_start_xmit;
@@ -2977,6 +3046,12 @@
 
 	return 0;
 
+err_out_free_consistent:
+	pci_free_consistent(pdev,
+			    sizeof(struct gem_init_block),
+			    gp->init_block,
+			    gp->gblock_dvma);
+
 err_out_iounmap:
 	down(&gp->pm_sem);
 	/* Stop the PM timer & task */
@@ -2985,13 +3060,13 @@
 	if (gp->hw_running)
 		gem_shutdown(gp);
 	up(&gp->pm_sem);
+
 	iounmap((void *) gp->regs);
 
-err_out_free_mmio_res:
-	release_mem_region(gemreg_base, gemreg_len);
+err_out_free_res:
+	pci_release_regions(pdev);
 
 err_out_free_netdev:
-	unregister_netdev(dev);
 	kfree(dev);
 
 	return -ENODEV;
@@ -3020,8 +3095,7 @@
 				    gp->init_block,
 				    gp->gblock_dvma);
 		iounmap((void *) gp->regs);
-		release_mem_region(pci_resource_start(pdev, 0),
-				   pci_resource_len(pdev, 0));
+		pci_release_regions(pdev);
 		kfree(dev);
 
 		pci_set_drvdata(pdev, NULL);
diff -urN linux-2.4.19-pre4/drivers/net/sunhme.c linux-2.4.19-pre5/drivers/net/sunhme.c
--- linux-2.4.19-pre4/drivers/net/sunhme.c	Fri Mar 29 14:49:09 2002
+++ linux-2.4.19-pre5/drivers/net/sunhme.c	Fri Mar 29 14:49:41 2002
@@ -3,7 +3,7 @@
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
  *
- * Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1998, 1999, 2002 David S. Miller (davem@redhat.com)
  *
  * Changes :
  * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -14,7 +14,7 @@
  */
 
 static char version[] =
-        "sunhme.c:v1.99 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+        "sunhme.c:v2.00 20/Mar/2002 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
 
@@ -34,6 +34,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/crc32.h>
+#include <linux/random.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1611,12 +1612,12 @@
 
 	/* Set the RX and TX ring ptrs. */
 	HMD(("ring ptrs rxr[%08x] txr[%08x]\n",
-	     (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)),
-	     (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))));
+	     ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)),
+	     ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))));
 	hme_write32(hp, erxregs + ERX_RING,
-		    (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)));
+		    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)));
 	hme_write32(hp, etxregs + ETX_RING,
-		    (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
+		    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
 
 	/* Set the supported burst sizes. */
 	HMD(("happy_meal_init: old[%08x] bursts<",
@@ -2643,33 +2644,28 @@
 	struct happy_meal *hp;
 	struct net_device *dev;
 	int i, qfe_slot = -1;
+	int err = -ENODEV;
 
 	if (is_qfe) {
 		qp = quattro_sbus_find(sdev);
 		if (qp == NULL)
-			return -ENODEV;
+			goto err_out;
 		for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
 			if (qp->happy_meals[qfe_slot] == NULL)
 				break;
 		if (qfe_slot == 4)
-			return -ENODEV;
+			goto err_out;
 	}
 
-	dev = init_etherdev(NULL, sizeof(struct happy_meal));
+	err = -ENOMEM;
+	dev = alloc_etherdev(sizeof(struct happy_meal));
 	if (!dev)
-		return -ENOMEM;
+		goto err_out;
 	SET_MODULE_OWNER(dev);
 
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	if (qfe_slot != -1)
-		printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
-		       dev->name, qfe_slot);
-	else
-		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
-		       dev->name);
-
 	/* If user did not specify a MAC address specifically, use
 	 * the Quattro local-mac-address property...
 	 */
@@ -2680,6 +2676,7 @@
 	if (i < 6) { /* a mac address was given */
 		for (i = 0; i < 6; i++)
 			dev->dev_addr[i] = macaddr[i];
+		macaddr[5]++;
 	} else if (qfe_slot != -1 &&
 		   prom_getproplen(sdev->prom_node,
 				   "local-mac-address") == 6) {
@@ -2689,11 +2686,6 @@
 		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
 	}
 
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c",
-		       dev->dev_addr[i], i == 5 ? ' ' : ':');
-	printk("\n");
-
 	hp = dev->priv;
 	memset(hp, 0, sizeof(*hp));
 
@@ -2701,11 +2693,12 @@
 
 	spin_lock_init(&hp->happy_lock);
 
+	err = -ENODEV;
 	if (sdev->num_registers != 5) {
 		printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
 		       sdev->num_registers);
 		printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
-		return -ENODEV;
+		goto err_out_free_netdev;
 	}
 
 	if (qp != NULL) {
@@ -2719,35 +2712,35 @@
 				 GREG_REG_SIZE, "HME Global Regs");
 	if (!hp->gregs) {
 		printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
-		return -ENODEV;
+		goto err_out_free_netdev;
 	}
 
 	hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
 				   ETX_REG_SIZE, "HME TX Regs");
 	if (!hp->etxregs) {
 		printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
-		return -ENODEV;
+		goto err_out_iounmap;
 	}
 
 	hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
 				   ERX_REG_SIZE, "HME RX Regs");
 	if (!hp->erxregs) {
 		printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
-		return -ENODEV;
+		goto err_out_iounmap;
 	}
 
 	hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
 				      BMAC_REG_SIZE, "HME BIGMAC Regs");
 	if (!hp->bigmacregs) {
 		printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
-		return -ENODEV;
+		goto err_out_iounmap;
 	}
 
 	hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
 				   TCVR_REG_SIZE, "HME Tranceiver Regs");
 	if (!hp->tcvregs) {
 		printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
-		return -ENODEV;
+		goto err_out_iounmap;
 	}
 
 	hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
@@ -2770,6 +2763,11 @@
 	hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
 						PAGE_SIZE,
 						&hp->hblock_dvma);
+	err = -ENOMEM;
+	if (!hp->happy_block) {
+		printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
+		goto err_out_iounmap;
+	}
 
 	/* Force check of the link first time we are brought up. */
 	hp->linkcheck = 0;
@@ -2812,20 +2810,157 @@
 	 */
 	happy_meal_set_initial_advertisement(hp);
 
-	ether_setup(dev);
+	if (register_netdev(hp->dev)) {
+		printk(KERN_ERR "happymeal: Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_free_consistent;
+	}
+
+	if (qfe_slot != -1)
+		printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
+		       dev->name, qfe_slot);
+	else
+		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
+		       dev->name);
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c",
+		       dev->dev_addr[i], i == 5 ? ' ' : ':');
+	printk("\n");
 
 	/* We are home free at this point, link us in to the happy
 	 * device list.
 	 */
-	dev->ifindex = dev_new_index();
 	hp->next_module = root_happy_dev;
 	root_happy_dev = hp;
 
 	return 0;
+
+err_out_free_consistent:
+	sbus_free_consistent(hp->happy_dev,
+			     PAGE_SIZE,
+			     hp->happy_block,
+			     hp->hblock_dvma);
+
+err_out_iounmap:
+	if (hp->gregs)
+		sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+	if (hp->etxregs)
+		sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+	if (hp->erxregs)
+		sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+	if (hp->bigmacregs)
+		sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+	if (hp->tcvregs)
+		sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+
+err_out_free_netdev:
+	kfree(dev);
+
+err_out:
+	return err;
 }
 #endif
 
 #ifdef CONFIG_PCI
+#ifndef __sparc__
+static int is_quattro_p(struct pci_dev *pdev)
+{
+	struct pci_dev *busdev = pdev->bus->self;
+	struct list_head *tmp;
+	int n_hmes;
+
+	if (busdev->vendor != PCI_VENDOR_ID_DEC ||
+	    busdev->device != PCI_DEVICE_ID_DEC_21153)
+		return 0;
+
+	n_hmes = 0;
+	tmp = pdev->bus->devices.next;
+	while (tmp != &pdev->bus->devices) {
+		struct pci_dev *this_pdev = pci_dev_b(tmp);
+
+		if (this_pdev->vendor == PCI_VENDOR_ID_SUN &&
+		    this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL)
+			n_hmes++;
+
+		tmp = tmp->next;
+	}
+
+	if (n_hmes != 4)
+		return 0;
+
+	return 1;
+}
+
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, int index, unsigned char *dev_addr)
+{
+	int this_offset;
+
+	for (this_offset = 0x20; this_offset < len; this_offset++) {
+		void *p = rom_base + this_offset;
+
+		if (readb(p + 0) != 0x90 ||
+		    readb(p + 1) != 0x00 ||
+		    readb(p + 2) != 0x09 ||
+		    readb(p + 3) != 0x4e ||
+		    readb(p + 4) != 0x41 ||
+		    readb(p + 5) != 0x06)
+			continue;
+
+		this_offset += 6;
+		p += 6;
+
+		if (index == 0) {
+			int i;
+
+			for (i = 0; i < 6; i++)
+				dev_addr[i] = readb(p + i);
+			break;
+		}
+		index--;
+	}
+}
+
+static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+	u32 rom_reg_orig;
+	void *p;
+	int index;
+
+	index = 0;
+	if (is_quattro_p(pdev))
+		index = PCI_SLOT(pdev->devfn);
+
+	if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+		if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+			goto use_random;
+	}
+
+	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+	pci_write_config_dword(pdev, pdev->rom_base_reg,
+			       rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+	p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+	if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+		find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr);
+
+	if (p != NULL)
+		iounmap(p);
+
+	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+	return;
+
+use_random:
+	/* Sun MAC prefix then 3 random bytes. */
+	dev_addr[0] = 0x08;
+	dev_addr[1] = 0x00;
+	dev_addr[2] = 0x20;
+	get_random_bytes(dev_addr, 3);
+	return;
+}
+#endif /* !(__sparc__) */
+
 static int __init happy_meal_pci_init(struct pci_dev *pdev)
 {
 	struct quattro *qp = NULL;
@@ -2838,6 +2973,7 @@
 	unsigned long hpreg_base;
 	int i, qfe_slot = -1;
 	char prom_name[64];
+	int err;
 
 	/* Now make sure pci_dev cookie is there. */
 #ifdef __sparc__
@@ -2850,52 +2986,33 @@
 	
 	prom_getstring(node, "name", prom_name, sizeof(prom_name));
 #else
-/* This needs to be corrected... -DaveM */
-	strcpy(prom_name, "qfe");
+	if (is_quattro_p(pdev))
+		strcpy(prom_name, "SUNW,qfe");
+	else
+		strcpy(prom_name, "SUNW,hme");
 #endif
 
+	err = -ENODEV;
 	if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) {
 		qp = quattro_pci_find(pdev);
 		if (qp == NULL)
-			return -ENODEV;
+			goto err_out;
 		for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
 			if (qp->happy_meals[qfe_slot] == NULL)
 				break;
 		if (qfe_slot == 4)
-			return -ENODEV;
+			goto err_out;
 	}
 
-	dev = init_etherdev(NULL, sizeof(struct happy_meal));
+	dev = alloc_etherdev(sizeof(struct happy_meal));
+	err = -ENOMEM;
 	if (!dev)
-		return -ENOMEM;
+		goto err_out;
 	SET_MODULE_OWNER(dev);
 
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	if (!qfe_slot) {
-		struct pci_dev *qpdev = qp->quattro_dev;
-
-		prom_name[0] = 0;
-		if (!strncmp(dev->name, "eth", 3)) {
-			int i = simple_strtoul(dev->name + 3, NULL, 10);
-			sprintf(prom_name, "-%d", i + 3);
-		}
-		printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
-		if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
-		    qpdev->device == PCI_DEVICE_ID_DEC_21153)
-			printk("DEC 21153 PCI Bridge\n");
-		else
-			printk("unknown bridge %04x.%04x\n", 
-				qpdev->vendor, qpdev->device);
-	}
-	if (qfe_slot != -1)
-		printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
-		       dev->name, qfe_slot);
-	else
-		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
-		       dev->name);
-
 	dev->base_addr = (long) pdev;
 
 	hp = (struct happy_meal *)dev->priv;
@@ -2912,13 +3029,20 @@
 	}		
 
 	hpreg_base = pci_resource_start(pdev, 0);
+	err = -ENODEV;
 	if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) {
 		printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
-		return -ENODEV;
+		goto err_out_clear_quattro;
 	}
+	if (pci_request_regions(pdev, dev->name)) {
+		printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, "
+		       "aborting.\n");
+		goto err_out_clear_quattro;
+	}
+
 	if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) {
 		printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n");
-		return -ENODEV;
+		goto err_out_free_res;
 	}
 
 	for (i = 0; i < 6; i++) {
@@ -2928,6 +3052,7 @@
 	if (i < 6) { /* a mac address was given */
 		for (i = 0; i < 6; i++)
 			dev->dev_addr[i] = macaddr[i];
+		macaddr[5]++;
 	} else {
 #ifdef __sparc__
 		if (qfe_slot != -1 &&
@@ -2938,15 +3063,10 @@
 			memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
 		}
 #else
-		memset(dev->dev_addr, 0, 6);
+		get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
 #endif
 	}
 	
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
-	printk("\n");
-
 	/* Layout registers. */
 	hp->gregs      = (hpreg_base + 0x0000UL);
 	hp->etxregs    = (hpreg_base + 0x2000UL);
@@ -2983,9 +3103,10 @@
 	hp->happy_block = (struct hmeal_init_block *)
 		pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
 
+	err = -ENODEV;
 	if (!hp->happy_block) {
 		printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n");
-		return -ENODEV;
+		goto err_out_iounmap;
 	}
 
 	hp->linkcheck = 0;
@@ -3024,16 +3145,63 @@
 	 */
 	happy_meal_set_initial_advertisement(hp);
 
-	ether_setup(dev);
+	if (register_netdev(hp->dev)) {
+		printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	if (!qfe_slot) {
+		struct pci_dev *qpdev = qp->quattro_dev;
+
+		prom_name[0] = 0;
+		if (!strncmp(dev->name, "eth", 3)) {
+			int i = simple_strtoul(dev->name + 3, NULL, 10);
+			sprintf(prom_name, "-%d", i + 3);
+		}
+		printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
+		if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
+		    qpdev->device == PCI_DEVICE_ID_DEC_21153)
+			printk("DEC 21153 PCI Bridge\n");
+		else
+			printk("unknown bridge %04x.%04x\n", 
+				qpdev->vendor, qpdev->device);
+	}
+
+	if (qfe_slot != -1)
+		printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
+		       dev->name, qfe_slot);
+	else
+		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
+		       dev->name);
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
+
+	printk("\n");
 
 	/* We are home free at this point, link us in to the happy
 	 * device list.
 	 */
-	dev->ifindex = dev_new_index();
 	hp->next_module = root_happy_dev;
 	root_happy_dev = hp;
 
 	return 0;
+
+err_out_iounmap:
+	iounmap((void *)hp->gregs);
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out_clear_quattro:
+	if (qp != NULL)
+		qp->happy_meals[qfe_slot] = NULL;
+
+	kfree(dev);
+
+err_out:
+	return err;
 }
 #endif
 
@@ -3080,6 +3248,7 @@
 				       PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
 		if (pci_enable_device(pdev))
 			continue;
+		pci_set_master(pdev);
 		cards++;
 		happy_meal_pci_init(pdev);
 	}
@@ -3120,12 +3289,18 @@
 	while (root_happy_dev) {
 		struct happy_meal *hp = root_happy_dev;
 		struct happy_meal *next = root_happy_dev->next_module;
+		struct net_device *dev = hp->dev;
+
+		/* Unregister netdev before unmapping registers as this
+		 * call can end up trying to access those registers.
+		 */
+		unregister_netdev(dev);
 
 #ifdef CONFIG_SBUS
 		if (!(hp->happy_flags & HFLAG_PCI)) {
 			if (hp->happy_flags & HFLAG_QUATTRO) {
 				if (hp->qfe_parent != last_seen_qfe) {
-					free_irq(hp->dev->irq, hp->qfe_parent);
+					free_irq(dev->irq, hp->qfe_parent);
 					last_seen_qfe = hp->qfe_parent;
 				}
 			}
@@ -3148,12 +3323,35 @@
 					    hp->happy_block,
 					    hp->hblock_dvma);
 			iounmap((void *)hp->gregs);
+			pci_release_regions(hp->happy_dev);
 		}
 #endif
-		unregister_netdev(hp->dev);
-		kfree(hp->dev);
+		kfree(dev);
+
 		root_happy_dev = next;
 	}
+
+	/* Now cleanup the quattro lists. */
+#ifdef CONFIG_SBUS
+	while (qfe_sbus_list) {
+		struct quattro *qfe = qfe_sbus_list;
+		struct quattro *next = qfe->next;
+
+		kfree(qfe);
+
+		qfe_sbus_list = next;
+	}
+#endif
+#ifdef CONFIG_PCI
+	while (qfe_pci_list) {
+		struct quattro *qfe = qfe_pci_list;
+		struct quattro *next = qfe->next;
+
+		kfree(qfe);
+
+		qfe_pci_list = next;
+	}
+#endif
 }
 
 module_init(happy_meal_probe);
diff -urN linux-2.4.19-pre4/drivers/net/sunhme.h linux-2.4.19-pre5/drivers/net/sunhme.h
--- linux-2.4.19-pre4/drivers/net/sunhme.h	Tue Aug  7 08:30:50 2001
+++ linux-2.4.19-pre5/drivers/net/sunhme.h	Fri Mar 29 14:49:42 2002
@@ -431,7 +431,7 @@
 	unsigned long	bigmacregs;     /* BIGMAC core regs		     */
 	unsigned long	tcvregs;        /* MIF transceiver regs              */
 
-	__u32                     hblock_dvma;    /* DVMA visible address happy block  */
+	dma_addr_t                hblock_dvma;    /* DVMA visible address happy block  */
 	unsigned int              happy_flags;    /* Driver state flags                */
 	enum happy_transceiver    tcvr_type;      /* Kind of transceiver in use        */
 	unsigned int              happy_bursts;   /* Get your mind out of the gutter   */
diff -urN linux-2.4.19-pre4/drivers/net/wan/comx-hw-munich.c linux-2.4.19-pre5/drivers/net/wan/comx-hw-munich.c
--- linux-2.4.19-pre4/drivers/net/wan/comx-hw-munich.c	Fri Mar 29 14:49:10 2002
+++ linux-2.4.19-pre5/drivers/net/wan/comx-hw-munich.c	Fri Mar 29 14:49:42 2002
@@ -1397,15 +1397,6 @@
     return;
 }
 
-void free_stuff(munich_board_t *board, struct comx_channel *ch)
-{
-/* Free CCB and the interrupt queues */
-    if (board->ccb) kfree((void *)board->ccb);
-    if (board->tiq) kfree((void *)board->tiq);
-    if (board->riq) kfree((void *)board->riq);
-    if (board->piq) kfree((void *)board->piq);
-}
-
 /* 
  * Hardware open routine.
  * Called by comx (upper) layer when the user wants to bring up the interface
@@ -1488,7 +1479,6 @@
 	if (board->tiq == NULL)
 	{
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENOMEM;
 	}
 	memset((void *)board->tiq, 0, MUNICH_INTQSIZE);
@@ -1497,7 +1487,6 @@
 	if (board->riq == NULL)
 	{
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENOMEM;
 	}
 	memset((void *)board->riq, 0, MUNICH_INTQSIZE);
@@ -1506,7 +1495,6 @@
 	if (board->piq == NULL)
 	{
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENOMEM;
 	}
 	memset((void *)board->piq, 0, MUNICH_PIQSIZE);
@@ -1527,7 +1515,6 @@
 		   board->pci->irq);
 	    /* TOD: free other resources (a sok malloc feljebb)                     */
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -EAGAIN;
 	}
 	board->irq = board->pci->irq;	/* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */
@@ -1597,7 +1584,6 @@
 	    free_irq(board->irq, (void *)board);	/* TOD: free other resources too *//* maybe shut down hw? */
 	    board->irq = 0;
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -EAGAIN;
 	}
 	else if (!(stat & STAT_PCMA))
@@ -1608,7 +1594,6 @@
 	    free_irq(board->irq, (void *)board);	/* TOD: free other resources too *//* maybe shut off the hw? */
 	    board->irq = 0;
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -EIO;
 	}
 
@@ -1670,7 +1655,7 @@
     spin_unlock_irqrestore(&mister_lock, flags);
 
     dev->irq = board->irq;	/* hogy szep legyen az ifconfig outputja */
-    ccb = board->ccb;		/* TOD: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
+    ccb = board->ccb;		/* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
 
     spin_lock_irqsave(&mister_lock, flags);
 
@@ -1680,13 +1665,12 @@
     /* Check if the selected timeslots aren't used already */
 
     for (i = 0; i < 32; i++)
-	if (((1 << i) & timeslots) && ccb->timeslot_spec[i].tti == 0)
+	if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti)
 	{
 	    printk("MUNICH_open: %s: timeslot %d already used by %s\n",
 		   dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name);
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
-	    return -EBUSY;	/* TOD: lehet hogy valami mas errno kellene? */
+	    return -EBUSY;	/* TODO: lehet hogy valami mas errno kellene? */
 	}
 
     /* find a free channel: */
@@ -1700,7 +1684,6 @@
 		("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n",
 		 dev->name);
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENODEV;
 	}
 	if (board->twins[channel] == NULL)
@@ -1998,7 +1981,7 @@
 
     spin_lock_irqsave(&mister_lock, flags);
 
-    board->use_count--;
+    if (board->use_count) board->use_count--;
 
     if (!board->use_count)	/* we were the last user of the board */
     {
@@ -2020,7 +2003,12 @@
 	    free_irq(board->irq, (void *)board);	/* Ha nem inicializalta magat, akkor meg nincs irq */
 	board->irq = 0;
 
-	free_stuff(board, ch);
+	/* Free CCB and the interrupt queues */
+	if (board->ccb) kfree((void *)board->ccb);
+	if (board->tiq) kfree((void *)board->tiq);
+	if (board->riq) kfree((void *)board->riq);
+	if (board->piq) kfree((void *)board->piq);
+	board->ccb = board->tiq = board->riq = board->piq = NULL;
     }
 
     /* Enable setting of hw parameters */
diff -urN linux-2.4.19-pre4/drivers/net/wd.c linux-2.4.19-pre5/drivers/net/wd.c
--- linux-2.4.19-pre4/drivers/net/wd.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre5/drivers/net/wd.c	Fri Mar 29 14:49:42 2002
@@ -97,7 +97,7 @@
 			return -EBUSY;
 		i = wd_probe1(dev, base_addr);
 		if (i != 0)  
-			release_resource(r);
+			release_region(base_addr, WD_IO_EXTENT);
 		else
 			r->name = dev->name;
 		return i;
@@ -114,7 +114,7 @@
 			r->name = dev->name;
 			return 0;
 		}
-		release_resource(r);
+		release_region(ioaddr, WD_IO_EXTENT);
 	}
 
 	return -ENODEV;
@@ -450,10 +450,11 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
 MODULE_PARM(mem_end, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
-MODULE_PARM_DESC(io, "WD80x3 I/O base address(es)");
-MODULE_PARM_DESC(irq, "WD80x3 IRQ number(s) (ignored for PureData boards)");
-MODULE_PARM_DESC(mem, "WD80x3 memory base address(es)(ignored for PureData boards)");
-MODULE_PARM_DESC(mem_end, "WD80x3 memory end address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
+MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
+MODULE_PARM_DESC(mem_end, "memory end address(es)");
+MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
 MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
diff -urN linux-2.4.19-pre4/drivers/net/wireless/orinoco_plx.c linux-2.4.19-pre5/drivers/net/wireless/orinoco_plx.c
--- linux-2.4.19-pre4/drivers/net/wireless/orinoco_plx.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.19-pre5/drivers/net/wireless/orinoco_plx.c	Fri Mar 29 14:49:42 2002
@@ -385,18 +385,17 @@
 	{0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},	/* Reported working, but unknown */
 	{0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},	/* Linksys WDT11 */
 	{0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},	/* USR 2415 */
+	{0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, 	/* Belkin F5D6000 */
 	{0,},
 };
 
 MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
 
 static struct pci_driver orinoco_plx_driver = {
-	name:"orinoco_plx",
-	id_table:orinoco_plx_pci_id_table,
-	probe:orinoco_plx_init_one,
-	remove:__devexit_p(orinoco_plx_remove_one),
-	suspend:0,
-	resume:0
+	name:		"orinoco_plx",
+	id_table:	orinoco_plx_pci_id_table,
+	probe:		orinoco_plx_init_one,
+	remove:		__devexit_p(orinoco_plx_remove_one),
 };
 
 static int __init orinoco_plx_init(void)
diff -urN linux-2.4.19-pre4/drivers/pci/gen-devlist.c linux-2.4.19-pre5/drivers/pci/gen-devlist.c
--- linux-2.4.19-pre4/drivers/pci/gen-devlist.c	Sun Nov  4 09:31:58 2001
+++ linux-2.4.19-pre5/drivers/pci/gen-devlist.c	Fri Mar 29 14:49:43 2002
@@ -1,7 +1,7 @@
 /*
  *	Generate devlist.h and classlist.h from the PCI ID file.
  *
- *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *	(c) 1999--2002 Martin Mares <mj@ucw.cz>
  */
 
 #include <stdio.h>
@@ -15,8 +15,13 @@
 	while (*c) {
 		if (*c == '"')
 			fprintf(f, "\\\"");
-		else
+		else {
 			fputc(*c, f);
+			if (*c == '?' && c[1] == '?') {
+				/* Avoid trigraphs */
+				fprintf(f, "\" \"");
+			}
+		}
 		c++;
 	}
 }
diff -urN linux-2.4.19-pre4/drivers/pci/pci.ids linux-2.4.19-pre5/drivers/pci/pci.ids
--- linux-2.4.19-pre4/drivers/pci/pci.ids	Fri Mar 29 14:49:10 2002
+++ linux-2.4.19-pre5/drivers/pci/pci.ids	Fri Mar 29 14:49:43 2002
@@ -7,7 +7,7 @@
 #	so if you have anything to contribute, please visit the home page or
 #	send a diff -u against the most recent pci.ids to pci-ids@ucw.cz.
 #
-#	$Id: pci.ids,v 1.24 2001/10/28 21:55:26 mares Exp $
+#	$Id: pci.ids,v 1.39 2002/03/23 14:58:55 mares Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
@@ -26,6 +26,10 @@
 0675  Dynalink
 	1700  IS64PH ISDN Adapter
 	1702  IS64PH ISDN Adapter
+# Wrong ID used in subsystem ID of VIA USB controllers.
+0925  VIA Technologies, Inc. (Wrong ID)
+09c1  Arris
+	0704  CM 200E Cable Modem
 0a89  BREA Technologies Inc
 0e11  Compaq Computer Corporation
 	0001  PCI to EISA Bridge
@@ -47,7 +51,7 @@
 	a0f7  PCI Hotplug Controller
 		8086 002a  PCI Hotplug Controller A
 		8086 002b  PCI Hotplug Controller B
-	a0f8  USB Open Host Controller
+	a0f8  ZFMicro Chipset USB
 	a0fc  Fibre Channel Host Controller
 	ae10  Smart-2/P RAID Controller
 		0e11 4030  Smart-2/P Array Controller
@@ -69,28 +73,10 @@
 	ae6d  NorthStar CPU to PCI Bridge
 	b011  Integrated Netelligent 10/100
 	b012  Netelligent 10 T/2
-	b01e  NC3120 Fast Ethernet NIC
-	b01f  NC3122 Fast Ethernet NIC
 	b02f  NC1120 Ethernet NIC
 	b030  Netelligent WS 5100
-	b04a  10/100 TX PCI Intel WOL UTP Controller
 	b060  Smart Array 5300 Controller
-	b0c6  NC3161 Fast Ethernet NIC
-	b0c7  NC3160 Fast Ethernet NIC
-	b0d7  NC3121 Fast Ethernet NIC
-	b0dd  NC3131 Fast Ethernet NIC
-	b0de  NC3132 Fast Ethernet Module
-	b0df  NC6132 Gigabit Module
-	b0e0  NC6133 Gigabit Module
-	b0e1  NC3133 Fast Ethernet Module
-	b123  NC6134 Gigabit NIC
-	b134  NC3163 Fast Ethernet NIC
-	b13c  NC3162 Fast Ethernet NIC
-	b144  NC3123 Fast Ethernet NIC
-	b163  NC3134 Fast Ethernet NIC
-	b164  NC3135 Fast Ethernet Upgrade Module
 	b178  Smart Array 5i/532
-	b1a4  NC7131 Gigabit Server Adapter
 	f130  NetFlex-3/P ThunderLAN 1.0
 	f150  NetFlex-3/P ThunderLAN 2.3
 1000  LSI Logic / Symbios Logic (formerly NCR)
@@ -109,6 +95,9 @@
 		0e11 7004  Embedded Ultra Wide SCSI Controller
 		1092 8760  FirePort 40 Dual SCSI Controller
 		1de1 3904  DC390F Ultra Wide SCSI Controller
+	0010  53c895
+		0e11 4040  Integrated Array Controller
+		0e11 4048  Integrated Array Controller
 	0012  53c895a
 	0020  53c1010 Ultra3 SCSI Adapter
 	0021  53c1010 66MHz  Ultra3 SCSI Adapter
@@ -122,7 +111,11 @@
 	0623  FC929 LAN
 	0624  FC919
 	0625  FC919 LAN
-	0701  83C885
+	0626  FC929X
+	0627  FC929X LAN
+	0628  FC919X
+	0629  FC919X LAN
+	0701  83C885 NT50 DigitalScape Fast Ethernet
 	0702  Yellowfin G-NIC gigabit ethernet
 		1318 0000  PEI100X
 	0901  61C102
@@ -139,28 +132,65 @@
 	9100  INI-9100/9100W SCSI Host
 1002  ATI Technologies Inc
 	4158  68800AX [Mach32]
+	4242  Radeon 8500 DV
+		1002 02aa  Radeon 8500 AIW DV Edition
 	4354  215CT [Mach64 CT]
 	4358  210888CX [Mach64 CX]
 	4554  210888ET [Mach64 ET]
 	4654  Mach64 VT
 	4742  3D Rage Pro AGP 1X/2X
+		1002 0040  Rage Pro Turbo AGP 2X
+		1002 0044  Rage Pro Turbo AGP 2X
+		1002 0061  Rage Pro AIW AGP 2X
+		1002 0062  Rage Pro AIW AGP 2X
+		1002 0063  Rage Pro AIW AGP 2X
+		1002 0080  Rage Pro Turbo AGP 2X
+		1002 0084  Rage Pro Turbo AGP 2X
+		1002 4742  Rage Pro Turbo AGP 2X
+		1002 8001  Rage Pro Turbo AGP 2X
+		1028 0082  Rage Pro Turbo AGP 2X
 		1028 4082  Optiplex GX1 Onboard Display Adapter
-		8086 4152  Rage 3D Pro AGP
+		1028 8082  Rage Pro Turbo AGP 2X
+		1028 c082  Rage Pro Turbo AGP 2X
+		8086 4152  Xpert 98D AGP 2X
+		8086 464a  Rage Pro Turbo AGP 2X
 	4744  3D Rage Pro AGP 1X
+		1002 4744  Rage Pro Turbo AGP
 	4747  3D Rage Pro
 	4749  3D Rage Pro
+		1002 0061  Rage Pro AIW
+		1002 0062  Rage Pro AIW
 	474c  Rage XC
-	474d  Rage XL AGP
+	474d  Rage XL AGP 2X
+		1002 0004  Xpert 98 RXL AGP 2X
+		1002 0008  Xpert 98 RXL AGP 2X
+		1002 0080  Rage XL AGP 2X
+		1002 0084  Xpert 98 AGP 2X
+		1002 474d  Rage XL AGP
+		1033 806a  Rage XL AGP
 	474e  Rage XC AGP
+		1002 474e  Rage XC AGP
 	474f  Rage XL
+		1002 0008  Rage XL
+		1002 474f  Rage XL
 	4750  3D Rage Pro 215GP
+		1002 0040  Rage Pro Turbo
+		1002 0044  Rage Pro Turbo
+		1002 0080  Rage Pro Turbo
+		1002 0084  Rage Pro Turbo
+		1002 4750  Rage Pro Turbo
 	4751  3D Rage Pro 215GQ
 	4752  Rage XL
+		1002 0008  Rage XL
+		1002 4752  Rage XL
 	4753  Rage XC
+		1002 4753  Rage XC
 	4754  3D Rage I/II 215GT [Mach64 GT]
 	4755  3D Rage II+ 215GTB [Mach64 GTB]
 	4756  3D Rage IIC 215IIC [Mach64 GT IIC]
+		1002 4756  Rage IIC
 	4757  3D Rage IIC AGP
+		1002 4757  Rage IIC AGP
 		1028 0089  Rage 3D IIC
 		1028 4082  Rage 3D IIC
 		1028 8082  Rage 3D IIC
@@ -169,77 +199,159 @@
 	4759  3D Rage IIC
 	475a  3D Rage IIC AGP
 		1002 0087  Rage 3D IIC
+		1002 475a  Rage IIC AGP
 	4c42  3D Rage LT Pro AGP-133
 		0e11 b0e8  Rage 3D LT Pro
 		0e11 b10e  3D Rage LT Pro (Compaq Armada 1750)
+		1002 0040  Rage LT Pro AGP 2X
+		1002 0044  Rage LT Pro AGP 2X
+		1002 4c42  Rage LT Pro AGP 2X
+		1002 8001  Rage LT Pro AGP 2X
 		1028 0085  Rage 3D LT Pro
 	4c44  3D Rage LT Pro AGP-66
 	4c45  Rage Mobility M3 AGP
 	4c46  Rage Mobility M3 AGP 2x
 	4c47  3D Rage LT-G 215LG
 	4c49  3D Rage LT Pro
+		1002 0004  Rage LT Pro
+		1002 0040  Rage LT Pro
+		1002 0044  Rage LT Pro
+		1002 4c49  Rage LT Pro
 	4c4d  Rage Mobility P/M AGP 2x
+		1002 0084  Xpert 98 AGP 2X (Mobility)
 	4c4e  Rage Mobility L AGP 2x
 	4c50  3D Rage LT Pro
+		1002 4c50  Rage LT Pro
 	4c51  3D Rage LT Pro
 	4c52  Rage Mobility P/M
 	4c53  Rage Mobility L
 	4c54  264LT [Mach64 LT]
-	4c57  Radeon Mobility M6 LW
+	4c57  Radeon Mobility M7 LW
+		1028 00e6  Radeon Mobility M7 LW (Dell Inspiron 8100)
+	4c58  Radeon Mobility M6 LX
 	4c59  Radeon Mobility M6 LY
+		104d 80e7  Vaio PCG Series video card
 	4c5a  Radeon Mobility M6 LZ
 	4d46  Rage Mobility M4 AGP
 	4d4c  Rage Mobility M4 AGP
-	5041  Rage 128 PA
-	5042  Rage 128 PB
-	5043  Rage 128 PC
-	5044  Rage 128 PD
-	5045  Rage 128 PE
-	5046  Rage 128 PF
+	5041  Rage 128 PA/PRO
+	5042  Rage 128 PB/PRO AGP 2x
+	5043  Rage 128 PC/PRO AGP 4x
+	5044  Rage 128 PD/PRO TMDS
+		1002 0028  Rage 128 AIW
+		1002 0029  Rage 128 AIW
+	5045  Rage 128 PE/PRO AGP 2x TMDS
+	5046  Rage 128 PF/PRO AGP 4x TMDS
+		1002 0004  Rage Fury Pro
+		1002 0008  Rage Fury Pro/Xpert 2000 Pro
+		1002 0014  Rage Fury Pro
+		1002 0018  Rage Fury Pro/Xpert 2000 Pro
+		1002 0028  Rage 128 Pro AIW AGP
+		1002 002a  Rage 128 Pro AIW AGP
+		1002 0048  Rage Fury Pro
 		1002 2000  Rage Fury MAXX AGP 4x (TMDS) (VGA device)
 		1002 2001  Rage Fury MAXX AGP 4x (TMDS) (Extra device?!)
-	5047  Rage 128 PG
-	5048  Rage 128 PH
-	5049  Rage 128 PI
-	504a  Rage 128 PJ
-	504b  Rage 128 PK
-	504c  Rage 128 PL
-	504d  Rage 128 PM
-	504e  Rage 128 PN
-	504f  Rage 128 PO
-	5050  Rage 128 PP
-	5051  Rage 128 PQ
-	5052  Rage 128 PR
-	5053  Rage 128 PS
-	5054  Rage 128 PT
-	5055  Rage 128 PU
-	5056  Rage 128 PV
-	5057  Rage 128 PW
-	5058  Rage 128 PX
+	5047  Rage 128 PG/PRO
+	5048  Rage 128 PH/PRO AGP 2x
+	5049  Rage 128 PI/PRO AGP 4x
+	504a  Rage 128 PJ/PRO TMDS
+	504b  Rage 128 PK/PRO AGP 2x TMDS
+	504c  Rage 128 PL/PRO AGP 4x TMDS
+	504d  Rage 128 PM/PRO
+	504e  Rage 128 PN/PRO AGP 2x
+	504f  Rage 128 PO/PRO AGP 4x
+	5050  Rage 128 PP/PRO TMDS
+		1002 0008  Xpert 128
+	5051  Rage 128 PQ/PRO AGP 2x TMDS
+	5052  Rage 128 PR/PRO AGP 4x TMDS
+	5053  Rage 128 PS/PRO
+	5054  Rage 128 PT/PRO AGP 2x
+	5055  Rage 128 PU/PRO AGP 4x
+	5056  Rage 128 PV/PRO TMDS
+	5057  Rage 128 PW/PRO AGP 2x TMDS
+	5058  Rage 128 PX/PRO AGP 4x TMDS
 	5144  Radeon QD
+		1002 0008  Radeon 7000/Radeon VE
+		1002 0009  Radeon 7000/Radeon
+		1002 000a  Radeon 7000/Radeon
+		1002 001a  Radeon 7000/Radeon
+		1002 0029  Radeon AIW
+		1002 0038  Radeon 7000/Radeon
+		1002 0039  Radeon 7000/Radeon
+		1002 008a  Radeon 7000/Radeon
+		1002 00ba  Radeon 7000/Radeon
+		1002 0139  Radeon 7000/Radeon
+		1002 028a  Radeon 7000/Radeon
+		1002 02aa  Radeon AIW
+		1002 053a  Radeon 7000/Radeon
 	5145  Radeon QE
 	5146  Radeon QF
 	5147  Radeon QG
+	5148  Radeon R200 QH
+	5149  Radeon R200 QI
+	514a  Radeon R200 QJ
+	514b  Radeon R200 QK
+	514c  Radeon QL
+		1002 013a  Radeon 8500
+	5157  Radeon 7500 QW
+		1002 013a  Radeon 7500
+	5158  Radeon 7500 QX
 	5159  Radeon VE QY
+		1002 000a  Radeon 7000/Radeon VE
+		1002 0038  Radeon 7000/Radeon VE
+		1002 003a  Radeon 7000/Radeon VE
+		1002 00ba  Radeon 7000/Radeon VE
+		1002 013a  Radeon 7000/Radeon VE
 	515a  Radeon VE QZ
-	5245  Rage 128 RE
-	5246  Rage 128 RF
+	5168  Radeon R200 Qh
+	5169  Radeon R200 Qi
+	516a  Radeon R200 Qj
+	516b  Radeon R200 Qk
+	5245  Rage 128 RE/SG
+		1002 0008  Xpert 128
+		1002 0028  Rage 128 AIW
+		1002 0029  Rage 128 AIW
+		1002 0068  Rage 128 AIW
+	5246  Rage 128 RF/SG AGP
+		1002 0004  Magnum/Xpert 128/Xpert 99
+		1002 0008  Magnum/Xpert128/X99/Xpert2000
+		1002 0028  Rage 128 AIW AGP
+		1002 0044  Rage Fury/Xpert 128/Xpert 2000
+		1002 0068  Rage 128 AIW AGP
+		1002 0448  Rage Fury
 	5247  Rage 128 RG
-	524b  Rage 128 RK
-	524c  Rage 128 RL
-	5345  Rage 128 SE
-	5346  Rage 128 SF
-	5347  Rage 128 SG
-	5348  Rage 128 4x
-	534b  Rage 128 SK
-	534c  Rage 128 SL
-	534d  Rage 128 SM
-	534e  Rage 128 SN
+	524b  Rage 128 RK/VR
+	524c  Rage 128 RL/VR AGP
+		1002 0008  Xpert 99/Xpert 2000
+		1002 0088  Xpert 99
+	5345  Rage 128 SE/4x
+	5346  Rage 128 SF/4x AGP 2x
+	5347  Rage 128 SG/4x AGP 4x
+	5348  Rage 128 SH
+	534b  Rage 128 SK/4x
+	534c  Rage 128 SL/4x AGP 2x
+	534d  Rage 128 SM/4x AGP 4x
+		1002 0008  Xpert 99/Xpert 2000
+		1002 0018  Xpert 2000
+	534e  Rage 128 4x
 	5354  Mach 64 VT
 		1002 5654  Mach 64 reference
-	5446  Rage 128 Pro TF
-	544c  Rage 128 Pro TL
-	5452  Rage 128 Pro TR
+	5446  Rage 128 Pro Ultra TF
+		1002 0004  Rage Fury Pro
+		1002 0008  Rage Fury Pro/Xpert 2000 Pro
+		1002 0018  Rage Fury Pro/Xpert 2000 Pro
+		1002 0028  Rage 128 AIW Pro AGP
+		1002 0029  Rage 128 AIW
+		1002 002a  Rage 128 AIW Pro AGP
+		1002 002b  Rage 128 AIW
+		1002 0048  Xpert 2000 Pro
+	544c  Rage 128 Pro Ultra TL
+	5452  Rage 128 Pro Ultra TR
+		1002 001c  Rage 128 Pro 4XL
+		103c 1279  Rage 128 Pro 4XL
+	5453  Rage 128 Pro Ultra TS
+	5454  Rage 128 Pro Ultra TT
+	5455  Rage 128 Pro Ultra TU
 	5654  264VT [Mach64 VT]
 		1002 5654  Mach64VT Reference
 	5655  264VT3 [Mach64 VT3]
@@ -255,7 +367,7 @@
 	000c  82C541 [Lynx]
 	000d  82C543 [Lynx]
 	0101  82C532
-	0102  82C534
+	0102  82C534 [Eagle]
 	0103  82C538
 	0104  82C535
 	0105  82C147
@@ -290,11 +402,17 @@
 	0001  DP83810
 	0002  87415/87560 IDE
 	000e  87560 Legacy I/O
-	000f  OHCI Compliant FireWire Controller
-	0011  National PCI System I/O
+	000f  FireWire Controller
+	0011  NS87560 National PCI System I/O
 	0012  USB Controller
 	0020  DP83815 (MacPhyter) Ethernet Controller
 	0022  DP83820 10/100/1000 Ethernet Controller
+	0500  SCx200 Bridge
+	0501  SCx200 SMI
+	0502  SCx200 IDE
+	0503  SCx200 Audio
+	0504  SCx200 Video
+	0505  SCx200 XBus
 	d001  87410 IDE
 100c  Tseng Labs Inc
 	3202  ET4000/W32p rev A
@@ -305,9 +423,10 @@
 	4702  ET6300
 100d  AST Research Inc
 100e  Weitek
-	9000  P9000
-	9001  P9000
-	9100  P9100
+	9000  P9000 Viper
+	9001  P9000 Viper
+	9002  P9000 Viper
+	9100  P9100 Viper Pro/SE
 1010  Video Logic, Ltd.
 1011  Digital Equipment Corporation
 	0001  DECchip 21050
@@ -360,6 +479,7 @@
 		1374 0001  Cardbus Ethernet Card 10/100
 		1395 0001  10/100 Ethernet CardBus PC Card
 		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
+	001a  Farallon PN9000SX
 	0021  DECchip 21052
 	0022  DECchip 21150
 	0023  DECchip 21150
@@ -368,7 +488,11 @@
 	0026  DECchip 21154
 	0045  DECchip 21553
 	0046  DECchip 21554
+		0e11 4050  Integrated Smart Array
+		0e11 4051  Integrated Smart Array
+		0e11 4058  Integrated Smart Array
 		103c 10c2  Hewlett-Packard NetRAID-4M
+		12d9 000a  VoIP PCI Gateway
 		9005 0365  Adaptec 5400S
 		9005 1364  Dell PowerEdge RAID Controller 2
 		9005 1365  Dell PowerEdge RAID Controller 2
@@ -394,7 +518,7 @@
 	00d6  GD 5465 [Laguna]
 	00e8  GD 5436U
 	1100  CL 6729
-	1110  PD 6832
+	1110  PD 6832 PCMCIA/CardBus Ctrlr
 	1112  PD 6834 PCMCIA/CardBus Ctrlr
 	1113  PD 6833 PCMCIA/CardBus Ctrlr
 	1200  GD 7542 [Nordic]
@@ -405,6 +529,8 @@
 		1014 1010  CS4610 SoundFusion Audio Accelerator
 	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 		1013 4280  Crystal SoundFusion PCI Audio Accelerator
+		1681 0050  Hercules Game Theater XP
+	6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 	6005  Crystal CS4281 PCI Audio
 		1013 4281  Crystal CS4281 PCI Audio
 		10cf 10a8  Crystal CS4281 PCI Audio
@@ -424,6 +550,7 @@
 	0017  CPU to PCI Bridge
 	0018  TR Auto LANstreamer
 	001b  GXT-150P
+	001c  Carrera
 	001d  82G2675
 	0020  MCA
 	0022  IBM27-82351
@@ -469,6 +596,7 @@
 	0144  Yotta Video Compositor Output
 		1014 0145  Yotta Output Controller (ytout)
 	0156  405GP PLB to PCI Bridge
+	01a7  PCI-X to PCI-X Bridge
 	01bd  Netfinity ServeRAID controller
 	01be  ServeRAID-4M
 	01bf  ServeRAID-4L
@@ -497,20 +625,25 @@
 	c24a  90C
 101e  American Megatrends Inc.
 	1960  MegaRAID
+		101e 0471  MegaRAID 471 Enterprise 1600 RAID Controller
+		101e 0475  MegaRAID 475 Express 500 RAID Controller
+		101e 0493  MegaRAID 493 Elite 1600 RAID Controller
 		1028 0471  PowerEdge RAID Controller 3/QC
 		1028 0493  PowerEdge RAID Controller 3/DC
-	9010  MegaRAID
+	9010  MegaRAID 428 Ultra RAID Controller
 	9030  EIDE Controller
 	9031  EIDE Controller
 	9032  EIDE & SCSI Controller
 	9033  SCSI Controller
 	9040  Multimedia card
-	9060  MegaRAID
+	9060  MegaRAID 434 Ultra GT RAID Controller
+	9063  MegaRAC
 101f  PictureTel
 1020  Hitachi Computer Products
 1021  OKI Electric Industry Co. Ltd.
 1022  Advanced Micro Devices [AMD]
 	2000  79c970 [PCnet LANCE]
+		1014 2000  NetFinity 10/100 Fast Ethernet
 		103c 104c  Ethernet with LAN remote power Adapter
 		103c 1064  Ethernet with LAN remote power Adapter
 		103c 1065  Ethernet with LAN remote power Adapter
@@ -519,15 +652,20 @@
 		103c 10ea  Ethernet with LAN remote power Adapter
 		1113 1220  EN1220 10/100 Fast Ethernet
 		1259 2450  AT-2450 10/100 Fast Ethernet
+		1259 2454  AT-2450v4 10Mb Ethernet Adapter
 		1259 2700  AT-2700TX 10/100 Fast Ethernet
 		1259 2701  AT-2700FX 100Mb Ethernet
 	2001  79c978 [HomePNA]
+		1092 0a78  Multimedia Home Network Adapter
+		1668 0299  ActionLink Home Network Adapter
 	2020  53c974 [PCscsi]
 	2040  79c974
 	7006  AMD-751 [Irongate] System Controller
 	7007  AMD-751 [Irongate] AGP Bridge
-	700e  AMD-760 [Irongate] System Controller
-	700f  AMD-760 [Irongate] AGP Bridge
+	700c  AMD-760 MP [IGD4-2P] System Controller
+	700d  AMD-760 MP [IGD4-2P] AGP Bridge
+	700e  AMD-760 [IGD4-1P] System Controller
+	700f  AMD-760 [IGD4-1P] AGP Bridge
 	7400  AMD-755 [Cobra] ISA
 	7401  AMD-755 [Cobra] IDE
 	7403  AMD-755 [Cobra] ACPI
@@ -536,15 +674,28 @@
 	7409  AMD-756 [Viper] IDE
 	740b  AMD-756 [Viper] ACPI
 	740c  AMD-756 [Viper] USB
-	7410  AMD-765 [Viper] ISA
-	7411  AMD-765 [Viper] IDE
-	7413  AMD-765 [Viper] ACPI
-	7414  AMD-765 [Viper] USB
-	7440  AMD-768 [??] ISA
-	7441  AMD-768 [??] IDE
-	7443  AMD-768 [??] ACPI
-	7448  AMD-768 [??] PCI
-	7449  AMD-768 [??] USB
+	7410  AMD-766 [ViperPlus] ISA
+	7411  AMD-766 [ViperPlus] IDE
+	7413  AMD-766 [ViperPlus] ACPI
+	7414  AMD-766 [ViperPlus] USB
+	7440  AMD-768 [Opus] ISA
+		1043 8044  Asus A7M-D motherboard ISA bridge
+	7441  AMD-768 [Opus] IDE
+	7443  AMD-768 [Opus] ACPI
+		1043 8044  Asus A7M-D motherboard
+	7448  AMD-768 [Opus] PCI
+	7449  AMD-768 [Opus] USB
+	7454  AMD-8151 System Controller
+	7455  AMD-8151 AGP Bridge
+	7460  AMD-8111 PCI
+	7461  AMD-8111 USB
+	7462  AMD-8111 Ethernet
+	7468  AMD-8111 LPC
+	7469  AMD-8111 IDE
+	746a  AMD-8111 SMBus 2.0
+	746b  AMD-8111 ACPI
+	746d  AMD-8111 AC97 Audio
+	756b  AMD-8111 ACPI
 1023  Trident Microsystems
 	0194  82C194
 	2000  4DWave DX
@@ -557,6 +708,7 @@
 	8520  CyberBlade i1
 		0e11 b16e  CyberBlade i1 AGP
 		1023 8520  CyberBlade i1 AGP
+	8820  CyberBlade XPAi1
 	9320  TGUI 9320
 	9350  GUI Accelerator
 	9360  Flat panel GUI Accelerator
@@ -580,7 +732,7 @@
 	9682  TGUI 9682
 	9683  TGUI 9683
 	9685  ProVIDIA 9685
-	9750  3DIm`age 975
+	9750  3DImage 9750
 		1014 9750  3DImage 9750
 		1023 9750  3DImage 9750
 	9753  TGUI 9753
@@ -620,6 +772,7 @@
 	1621  M1621 Northbridge [Aladdin-Pro II]
 	1631  M1631 Northbridge+3D Graphics [Aladdin TNT2]
 	1641  M1641 Northbridge [Aladdin-Pro IV]
+	1647  M1647 [MaGiK1] PCI North Bridge
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -629,26 +782,26 @@
 	3307  M3307 MPEG-I Video Controller
 	3309  M3309 MPEG-II Video w/ Software Audio Decoder
 	3321  M3321 MPEG-II Audio/Video Decoder
-	5212  ALI M4803
+	5212  M4803
 	5215  ALI PCI EIDE Controller
 	5217  M5217H
 	5219  M5219
 	5225  M5225
 	5229  M5229
 	5235  M5235
-	5237  ALI M5237 PCI USB Host Controller
+	5237  M5237 PCI USB Host Controller
 	5240  EIDE Controller
 	5241  PCMCIA Bridge
 	5242  General Purpose Controller
 	5243  PCI to PCI Bridge Controller
 	5244  Floppy Disk Controller
-	5247  ALI M1541 PCI to PCI Bridge
-	5251  M5251 P1394 OHCI Controller
-	5427  ALI PCI to AGP Bridge
-	5451  ALI M5451 PCI AC-Link Controller Audio Device
-	5453  ALI M5453 PCI AC-Link Controller Modem Device
-	7101  ALI M7101 PCI PMU Power Management Controller
-		10b9 7101  ALI M7101 PCI PMU Power Management Controller
+	5247  M1541 PCI to PCI Bridge
+	5251  M5251 P1394 Controller
+	5427  PCI to AGP Bridge
+	5451  M5451 PCI AC-Link Controller Audio Device
+	5453  M5453 PCI AC-Link Controller Modem Device
+	7101  M7101 PCI PMU Power Management Controller
+		10b9 7101  M7101 PCI PMU Power Management Controller
 1028  Dell Computer Corporation
 	0001  PowerEdge Expandable RAID Controller 2/Si
 	0002  PowerEdge Expandable RAID Controller 3/Di
@@ -656,8 +809,10 @@
 	0004  PowerEdge Expandable RAID Controller 3/Si
 	0005  PowerEdge Expandable RAID Controller 3/Di
 	0006  PowerEdge Expandable RAID Controller 3/Di
+	0007  Remote Assitant Card 3
 	0008  PowerEdge Expandable RAID Controller 3/Di
 	000a  PowerEdge Expandable RAID Controller 3/Di
+	000c  Embedded Systems Management Device 4
 1029  Siemens Nixdorf IS
 102a  LSI Logic
 	0000  HYDRA
@@ -698,9 +853,23 @@
 		102b ca6c  Millennium G250 AGP
 		102b dbbc  Millennium G200 AGP
 		102b dbc2  Millennium G200 MMS (Dual G200)
+		102b dbc3  G200 Multi-Monitor
 		102b dbc8  Millennium G200 MMS (Dual G200)
+		102b dbd2  G200 Multi-Monitor
+		102b dbd3  G200 Multi-Monitor
+		102b dbd4  G200 Multi-Monitor
+		102b dbd5  G200 Multi-Monitor
+		102b dbd8  G200 Multi-Monitor
+		102b dbd9  G200 Multi-Monitor
 		102b dbe2  Millennium G200 MMS (Quad G200)
+		102b dbe3  G200 Multi-Monitor
 		102b dbe8  Millennium G200 MMS (Quad G200)
+		102b dbf2  G200 Multi-Monitor
+		102b dbf3  G200 Multi-Monitor
+		102b dbf4  G200 Multi-Monitor
+		102b dbf5  G200 Multi-Monitor
+		102b dbf8  G200 Multi-Monitor
+		102b dbf9  G200 Multi-Monitor
 		102b f806  Mystique G200 Video AGP
 		102b ff00  MGA-G200 AGP
 		102b ff02  Mystique G200 AGP
@@ -708,16 +877,18 @@
 		102b ff04  Marvel G200 AGP
 		110a 0032  MGA-G200 AGP
 	0525  MGA G400 AGP
-		0e11 b16f  Matrox MGA-G400 AGP
+		0e11 b16f  MGA-G400 AGP
 		102b 0328  Millennium G400 16Mb SDRAM
 		102b 0338  Millennium G400 16Mb SDRAM
 		102b 0378  Millennium G400 32Mb SDRAM
 		102b 0541  Millennium G450 Dual Head
 		102b 0542  Millennium G450 Dual Head LX
-		102b 0641  Millennium G450 32Mb SDRAM
+		102b 0543  Millennium G450 Single Head LX
+		102b 0641  Millennium G450 32Mb SDRAM Dual Head
 		102b 0642  Millennium G450 32Mb SDRAM Dual Head LX
+		102b 0643  Millennium G450 32Mb SDRAM Single Head LX
 		102b 07c0  Millennium G450 Dual Head LE
-		102b 07c1  Millennium G450 SDR Dual Head
+		102b 07c1  Millennium G450 SDR Dual Head LE
 		102b 0d41  Millennium G450 Dual Head PCI
 		102b 0d42  Millennium G450 Dual Head LX PCI
 		102b 0e00  Marvel G450 eTV
@@ -733,11 +904,24 @@
 		102b 2159  Millennium G400 Dual Head 16Mb
 		102b 2179  Millennium G400 MAX/Dual Head 32Mb
 		102b 217d  Millennium G400 Dual Head Max
+		102b 23c0  Millennium G450
+		102b 23c1  Millennium G450
+		102b 23c2  Millennium G450 DVI
+		102b 23c3  Millennium G450 DVI
 		102b 2f58  Millennium G400
 		102b 2f78  Millennium G400
 		102b 3693  Marvel G400 AGP
-		1705 0001  Millennium G450 32MB SGRAM
-		b16f 0e11  Matrox MGA-G400 AGP
+		102b 5dd0  4Sight II
+		102b 5f50  4Sight II
+		102b 5f51  4Sight II
+		102b 5f52  4Sight II
+		102b 9010  Millennium G400 Dual Head
+		1458 0400  GA-G400
+		1705 0001  Digital First Millennium G450 32MB SGRAM
+		1705 0002  Digital First Millennium G450 16MB SGRAM
+		1705 0003  Digital First Millennium G450 32MB
+		1705 0004  Digital First Millennium G450 16MB
+		b16f 0e11  MGA-G400 AGP
 	0d10  MGA Ultima/Impression
 	1000  MGA G100 [Productiva]
 		102b ff01  Productiva G100
@@ -752,12 +936,15 @@
 		110a 001e  MGA-G100 AGP
 	2007  MGA Mistral
 	2527  MGA G550 AGP
+		102b 0f83  Millennium G550
 		102b 0f84  Millennium G550 Dual Head DDR 32Mb
+		102b 1e41  Millennium G550
 	4536  VIA Framegrabber
 	6573  Shark 10/100 Multiport SwitchNIC
 102c  Chips and Technologies
 	00b8  F64310
 	00c0  F69000 HiQVideo
+		102c 00c0  F69000 HiQVideo
 	00d0  F65545
 	00d8  F65545
 	00dc  F65548
@@ -796,6 +983,7 @@
 	0029  PowerVR PCX1
 	002a  PowerVR 3D
 	0035  USB
+		12ee 7000  Root Hub
 	003e  NAPCCARD Cardbus Controller
 	0046  PowerVR PCX2 [midas]
 	005a  Vrc5074 [Nile 4]
@@ -813,6 +1001,10 @@
 		1033 8014  RCV56ACF 56k Voice Modem
 	009b  Vrc5476
 	00a6  VRC5477 AC97
+	00cd  IEEE 1394 [OrangeLink] Host Controller
+		12ee 8011  Root hub
+	00e0  USB 2.0
+		12ee 7001  Root hub
 1034  Framatome Connectors USA Inc.
 1035  Comp. & Comm. Research Lab
 1036  Future Domain Corp.
@@ -871,8 +1063,9 @@
 		1092 4920  SpeedStar A70
 		1569 6326  SiS6326 GUI Accelerator
 	7001  7001
-	7007  OHCI Compliant FireWire Controller
+	7007  FireWire Controller
 	7012  SiS7012 PCI Audio Accelerator
+	7013  56k Winmodem (Smart Link HAMR5600 compatible)
 	7016  SiS7016 10/100 Ethernet Adapter
 		1039 7016  SiS7016 10/100 Ethernet Adapter
 	7018  SiS PCI Audio Accelerator
@@ -902,8 +1095,17 @@
 103b  Tatung Co. of America
 103c  Hewlett-Packard Company
 	1005  A4977A Visualize EG
-	1030  J2585A
-	1031  J2585B
+	1028  Tach TL Fibre Channel Host Adapter
+	1029  Tach XL2 Fibre Channel Host Adapter
+		107e 000f  Interphase 5560 Fibre Channel Adapter
+		9004 9210  1Gb/2Gb Family Fibre Channel Controller
+		9004 9211  1Gb/2Gb Family Fibre Channel Controller
+	102a  Tach TS Fibre Channel Host Adapter
+		107e 000e  Interphase 5540/5541 Fibre Channel Adapter
+		9004 9110  1Gb/2Gb Family Fibre Channel Controller
+		9004 9111  1Gb/2Gb Family Fibre Channel Controller
+	1030  J2585A DeskDirect 10/100VG NIC
+	1031  J2585B HP 10/100VG PCI LAN Adapter
 		103c 1040  J2973A DeskDirect 10BaseT NIC
 		103c 1041  J2585B DeskDirect 10/100VG NIC
 		103c 1042  J2970A DeskDirect 10BaseT/2 NIC
@@ -918,8 +1120,8 @@
 	121a  NetServer SMIC Controller
 	121b  NetServer Legacy COM Port Decoder
 	121c  NetServer PCI COM Port Decoder
-	2910  E2910A
-	2925  E2925A
+	2910  E2910A PCIBus Exerciser
+	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
 103f  Synopsys/Logic Modeling Group
 1040  Accelgraphics Inc.
@@ -931,11 +1133,49 @@
 	3010  Samurai_1
 	3020  Samurai_IDE
 1043  Asustek Computer, Inc.
+	0675  ISDNLink P-IN100-ST-D
+	4057  V8200 GeForce 3
 1044  Distributed Processing Technology
 	1012  Domino RAID Engine
 	a400  SmartCache/Raid I-IV Controller
 	a500  PCI Bridge
 	a501  SmartRAID V Controller
+		1044 c001  PM1554U2 Ultra2 Single Channel
+		1044 c002  PM1654U2 Ultra2 Single Channel
+		1044 c003  PM1564U3 Ultra3 Single Channel
+		1044 c004  PM1564U3 Ultra3 Dual Channel
+		1044 c005  PM1554U2 Ultra2 Single Channel (NON ACPI)
+		1044 c00a  PM2554U2 Ultra2 Single Channel
+		1044 c00b  PM2654U2 Ultra2 Single Channel
+		1044 c00c  PM2664U3 Ultra3 Single Channel
+		1044 c00d  PM2664U3 Ultra3 Dual Channel
+		1044 c00e  PM2554U2 Ultra2 Single Channel (NON ACPI)
+		1044 c00f  PM2654U2 Ultra2 Single Channel (NON ACPI)
+		1044 c014  PM3754U2 Ultra2 Single Channel (NON ACPI)
+		1044 c015  PM3755U2B Ultra2 Single Channel (NON ACPI)
+		1044 c016  PM3755F Fibre Channel (NON ACPI)
+		1044 c01e  PM3757U2 Ultra2 Single Channel
+		1044 c01f  PM3757U2 Ultra2 Dual Channel
+		1044 c020  PM3767U3 Ultra3 Dual Channel
+		1044 c021  PM3767U3 Ultra3 Quad Channel
+		1044 c028  PM2865U3 Ultra3 Single Channel
+		1044 c029  PM2865U3 Ultra3 Dual Channel
+		1044 c02a  PM2865F Fibre Channel
+		1044 c03c  2000S Ultra3 Single Channel
+		1044 c03d  2000S Ultra3 Dual Channel
+		1044 c03e  2000F Fibre Channel
+		1044 c046  3000S Ultra3 Single Channel
+		1044 c047  3000S Ultra3 Dual Channel
+		1044 c048  3000F Fibre Channel
+		1044 c050  5000S Ultra3 Single Channel
+		1044 c051  5000S Ultra3 Dual Channel
+		1044 c052  5000F Fibre Channel
+		1044 c05a  2400A UDMA Four Channel
+		1044 c05b  2400A UDMA Four Channel DAC
+		1044 c064  3010S Ultra3 Dual Channel
+		1044 c065  3010S Ultra3 Four Channel
+		1044 c066  3010S Fibre Channel
+	a511  SmartRAID V Controller
 1045  OPTi Inc.
 	a0f8  82C750 [Vendetta] USB Controller
 	c101  92C264
@@ -967,7 +1207,9 @@
 104a  SGS Thomson Microelectronics
 	0008  STG 2000X
 	0009  STG 1764X
+	0981  DEC-Tulip compatible 10/100 Ethernet
 	1746  STG 1764X
+	2774  DEC-Tulip compatible 10/100 Ethernet
 	3520  MPEG-II decoder card
 104b  BusLogic
 	0140  BT-946C (old) [multimaster  01]
@@ -979,6 +1221,13 @@
 	1000  Eagle i/f AS
 	3d04  TVP4010 [Permedia]
 	3d07  TVP4020 [Permedia 2]
+		1011 4d10  Comet
+		1040 000f  AccelStar II
+		1040 0011  AccelStar II
+		1048 0a31  WINNER 2000
+		1048 0a32  GLoria Synergy
+		1048 0a35  GLoria Synergy
+		107d 2633  WinFast 3D L2300
 		1092 0127  FIRE GL 1000 PRO
 		1092 0136  FIRE GL 1000 PRO
 		1092 0141  FIRE GL 1000 PRO
@@ -991,15 +1240,26 @@
 		1092 0156  FIRE GL 1000 PRO
 		1092 0157  FIRE GL 1000 PRO
 		1097 3d01  Jeronimo Pro
+		1102 100f  Graphics Blaster Extreme
 		3d3d 0100  Reference Permedia 2 3D
 	8000  PCILynx/PCILynx2 IEEE 1394 Link Layer Controller
 		e4bf 1010  CF1-1-SNARE
 		e4bf 1020  CF1-2-SNARE
-	8009  OHCI Compliant FireWire Controller
-	8019  TSB12LV23 OHCI Compliant IEEE-1394 Controller
+	8009  FireWire Controller
+		104d 8032  8032 OHCI i.LINK (IEEE 1394) Controller
+	8017  PCI4410 FireWire Controller
+	8019  TSB12LV23 IEEE-1394 Controller
 		11bd 000a  Studio DV500-1394
 		11bd 000e  Studio DV
 		e4bf 1010  CF2-1-CYMBAL
+	8020  TSB12LV26 IEEE-1394 Controller (Link)
+	8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)
+		104d 80e7  Notebook Computer Vaio PCG Series
+	8022  TSB43AB22 IEEE-1394 Controller (PHY/Link) 1394a-2000
+	8024  TSB43AB23 IEEE-1394 Controller (PHY/Link) 1394a-2000
+	8026  TSB43AB21 IEEE-1394 Controller (PHY/Link) 1394a-2000
+	8027  PCI4451 IEEE-1394 Controller
+		1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)
 	a001  TDC1570
 	a100  TDC1561
 	ac10  PCI1050
@@ -1018,10 +1278,12 @@
 	ac1e  PCI1211
 	ac1f  PCI1251B
 	ac20  TI 2030
+	ac21  PCI2031
 	ac30  PCI1260 PC card Cardbus Controller
 	ac40  PCI4450 PC card Cardbus Controller
 	ac41  PCI4410 PC card Cardbus Controller
 	ac42  PCI4451 PC card Cardbus Controller
+		1028 00e6  PCI4451 PC card CardBus Controller (Dell Inspiron 8100)
 	ac50  PCI1410 PC card Cardbus Controller
 	ac51  PCI1420
 	ac52  PCI1451 PC card Cardbus Controller
@@ -1033,6 +1295,7 @@
 	8039  CXD3222 i.LINK Controller
 	8056  Rockwell HCF 56K modem
 	808a  Memory Stick Controller
+	80e7  Vaio PCG-GR114MK
 104e  Oak Technology, Inc
 	0017  OTI-64017
 	0107  OTI-107 [Spitfire]
@@ -1058,7 +1321,7 @@
 1055  EFAR Microsystems
 	9130  EIDE Controller
 	9460  PCI to ISA Bridge
-	9462  USB Universal Host Controller [OHCI]
+	9462  USB Universal Host Controller
 	9463  Power Management Controller [Bridge]
 1056  ICL
 # Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this.
@@ -1096,13 +1359,24 @@
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
 	0d30  20265
+		105a 4d33  Ultra100
+	0d38  20263
+		105a 4d39  Fasttrak66
 	4d30  20267
+		105a 4d33  Ultra100
+		105a 4d39  Fasttrak100
 	4d33  20246
 	4d38  20262
+		105a 4d30  Ultra Device on SuperTrak
+		105a 4d33  Ultra66
+		105a 4d39  Fasttrak66
 	4d68  20268
-	6268  20268R
+		105a 4d68  Ultra100TX2
 	4d69  20269
+	5275  PDC20276 IDE
+		105a 0275  SuperTrak SX6000 IDE
 	5300  DC5300
+	6268  20268R
 105b  Foxconn International, Inc.
 105c  Wipro Infotech Limited
 105d  Number 9 Computer Company
@@ -1167,7 +1441,9 @@
 	0001  DAC960P
 	0002  DAC960PD
 	0010  DAC960PX
-	ba55  eXtremeRAID support Device
+	0050  AcceleRAID 352/170/160 support Device
+	ba55  eXtremeRAID 1100 support Device
+	ba56  eXtremeRAID 2000/3000 support Device
 106a  Aten Research Inc
 106b  Apple Computer Inc.
 	0001  Bandit PowerPC host bridge
@@ -1238,19 +1514,21 @@
 1075  Advanced Integrations Research
 1076  Chaintech Computer Co. Ltd
 1077  QLogic Corp.
-	1016  QLA10160
-	1020  ISP1020
-	1022  ISP1022
-	1080  QLA1080
-	1216  QLA12160
+	1016  ISP10160 Single Channel Ultra3 SCSI Processor
+	1020  ISP1020 Fast-wide SCSI
+	1022  ISP1022 Fast-wide SCSI
+	1080  ISP1080 SCSI Host Adapter
+	1216  ISP12160 Dual Channel Ultra3 SCSI Processor
 		101e 8471  QLA12160 on AMI MegaRAID
 		101e 8493  QLA12160 on AMI MegaRAID
-	1240  QLA1240
-	1280  QLA1280
-	2020  ISP2020A
-	2100  QLA2100
+	1240  ISP1240 SCSI Host Adapter
+	1280  ISP1280
+	2020  ISP2020A Fast!SCSI Basic Adapter
+	2100  QLA2100 64-bit Fibre Channel Adapter
+		1077 0001  QLA2100 64-bit Fibre Channel Adapter
 	2200  QLA2200
-	2300  QLA2300
+	2300  QLA2300 64-bit FC-AL Adapter
+	2312  QLA2312 Fibre Channel Adapter
 1078  Cyrix Corporation
 	0000  5510 [Grappa]
 	0001  PCI Master
@@ -1260,6 +1538,10 @@
 	0102  5530 IDE [Kahlua]
 	0103  5530 Audio [Kahlua]
 	0104  5530 Video [Kahlua]
+	0400  ZFMicro PCI Bridge
+	0401  ZFMicro Chipset SMI
+	0402  ZFMicro Chipset IDE
+	0403  ZFMicro Expansion Bus
 1079  I-Bus
 107a  NetWorth
 107b  Gateway 2000
@@ -1267,9 +1549,22 @@
 107d  LeadTek Research Inc.
 	0000  P86C850
 107e  Interphase Corporation
-	0001  ATM Interface Card
+	0001  5515 ATM Adapter [Flipper]
 	0002  100 VG AnyLan Controller
-	0008  155 Mbit ATM Controller
+	0004  5526 Fibre Channel Host Adapter
+	0005  x526 Fibre Channel Host Adapter
+	0008  5525/5575 ATM Adapter (155 Mbit) [Atlantic]
+	9003  5535-4P-BRI-ST
+	9007  5535-4P-BRI-U
+	9008  5535-1P-SR
+	900c  5535-1P-SR-ST
+	900e  5535-1P-SR-U
+	9011  5535-1P-PRI
+	9013  5535-2P-PRI
+	9023  5536-4P-BRI-ST
+	9027  5536-4P-BRI-U
+	9031  5536-1P-PRI
+	9033  5536-2P-PRI
 107f  Data Technology Corporation
 	0802  SL82C105
 1080  Contaq Microsystems
@@ -1342,6 +1637,7 @@
 	00a8  Speedstar 64
 	0550  Viper V550
 	08d4  Supra 2260 Modem
+	094c  SupraExpress 56i Pro
 	1092  Viper V330
 	6120  Maximum DVD
 	8810  Stealth SE
@@ -1385,6 +1681,9 @@
 	0647  PCI0647
 	0648  PCI0648
 	0649  PCI0649
+		0e11 005d  Integrated Ultra ATA-100 Dual Channel Controller
+		0e11 007e  Integrated Ultra ATA-100 IDE RAID Controller
+		101e 0649  AMI MegaRAID IDE 100 Controller
 	0650  PBC0650A
 	0670  USB0670
 	0673  USB0673
@@ -1406,6 +1705,7 @@
 		13e9 0070  Win/TV (Video Section)
 	036e  Bt878
 		0070 13eb  WinTV/GO
+		0070 ff01  Viewcast Osprey 200
 		127a 0001  Bt878 Mediastream Controller NTSC
 		127a 0002  Bt878 Mediastream Controller PAL BG
 		127a 0003  Bt878a Mediastream Controller PAL BG
@@ -1454,6 +1754,7 @@
 		1852 1852  FlyVideo'98 (with FM Tuner)
 	0878  Bt878
 		0070 13eb  WinTV/GO
+		0070 ff01  Viewcast Osprey 200
 		127a 0001  Bt878 Video Capture (Audio Section)
 		127a 0002  Bt878 Video Capture (Audio Section)
 		127a 0003  Bt878 Video Capture (Audio Section)
@@ -1561,9 +1862,25 @@
 	0001  i960 PCI bus interface
 	1076  VScom 800 8 port serial adaptor
 	1077  VScom 400 4 port serial adaptor
+	1078  VScom 210 2 port serial and 1 port parallel adaptor
+	1103  VScom 200 2 port serial adaptor
+	1146  VScom 010 1 port parallel adaptor
+	1147  VScom 020 2 port parallel adaptor
+	9030  PCI <-> IOBus Bridge Hot Swap
+		15ed 1002  MCCS 8-port Serial Hot Swap
+		15ed 1003  MCCS 16-port Serial Hot Swap
 	9036  9036
 	9050  PCI <-> IOBus Bridge
 		10b5 2273  SH-ARC SoHard ARCnet card
+		1522 0001  RockForce 4 Port V.90 Data/Fax/Voice Modem
+		1522 0002  RockForce 2 Port V.90 Data/Fax/Voice Modem
+		1522 0010  RockForce2000 4 Port V.90 Data/Fax/Voice Modem
+		1522 0020  RockForce2000 2 Port V.90 Data/Fax/Voice Modem
+		15ed 1000  Macrolink MCCS 8-port Serial
+		15ed 1001  Macrolink MCCS 16-port Serial
+		15ed 1002  Macrolink MCCS 8-port Serial Hot Swap
+		15ed 1003  Macrolink MCCS 16-port Serial Hot Swap
+		d531 c002  PCIntelliCAN 2xSJA1000 CAN bus
 		d84d 4006  EX-4006 1P
 		d84d 4008  EX-4008 1P EPP/ECP
 		d84d 4014  EX-4014 2P
@@ -1587,6 +1904,7 @@
 	906e  9060ES
 	9080  9080
 		10b5 9080  9080 [real subsystem ID not set]
+		129d 0002  Aculab PCI Prosidy card
 	a001  GTEK Jetport II 2 port serial adaptor
 	c001  GTEK Cyclone 16/32 port serial adaptor
 10b6  Madge Networks
@@ -1608,14 +1926,19 @@
 	000a  Smart 100/16/4 PCI Ringnode
 		10b6 000a  Smart 100/16/4 PCI Ringnode
 	000b  16/4 CardBus Adapter Mk2
+		10b6 0008  16/4 CardBus Adapter Mk2
 		10b6 000b  16/4 Cardbus Adapter Mk2
-	1000  Collage 25 ATM Adapter
+	000c  RapidFire 3140V2 16/4 TR Adapter
+		10b6 000c  RapidFire 3140V2 16/4 TR Adapter
+	1000  Collage 25/155 ATM Client Adapter
 	1001  Collage 155 ATM Server Adapter
 10b7  3Com Corporation
-	0001  3c985 1000BaseSX
-	3390  Token Link Velocity
+	0001  3c985 1000BaseSX (SX/TX)
+	1007  Mini PCI 56k Winmodem
+		10b7 615c  Mini PCI 56K Modem
+	3390  3c339 TokenLink Velocity
 	3590  3c359 TokenLink Velocity XL
-		10b7 3590  TokenLink Velocity XL Adapter
+		10b7 3590  TokenLink Velocity XL Adapter (3C359/359B)
 	4500  3c450 Cyclone/unknown
 	5055  3c555 Laptop Hurricane
 	5057  3c575 [Megahertz] 10/100 LAN CardBus
@@ -1623,6 +1946,7 @@
 	5157  3c575 [Megahertz] 10/100 LAN CardBus
 		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
 	5257  3CCFE575CT Cyclone CardBus
+		10b7 5c57  FE575C-3Com 10/100 LAN CardBus-Fast Ethernet
 	5900  3c590 10BaseT [Vortex]
 	5920  3c592 EISA 10mbps Demon/Vortex
 	5950  3c595 100BaseTX [Vortex]
@@ -1633,10 +1957,20 @@
 		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
 	6055  3c556 Hurricane CardBus
 	6056  3c556B Hurricane CardBus
+		10b7 6556  10/100 Mini PCI Ethernet Adapter
 	6560  3CCFE656 Cyclone CardBus
+		10b7 656a  3CCFEM656 10/100 LAN 56K Modem CardBus
+	6561  3CCFEM656 10/100 LAN 56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN 56K Modem CardBus
 	6562  3CCFEM656 [id 6562] Cyclone CardBus
+		10b7 656b  3CCFEM656B 10/100 LAN 56K Modem CardBus
+	6563  3CCFEM656B 10/100 LAN 56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN 56K Modem CardBus
 	6564  3CCFEM656 [id 6564] Cyclone CardBus
 	7646  3cSOHO100-TX Hurricane
+	7940  3c803 FDDILink UTP Controller
+	7980  3c804 FDDILink SAS Controller
+	7990  3c805 FDDILink DAS Controller
 	8811  Token ring
 	9000  3c900 10BaseT [Boomerang]
 	9001  3c900 Combo [Boomerang]
@@ -1647,7 +1981,7 @@
 	9006  3c900B-TPC [Etherlink XL TPC]
 	900a  3c900B-FL [Etherlink XL FL]
 	9050  3c905 100BaseTX [Boomerang]
-	9051  3c905 100BaseT4
+	9051  3c905 100BaseT4 [Boomerang]
 	9055  3c905B 100BaseTX [Cyclone]
 		1028 0080  3C905B Fast Etherlink XL 10/100
 		1028 0081  3C905B Fast Etherlink XL 10/100
@@ -1670,19 +2004,26 @@
 		1028 0098  3C905B Fast Etherlink XL 10/100
 		1028 0099  3C905B Fast Etherlink XL 10/100
 		10b7 9055  3C905B Fast Etherlink XL 10/100
-	9056  3c905B-T4
+	9056  3c905B-T4 [Fast EtherLink XL 10/100]
 	9058  3c905B-Combo [Deluxe Etherlink XL 10/100]
 	905a  3c905B-FX [Fast Etherlink XL FX 10/100]
-	9200  3c905C-TX [Fast Etherlink]
+	9200  3c905C-TX/TX-M [Tornado]
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
+		10b7 7000  10/100 Mini PCI Ethernet Adapter
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
 		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
 	9805  3c980-TX 10/100baseTX NIC [Python-T]
+		10b7 1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]
+		10b7 1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]
 		10b7 9805  3c980 10/100baseTX NIC [Python-T]
+	9902  3CR990-TX-95 56-bit Typhoon Client
+	9903  3CR990-TX-97 168-bit Typhoon Client
+	9908  3CR990SVR95 56-bit Typhoon Server
+	9909  3CR990SVR97 Typhoon Server
 10b8  Standard Microsystems Corp [SMC]
 	0005  83C170QF
-		1055 e000  LANEPIC
-		1055 e002  LANEPIC
+		1055 e000  LANEPIC 10/100 [EVB171Q-PCI]
+		1055 e002  LANEPIC 10/100 [EVB171G-PCI]
 		10b8 a011  EtherPower II 10/100
 		10b8 a014  EtherPower II 10/100
 		10b8 a015  EtherPower II 10/100
@@ -1724,7 +2065,13 @@
 	1543  M1543
 	1621  M1621
 	1631  ALI M1631 PCI North Bridge Aladdin Pro III
+	1632  M1632M Northbridge+Trident
 	1641  ALI M1641 PCI North Bridge Aladdin Pro IV
+	1644  M1644/M1644T Northbridge+Trident
+	1646  M1646 Northbridge+Trident
+	1647  M1647 Northbridge [MAGiK 1 / MobileMAGiK 1]
+	1651  M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM]
+	1671  M1671 Northbridge [Aladdin-P4]
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -1739,11 +2086,21 @@
 	5219  M5219
 	5225  M5225
 	5229  M5229 IDE
+		1043 8053  A7A66 Motherboard IDE
 	5235  M5225
-	5237  M5237 USB
-	5243  M5243
-	5247  M5247
-	5451  M5451 PCI South Bridge Audio
+	5237  USB 1.1 Controller
+	5239  USB 2.0 Controller
+	5243  M1541 PCI to AGP Controller
+	5247  PCI to AGP Controller
+	5251  M5251 P1394 OHCI 1.0 Controller
+	5253  M5253 P1394 OHCI 1.1 Controller
+	5261  M5261 Ethernet Controller
+	5451  M5451 PCI AC-Link Controller Audio Device
+	5453  M5453 PCI AC-Link Controller Modem Device
+	5455  M5455 PCI AC-Link Controller Audio Device
+	5457  M5457 AC-Link Modem Interface Controller
+	5471  M5471 Memory Stick Controller
+	5473  M5473 SD-MMC Controller
 	7101  M7101 PMU
 		10b9 7101  ALI M7101 Power Management Controller
 10ba  Mitsubishi Electric Corp.
@@ -1805,6 +2162,7 @@
 		110a 8005  MagicMedia 256AV Audio Device
 		14c0 0004  MagicMedia 256AV Audio Device
 	8006  NM2360 [MagicMedia 256ZX Audio]
+	8016  NM2360 [MagicMedia 256ZX Audio]
 10c9  Dataexpert Corporation
 10ca  Fujitsu Microelectr., Inc.
 10cb  Omron Corporation
@@ -1831,6 +2189,7 @@
 10d9  Macronix, Inc. [MXIC]
 	0512  MX98713
 	0531  MX987x5
+		1186 1200  DFE-540TX ProFAST 10/100 Adapter
 	8625  MX86250
 	8888  MX86200
 10da  Compaq IPG-Austin
@@ -1908,12 +2267,13 @@
 	002f  Vanta [NV6]
 	00a0  Riva TNT2
 		14af 5810  Maxi Gamer Xentor
-	0100  GeForce 256
+	0100  NV10 (GeForce 256)
 		1043 0200  AGP-V6600 SGRAM
 		1043 0201  AGP-V6600 SDRAM
 		1043 4008  AGP-V6600 SGRAM
 		1043 4009  AGP-V6600 SDRAM
 		1102 102d  CT6941 GeForce 256
+		14af 5022  3D Prophet SE
 	0101  GeForce 256 DDR
 		1043 0202  AGP-V6800 DDR
 		1043 400a  AGP-V6800 DDR SGRAM
@@ -1922,16 +2282,43 @@
 		14af 5021  3D Prophet DDR-DVI
 	0103  Quadro (GeForce 256 GL)
 	0110  NV11 (GeForce2 MX)
+		1043 4015  AGP-7100 Pro with TV output
+		1043 4031  V7100 Pro with TV output
 	0111  NV11 (GeForce2 MX DDR)
 	0112  GeForce2 Go
 	0113  NV11 (GeForce2 MXR)
 	0150  NV15 (GeForce2 Pro)
+		1043 4016  V7700 AGP Video Card
 		107d 2840  WinFast GeForce2 GTS with TV output
+		1462 8831  Creative GeForce2 Pro
 	0151  NV15 DDR (GeForce2 GTS)
 	0152  NV15 Bladerunner (GeForce2 Ultra)
 	0153  NV15 GL (Quadro2 Pro)
+	0170  NV1x
+	0171  NV1x
+	0172  NV1x
+	0173  NV1x
+	0174  NV1x
+	0175  NV1x
+	0176  GeForce4 420 Go 32M
+	0178  NV1x
+	0179  GeForce4 440 Go 64M
+	017a  NV1x
+	017b  NV1x
+	017c  NV1x
+	01a0  GeForce2 Integrated GPU
+	01bc  nForce IDE
 	0200  NV20 (GeForce3)
+		1043 402f  AGP-V8200 DDR
+	0201  GeForce3 Ti200
+	0202  GeForce3 Ti500
+		1043 405b  V8200 T5
 	0203  Quadro DCC
+	0250  NV25 (GeForce 4)
+	0251  GeForce4 Ti 4400
+	0253  GeForce4 Ti 4200
+	0258  NV25 (GeForce 4)
+	025b  NV25 (GeForce 4)
 10df  Emulex Corporation
 	10df  Light Pulse Fibre Channel Adapter
 	1ae5  LP6000 Fibre Channel Host Adapter
@@ -1963,14 +2350,15 @@
 	8043  LANai4.x [Myrinet LANai interface chip]
 	8062  S5933_PARASTATION
 	807d  S5933 [Matchmaker]
-	8088  Kingsberg Spacetec Format Synchronizer
-	8089  Kingsberg Spacetec Serial Output Board
+	8088  Kongsberg Spacetec Format Synchronizer
+	8089  Kongsberg Spacetec Serial Output Board
 	809c  S5933_HEPC3
 	80d7  PCI-9112
 	80d9  PCI-9118
 	80da  PCI-9812
 	811a  PCI-IEEE1355-DS-DE Interface
 	8170  S5933 [Matchmaker] (Chipset Development Tool)
+	82db  AJA HDNTV HD SDI Framestore
 10e9  Alps Electric Co., Ltd.
 10ea  Intergraphics Systems
 	1680  IGA-1680
@@ -1994,7 +2382,7 @@
 		10ec 8129  RT8129 Fast Ethernet Adapter
 	8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter
 		10ec 8138  RT8139 (B/C) Fast Ethernet Adapter
-	8139  RTL-8139
+	8139  RTL-8139/8139C
 		1025 8920  ALN-325
 		1025 8921  ALN-325
 		10bd 0320  EP-320X-R
@@ -2038,6 +2426,8 @@
 	000c  TARGA 1000
 10fb  Thesys Gesellschaft für Mikroelektronik mbH
 10fc  I-O Data Device, Inc.
+# What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives
+	0003  Cardbus IDE Controller
 10fd  Soyo Computer, Inc
 10fe  Fast Multimedia AG
 10ff  NCube
@@ -2063,18 +2453,26 @@
 		1102 8031  CT4831 SBLive! Value
 		1102 8040  CT4760 SBLive!
 		1102 8051  CT4850 SBLive! Value
-	7002  SB Live!
+	0004  SB Audigy
+	4001  SB Audigy FireWire Port
+	7002  SB Live! MIDI/Game Port
 		1102 0020  Gameport Joystick
+	7003  SB Audigy MIDI/Game port
 	8938  ES1371
 1103  Triones Technologies, Inc.
 	0003  HPT343
 	0004  HPT366 / HPT370
 		1103 0005  HPT370 UDMA100
+# Not HPT370A, It's HPT370. I don't know what ID HPT370A has.
+	0005  HPT370
 1104  RasterOps Corp.
 1105  Sigma Designs, Inc.
 	8300  REALmagic Hollywood Plus DVD Decoder
+	8400  EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder
 1106  VIA Technologies, Inc.
 	0305  VT8363/8365 [KT133/KM133]
+		1043 8042  A7V133/A7V133-C
+		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID
 	0391  VT8371 [KX133]
 	0501  VT8501 [Apollo MVP4]
 	0505  VT82C505
@@ -2094,6 +2492,7 @@
 	0605  VT8605 [ProSavage PM133]
 	0680  VT82C680 [Apollo P6]
 	0686  VT82C686 [Apollo Super South]
+		1043 8042  ATV133/A7V133-C
 		1106 0000  VT82C686/A PCI to ISA Bridge
 		1106 0686  VT82C686/A PCI to ISA Bridge
 	0691  VT82C693A/694x [Apollo PRO133x]
@@ -2106,25 +2505,30 @@
 	1571  VT82C416MV
 	1595  VT82C595/97 [Apollo VP2/97]
 	3038  UHCI USB
-		1234 0925  MVP3 USB Controller
 	3040  VT82C586B ACPI
-	3043  VT86C100A [Rhine 10/100]
+	3043  VT3043 [Rhine]
 		10bd 0000  VT86C100A Fast Ethernet Adapter
 		1106 0100  VT86C100A Fast Ethernet Adapter
-		1186 1400  DFE-530TX
-	3044  OHCI Compliant IEEE 1394 Host Controller
+		1186 1400  DFE-530TX rev A
+	3044  IEEE 1394 Host Controller
 	3050  VT82C596 Power Management
 	3051  VT82C596 Power Management
 	3057  VT82C686 [Apollo Super ACPI]
-	3058  AC97 Audio Controller
+		1043 8042  ATV133/A7V133-C
+	3058  VT82C686 AC97 Audio Controller
+		1458 7600  Onboard Audio
 		1462 3091  MS-6309 Onboard Audio
-	3059  AC97 Audio Controller
-	3065  Ethernet Controller
+	3059  VT8233 AC97 Audio Controller
+	3065  VT6102 [Rhine-II]
+		1186 1400  DFE-530TX rev A
+		1186 1401  DFE-530TX rev B
 	3068  AC97 Modem Controller
 	3074  VT8233 PCI to ISA Bridge
 	3091  VT8633 [Apollo Pro266]
 	3099  VT8367 [KT266]
+	3104  USB 2.0
 	3109  VT8233C PCI to ISA Bridge
+	3128  VT8753 [P4X266 AGP]
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
 	8231  VT8231 [PCI-to-ISA Bridge]
@@ -2161,6 +2565,7 @@
 	6120  SZB6120
 110b  Chromatic Research Inc.
 	0001  Mpact Media Processor
+	0004  Mpact 2
 110c  Mini-Max Technology, Inc.
 110d  Znyx Advanced Systems
 110e  CPU Technology
@@ -2184,6 +2589,7 @@
 	5105  10Mbps Network card
 	9211  EN-1207D Fast Ethernet Adapter
 		1113 9211  EN-1207D Fast Ethernet Adapter
+	9511  Fast Ethernet Adapter
 1114  Atmel Corporation
 1115  3D Labs
 1116  Data Translation
@@ -2288,6 +2694,7 @@
 	0001  Powerbis Bridge
 111d  Integrated Device Tech
 	0001  IDT77211 ATM Adapter
+	0003  IDT77252 ATM network controller
 111e  Eldec
 111f  Precision Digital Images
 	4a47  Precision MX Video engine interface
@@ -2330,8 +2737,11 @@
 	7912  EiconCard S91
 	7941  EiconCard S94
 	7942  EiconCard S94
+	7943  EiconCard S94
+	7944  EiconCard S94
 	b921  EiconCard P92
 	b922  EiconCard P92
+	b923  EiconCard P92
 	e001  DIVA 20PRO
 		1133 e001  DIVA Pro 2.0 S/T
 	e002  DIVA 20
@@ -2340,8 +2750,12 @@
 		1133 e003  DIVA Pro 2.0 U
 	e004  DIVA 20_U
 		1133 e004  DIVA 2.0 U
+	e005  DIVA LOW
+		1133 e005  DIVA 2.01 S/T
 	e010  DIVA Server BRI-2M
 		1133 e010  DIVA Server BRI-2M
+	e012  DIVA Server BRI-8M
+		1133 e012  DIVA Server BRI-8M
 	e014  DIVA Server PRI-30M
 		1133 e014  DIVA Server PRI-30M
 1134  Mercury Computer Systems
@@ -2368,8 +2782,8 @@
 113f  Equinox Systems, Inc.
 	0808  SST-64P Adapter
 	1010  SST-128P Adapter
-	80c0  SST-16P Adapter
-	80c4  SST-16P Adapter
+	80c0  SST-16P DB Adapter
+	80c4  SST-16P RJ Adapter
 	80c8  SST-16P Adapter
 	8888  SST-4P Adapter
 	9090  SST-8P Adapter
@@ -2416,6 +2830,7 @@
 		1148 9862  SK-9862 (1000Base-SX VF45 dual link)
 1149  Win System Corporation
 114a  VMIC
+	5579  VMIPCI-5579 (Reflective Memory Card)
 	7587  VMIVME-7587
 114b  Canopus Co., Ltd
 114c  Annabooks
@@ -2441,12 +2856,24 @@
 	001a  DataFirePRIme E1 (1-port)
 	001b  AccelePort C/X (IBM)
 	001d  DataFire RAS T1/E1/PRI
+		114f 0050  DataFire RAS E1 Adapter
+		114f 0051  DataFire RAS Dual E1 Adapter
+		114f 0052  DataFire RAS T1 Adapter
+		114f 0053  DataFire RAS Dual T1 Adapter
 	0023  AccelePort RAS
 	0024  DataFire RAS B4 ST/U
+		114f 0030  DataFire RAS BRI U Adapter
+		114f 0031  DataFire RAS BRI S/T Adapter
 	0026  AccelePort 4r 920
 	0027  AccelePort Xr 920
 	0034  AccelePort 2r 920
 	0035  DataFire DSP T1/E1/PRI cPCI
+	0040  AccelePort Xp
+	0042  AccelePort 2p PCI
+	0070  Datafire Micro V IOM2 (Europe)
+	0071  Datafire Micro V (Europe)
+	0072  Datafire Micro V IOM2 (North America)
+	0073  Datafire Micro V (North America)
 	6001  Avanstar
 1150  Thinking Machines Corp
 1151  JAE Electronics Inc.
@@ -2469,6 +2896,8 @@
 	0003  Cardbus Ethernet 10/100
 		1014 0181  10/100 EtherJet Cardbus Adapter
 		1014 1181  10/100 EtherJet Cardbus Adapter
+		1014 8181  10/100 EtherJet Cardbus Adapter
+		1014 9181  10/100 EtherJet Cardbus Adapter
 		115d 0181  Cardbus Ethernet 10/100
 		115d 1181  Cardbus Ethernet 10/100
 		8086 8181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
@@ -2486,6 +2915,7 @@
 	000b  Cardbus Ethernet 10/100
 		1014 0183  10/100 EtherJet Cardbus Adapter
 		115d 0183  Cardbus Ethernet 10/100
+	000c  Mini-PCI V.90 56k Modem
 	000f  Cardbus Ethernet 10/100
 		1014 0183  10/100 EtherJet Cardbus Adapter
 		115d 0183  Cardbus Ethernet 10/100
@@ -2516,7 +2946,7 @@
 	0201  CSB5 South Bridge
 	0211  OSB4 IDE Controller
 	0212  CSB5 IDE Controller
-	0220  OSB4/CSB5 OHCI USB Controller
+	0220  OSB4/CSB5 USB Controller
 1167  Mutoh Industries Inc
 1168  Thine Electronics Inc
 1169  Centre for Development of Advanced Computing
@@ -2567,6 +2997,7 @@
 	0476  RL5c476 II
 	0477  RL5c477
 	0478  RL5c478
+	0552  R5C552 IEEE 1394 Controller
 1181  Telmatics International
 1183  Fujikura Ltd
 1184  Forks Inc
@@ -2575,6 +3006,8 @@
 	0100  DC21041
 	1002  Sundance Ethernet
 	1300  RTL8139 Ethernet
+	1340  DFE-690TXD CardBus PC Card
+	1561  DRP-32TXD Cardbus PC Card
 	4000  DL2K Ethernet
 1187  Advanced Technology Laboratories, Inc.
 1188  Shima Seiki Manufacturing Ltd.
@@ -2694,6 +3127,7 @@
 	0440  56k WinModem
 		0001 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 		1033 8015  LT WinModem 56k Data+Fax+Voice+Dsvd
+		1033 8047  LT WinModem 56k Data+Fax+Voice+Dsvd
 		1033 804f  LT WinModem 56k Data+Fax+Voice+Dsvd
 		10cf 102c  LB LT Modem V.90 56k
 		10cf 104a  BIBLO LT Modem 56k
@@ -2701,15 +3135,18 @@
 		1179 0001  Internal V.90 Modem
 		11c1 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 		122d 4101  MDP7800-U Modem
+		122d 4102  MDP7800SP-U Modem
 		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 0441  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0450  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 f100  LT WinModem 56k Data+Fax+Voice+Dsvd
 		13e0 f101  LT WinModem 56k Data+Fax+Voice+Dsvd
 		144d 2101  LT56PV Modem
 		149f 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
 	0441  56k WinModem
 		1033 804d  LT WinModem 56k Data+Fax
+		1033 8065  LT WinModem 56k Data+Fax
 		1092 0440  Supra 56i
 		1179 0001  Internal V.90 Modem
 		11c1 0440  LT WinModem 56k Data+Fax
@@ -2719,11 +3156,16 @@
 		13e0 0100  LT WinModem 56k Data+Fax
 		13e0 0410  LT WinModem 56k Data+Fax
 		13e0 0420  TelePath Internet 56k WinModem
+		13e0 0440  LT WinModem 56k Data+Fax
 		13e0 0443  LT WinModem 56k Data+Fax
+		13e0 f102  LT WinModem 56k Data+Fax
 		1416 9804  CommWave 56k Modem
 		141d 0440  LT WinModem 56k Data+Fax
 		144f 0441  Lucent 56k V.90 DF Modem
+		144f 0449  Lucent 56k V.90 DF Modem
+		144f 110d  Lucent Win Modem
 		1468 0441  Presario 56k V.90 DF Modem
+		1668 0440  Lucent Win Modem
 	0442  56k WinModem
 		0001 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		11c1 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
@@ -2732,6 +3174,7 @@
 		13e0 0442  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		13fc 2471  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		144d 2104  LT56PT Modem
+		144f 1104  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		149f 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		1668 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 	0443  LT WinModem
@@ -2740,14 +3183,22 @@
 	0446  LT WinModem
 	0447  LT WinModem
 	0448  WinModem 56k
+		1014 0131  Lucent Win Modem
+		1033 8066  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0030  56k Voice Modem
 		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
+# Actiontech eth+modem card as used by Dell &c.
+		1668 2400  LT WinModem 56k (MiniPCI Ethernet+Modem)
 	0449  WinModem 56k
 		0e11 b14d  56k V.90 Modem
 		13e0 0020  LT WinModem 56k Data+Fax
 		13e0 0041  TelePath Internet 56k WinModem
+		1436 0440  Lucent Win Modem
 		144f 0449  Lucent 56k V.90 DFi Modem
+		1468 0440  Lucent Win Modem
 		1468 0449  Presario 56k V.90 DFi Modem
 	044a  F-1156IV WinModem (V90, 56KFlex)
+		10cf 1072  LB Global LT Modem
 		13e0 0012  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		13e0 0042  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
 		144f 1005  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
@@ -2755,6 +3206,7 @@
 	044c  LT WinModem
 	044d  LT WinModem
 	044e  LT WinModem
+	044f  V90 WildWire Modem
 	0450  LT WinModem
 	0451  LT WinModem
 	0452  LT WinModem
@@ -2766,7 +3218,11 @@
 	0458  LT WinModem
 	0459  LT WinModem
 	045a  LT WinModem
+	0461  V90 WildWire Modem
+	0462  V90 WildWire Modem
 	0480  Venus Modem (V90, 56KFlex)
+	5811  FW323
+		dead 0800  FireWire Host Bus Adapter
 11c2  Sand Microelectronics
 11c3  NEC Corp
 11c4  Document Technologies, Inc
@@ -2797,6 +3253,7 @@
 11d2  Intercom Inc.
 11d3  Trancell Systems Inc
 11d4  Analog Devices
+	1805  SM56 PCI modem
 	1889  AD1889 sound chip
 11d5  Ikon Corporation
 	0115  10115
@@ -2933,7 +3390,7 @@
 		1092 8030  Monster Fusion
 		1092 8035  Monster Fusion AGP
 		10b0 0001  Dragon 4000
-		1102 1017  CT6760 3D Blaster Banshee
+		1102 1018  3D Blaster Banshee VE
 		121a 0001  Voodoo Banshee AGP
 		121a 0003  Voodoo Banshee AGP SGRAM
 		121a 0004  Voodoo Banshee
@@ -2963,6 +3420,7 @@
 		121a 0062  Voodoo3 3500 TV (SECAM)
 	0009  Voodoo 4 / Voodoo 5
 		121a 0009  Voodoo5 AGP 5500/6000
+	0057  Voodoo 3/3000 [Avenger]
 121b  Advanced Telecommunications Modules
 121c  Nippon Texaco., Ltd
 121d  Lippert Automationstechnik GmbH
@@ -3035,8 +3493,12 @@
 1243  Delphax
 1244  AVM Audiovisuelles MKTG & Computer System GmbH
 	0700  B1 ISDN
+	0800  C4 ISDN
 	0a00  A1 ISDN [Fritz]
 		1244 0a00  FRITZ!Card ISDN Controller
+	0e00  Fritz!PCI v2.0 ISDN
+	1100  C2 ISDN
+	1200  T1 ISDN
 1245  A.P.D., S.A.
 1246  Dipix Technologies, Inc.
 1247  Xylon Research, Inc.
@@ -3044,11 +3506,14 @@
 1249  Samsung Electronics Co., Ltd.
 124a  AEG Electrocom GmbH
 124b  SBS/Greenspring Modular I/O
+	0040  cPCI-200 Four Slot IndustryPack carrier
+		124b 9080  PCI9080 Bridge
 124c  Solitron Technologies, Inc.
 124d  Stallion Technologies, Inc.
 	0000  EasyConnection 8/32
 	0002  EasyConnection 8/64
 	0003  EasyIO
+	0004  EasyConnection/RA
 124e  Cylink
 124f  Infotrend Technology, Inc.
 	0041  IFT-2000 Series RAID Controller
@@ -3095,10 +3560,22 @@
 	1989  ESS Modem
 		125d 1989  ESS Modem
 	1998  ES1983S Maestro-3i PCI Audio Accelerator
+		1028 00e6  ES1983S Maestro-3i (Dell Inspiron 8100)
 	1999  ES1983S Maestro-3i PCI Modem Accelerator
+	199a  ES1983S Maestro-3i PCI Audio Accelerator
+	199b  ES1983S Maestro-3i PCI Modem Accelerator
 	2808  ES336H Fax Modem (Later Model)
 	2838  ES2838/2839 SuperLink Modem
 	2898  ES2898 Modem
+		125d 0424  ES56-PI Data Fax Modem
+		125d 0425  ES56T-PI Data Fax Modem
+		125d 0426  ES56V-PI Data Fax Modem
+		125d 0427  VW-PI Data Fax Modem
+		125d 0428  ES56ST-PI Data Fax Modem
+		125d 0429  ES56SV-PI Data Fax Modem
+		147a c001  ES56-PI Data Fax Modem
+		14fe 0428  ES56-PI Data Fax Modem
+		14fe 0429  ES56-PI Data Fax Modem
 125e  Specialvideo Engineering SRL
 125f  Concurrent Technologies, Inc.
 1260  Harris Semiconductor
@@ -3194,7 +3671,9 @@
 		4942 4c4c  Creative Sound Blaster AudioPCI128
 	5880  5880 AudioPCI
 		1274 2000  Creative Sound Blaster AudioPCI128
+		1274 2003  Creative SoundBlaster AudioPCI 128
 		1274 5880  Creative Sound Blaster AudioPCI128
+		1458 a000  5880 AudioPCI On Motherboard 6OXET
 		1462 6880  5880 AudioPCI On Motherboard MS-6188 1.00
 		270f 2001  5880 AudioPCI On Motherboard 6CTR
 		270f 2200  5880 AudioPCI On Motherboard 6WTX
@@ -3203,6 +3682,7 @@
 1276  Switched Network Technologies, Inc.
 1277  Comstream
 1278  Transtech Parallel Systems Ltd.
+	0701  TPE3/TM3 PowerPC Node
 1279  Transmeta Corporation
 	0295  Northbridge
 	0395  LongRun Northbridge
@@ -3210,26 +3690,29 @@
 	0397  BIOS scratchpad
 127a  Rockwell International
 	1002  HCF 56k Data/Fax Modem
+		1092 094c  SupraExpress 56i PRO [Diamond SUP2380]
 		122d 4002  HPG / MDP3858-U # Aztech
 		122d 4005  MDP3858-E # Aztech
 		122d 4007  MDP3858-A/-NZ # Aztech
 		122d 4012  MDP3858-SA # Aztech
 		122d 4017  MDP3858-W # Aztech
 		122d 4018  MDP3858-W # Aztech
+		127a 1002  Rockwell 56K D/F HCF Modem
 	1003  HCF 56k Data/Fax Modem
 		0e11 b0bc  229-DF Zephyr # Compaq
 		0e11 b114  229-DF Cheetah # Compaq
 		1033 802b  229-DF # NEC
 		13df 1003  PCI56RX Modem # E-Tech Inc
 		13e0 0117  IBM # GVC
-		13e0 0147  IBM # GVC
+		13e0 0147  IBM # GVC F-1156IV /R3 Spain V.90 Modem
 		13e0 0197  IBM # GVC
-		13e0 01c7  IBM # GVC
+		13e0 01c7  IBM # GVC F-1156IV /R3 WW V.90 Modem
 		13e0 01f7  IBM # GVC
 		1436 1003  IBM # CIS
-		1436 1103  IBM # CIS
+		1436 1103  IBM # CIS 5614PM3G V.90 Modem
 		1436 1602  Compaq 229-DF Ducati
 	1004  HCF 56k Data/Fax/Voice Modem
+		1048 1500  MicroLink 56k Modem
 		10cf 1059  Fujitsu 229-DFRT
 	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		1033 8029  229-DFSV # NEC
@@ -3250,16 +3733,19 @@
 		13df 1005  PCI56RVP Modem  # E-Tech Inc
 		13e0 0187  IBM # GVC
 		13e0 01a7  IBM # GVC
-		13e0 01b7  IBM # GVC
-		13e0 01d7  IBM # GVC
+		13e0 01b7  IBM # GVC DF-1156IV /R3 Spain V.90 Modem
+		13e0 01d7  IBM # GVC DF-1156IV /R3 WW V.90 Modem
 		1436 1005  IBM # CIS
 		1436 1105  IBM # CIS
+		1437 1105  IBM # CIS 5614PS3G V.90 Modem
+	1022  HCF 56k Modem
+		1436 1303  M3-5614PM3G V.90 Modem
 	1023  HCF 56k Data/Fax Modem
 		122d 4020  Packard Bell MDP3858-WE # Aztech
 		122d 4023  MDP3858-UE # Aztech
-		13e0 0247  IBM # GVC
+		13e0 0247  IBM # GVC F-1156IV /R6 Spain V.90 Modem
 		13e0 0297  IBM # GVC
-		13e0 02c7  IBM # GVC
+		13e0 02c7  IBM # GVC F-1156IV /R6 WW V.90 Modem
 		1436 1203  IBM # CIS
 		1436 1303  IBM # CIS
 	1024  HCF 56k Data/Fax/Voice Modem
@@ -3270,7 +3756,11 @@
 		122d 4024  MDP3858V-UE # Aztech
 		122d 4025  MDP3858SP-UE # Aztech
 	1026  HCF 56k PCI Speakerphone Modem
+	1032  HCF 56k Modem
+	1033  HCF 56k Modem
+	1034  HCF 56k Modem
 	1035  HCF 56k PCI Speakerphone Modem
+	1036  HCF 56k Modem
 	1085  HCF 56k Volcano PCI Modem
 	2005  HCF 56k Data/Fax Modem
 		104d 8044  229-DFSV # Sony
@@ -3310,6 +3800,7 @@
 	4322  Riptide PCI Game Controller
 		1235 4322  Riptide PCI Game Controller
 	8234  RapidFire 616X ATM155 Adapter
+		108d 0022  RapidFire 616X ATM155 Adapter
 		108d 0027  RapidFire 616X ATM155 Adapter
 127b  Pixera Corporation
 127c  Crosspoint Solutions, Inc.
@@ -3361,6 +3852,7 @@
 1298  Spellcaster Telecommunications Inc.
 1299  Knowledge Technology Lab.
 129a  VMetro, inc.
+	0615  PBT-615 PCI-X Bus Analyzer
 129b  Image Access
 129c  Jaycor
 129d  Compcore Multimedia, Inc.
@@ -3383,8 +3875,10 @@
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
 	0001  AceNIC Gigabit Ethernet (Fibre)
-		1410 0104  Gigabit Ethernet-SX PCI Adapter (14100401)
+		12ae 0001  Gigabit Ethernet-SX (Universal)
+		1410 0104  Gigabit Ethernet-SX PCI Adapter
 	0002  AceNIC Gigabit Ethernet (Copper)
+		12ae 0002  Gigabit Ethernet-T (3C986-T)
 12af  TDK USA Corp
 12b0  Jorge Scientific Corp
 12b1  GammaLink
@@ -3450,19 +3944,24 @@
 	0008  NV1
 	0009  DAC64
 	0018  Riva128
+		1048 0c10  VICTORY Erazor
 		107b 8030  STB Velocity 128
 		1092 0350  Viper V330
 		1092 1092  Viper V330
 		10b4 1b1b  STB Velocity 128
-		10b4 1b20  STB Velocity 128
+		10b4 1b1d  STB Velocity 128
+		10b4 1b1e  STB Velocity 128, PAL TV-Out
+		10b4 1b20  STB Velocity 128 Sapphire
 		10b4 1b21  STB Velocity 128
 		10b4 1b22  STB Velocity 128 AGP, NTSC TV-Out
 		10b4 1b23  STB Velocity 128 AGP, PAL TV-Out
 		10b4 1b27  STB Velocity 128 DVD
+		10b4 1b88  MVP Pro 128
 		10b4 222a  STB Velocity 128 AGP
 		10b4 2230  STB Velocity 128
+		10b4 2232  STB Velocity 128
 		10b4 2235  STB Velocity 128 AGP
-		2a15 54a3  3DVision-SAGP
+		2a15 54a3  3DVision-SAGP / 3DexPlorer 3000
 	0019  Riva128ZX
 	0020  TNT
 	0028  TNT2
@@ -3470,7 +3969,7 @@
 	002c  VTNT2
 	00a0  ITNT2
 12d3  Vingmed Sound A/S
-12d4  DGM&S
+12d4  Ulticom (Formerly DGM&S)
 12d5  Equator Technologies
 12d6  Analogic Corp
 12d7  Biotronic SRL
@@ -3769,6 +4268,7 @@
 1383  Controlnet Inc
 1384  Reality Simulation Systems Inc
 1385  Netgear
+	4100  802.11b Wireless Adapter (MA301)
 	620a  GA620
 	622a  GA622
 	630a  GA630
@@ -3794,6 +4294,7 @@
 	2180  Intellio C218 Turbo PCI
 	3200  Intellio C320 Turbo PCI
 1394  Level One Communications
+	0001  LXT1001 Gigabit Ethernet
 1395  Ambicom Inc
 1396  Cipher Systems Inc
 1397  Cologne Chip Designs GmbH
@@ -3811,12 +4312,17 @@
 13a0  Crystal Group Inc
 13a1  Kawasaki Heavy Industries Ltd
 13a2  Ositech Communications Inc
-13a3  Hi-Fn
+13a3  Hifn Inc.
+	0005  7751 Security Processor
+	0006  6500 Public Key Processor
+	0007  7811 Security Processor
+	0012  7951 Security Processor
 13a4  Rascom Inc
 13a5  Audio Digital Imaging Inc
 13a6  Videonics Inc
 13a7  Teles AG
 13a8  Exar Corp.
+	0158  XR17C158 Octal UART
 13a9  Siemens Medical Systems, Ultrasound Group
 13aa  Broadband Networks Inc
 13ab  Arcom Control Systems Ltd
@@ -3861,6 +4367,7 @@
 13cf  Studio Audio & Video Ltd
 13d0  Techsan Electronics Co Ltd
 13d1  Abocom Systems Inc
+	ab06  RTL8139 [FE2000VX] CardBus Fast Ethernet Attached Port Adapter
 13d2  Shark Multimedia Inc
 13d3  IMC Networks
 13d4  Graphics Microsystems Inc
@@ -3898,7 +4405,8 @@
 13f1  Oce' - Technologies B.V.
 13f2  Ford Microelectronics Inc
 13f3  Mcdata Corporation
-13f4  Troika Design Inc
+13f4  Troika Networks, Inc.
+	1401  Zentai Fibre Channel Adapter
 13f5  Kansai Electric Co. Ltd
 13f6  C-Media Electronics Inc
 	0100  CM8338A
@@ -3906,6 +4414,7 @@
 	0101  CM8338B
 		13f6 0101  CMI8338-031 PCI Audio Device
 	0111  CM8738
+		1043 8077  CMI8738 6-channel audio controller
 		13f6 0111  CMI8738/C3DX PCI Audio Device
 	0211  CM8738
 13f7  Wildfire Communications
@@ -3940,6 +4449,7 @@
 	8800  BOCA Research IOPPAR
 1408  Aloka Co. Ltd
 1409  Timedia Technology Co Ltd
+	7168  PCI2S550 (Dual 16550 UART)
 140a  DSP Research Inc
 140b  Ramix Inc
 140c  Elmic Systems Inc
@@ -3953,7 +4463,14 @@
 1413  Addonics
 1414  Microsoft Corporation
 1415  Oxford Semiconductor Ltd
-	9521  Oxford Semi OX16PCI952 PCI/dual 16950 UART
+	8403  VScom 011H-EP1 1 port parallel adaptor
+	9501  Quad 16950 UART
+		15ed 2000  MCCR Serial p0-3 of 8
+		15ed 2001  MCCR Serial p0-3 of 16
+	9511  OX16PCI954 (Quad 16950 UART) function 1
+		15ed 2000  MCCR Serial p4-7 of 8
+		15ed 2001  MCCR Serial p4-15 of 16
+	9521  OX16PCI952 (Dual 16950 UART)
 1416  Multiwave Innovation pte Ltd
 1417  Convergenet Technologies Inc
 1418  Kyushu electronics systems Inc
@@ -4130,6 +4647,10 @@
 14b8  Techsoft Technology Co Ltd
 14b9  AIRONET Wireless Communications
 	0001  PC4800
+	0340  PC4800
+	0350  PC4800
+	4500  PC4500
+	4800  PC4800
 14ba  INTERNIX Inc.
 14bb  SEMTECH Corporation
 14bc  Globespan Semiconductor Inc.
@@ -4155,6 +4676,22 @@
 14d0  Ericsson Axe R & D
 14d1  Computer Hi-Tech Co Ltd
 14d2  Titan Electronics Inc
+	8001  VScom 010L 1 port parallel adaptor
+	8002  VScom 020L 2 port parallel adaptor
+	8010  VScom 100L 1 port serial adaptor
+	8011  VScom 110L 1 port serial and 1 port parallel adaptor
+	8020  VScom 200L 1 port serial adaptor
+	8021  VScom 210L 2 port serial and 1 port parallel adaptor
+	8040  VScom 400L 4 port serial adaptor
+	8080  VScom 800L 8 port serial adaptor
+	a000  VScom 010H 1 port parallel adaptor
+	a001  VScom 100H 1 port serial adaptor
+	a003  VScom 400H 4 port serial adaptor
+	a004  VScom 400HF1 4 port serial adaptor
+	a005  VScom 200H 2 port serial adaptor
+	e001  VScom 010HV2 1 port parallel adaptor
+	e010  VScom 100HV2 1 port serial adaptor
+	e020  VScom 200HV2 2 port serial adaptor
 14d3  CIRTECH (UK) Ltd
 14d4  Panacom Technology Corp
 14d5  Nitsuko Corporation
@@ -4184,27 +4721,29 @@
 14e3  AMTELCO
 14e4  BROADCOM Corporation
 	1644  NetXtreme BCM5700 Gigabit Ethernet
-		1014 0277  Broadcom Vigil B5700 1000Base-T
-		1028 00d1  Broadcom BCM5700
-		1028 0106  Broadcom BCM5700
-		1028 0109  Broadcom BCM5700
-		1028 010a  Broadcom BCM5700
+		1014 0277  Vigil B5700 1000BaseTX
+		1028 00d1  NetXtreme 1000BaseTX
+		1028 0106  NetXtreme 1000BaseTX
+		1028 0109  NetXtreme 1000BaseTX
 		10b7 1000  3C996-T 1000BaseTX
 		10b7 1001  3C996B-T 1000BaseTX
 		10b7 1002  3C996C-T 1000BaseTX
-		10b7 1003  3C997-T 1000BaseTX
+		10b7 1003  3C997-T 1000BaseTX Dual Port
 		10b7 1004  3C996-SX 1000BaseSX
-		10b7 1005  3C997-SX 1000BaseSX
+		10b7 1005  3C997-SX 1000BaseSX Dual Port
 		10b7 1008  3C942 Gigabit LOM (31X31)
 		14e4 0002  NetXtreme 1000BaseSX
 		14e4 0003  NetXtreme 1000BaseSX
 		14e4 0004  NetXtreme 1000BaseTX
+		14e4 1028  NetXtreme 1000BaseTX
 		14e4 1644  NetXtreme BCM5700 1000BaseTX
 	1645  NetXtreme BCM5701 Gigabit Ethernet
-		0e11 007c  NC7770 1000BaseTX
-		0e11 007d  NC6770 1000BaseSX
-		0e11 0085  NC7780 1000BaseTX
-		1028 0121  Broadcom BCM5701
+		0e11 007c  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		0e11 007d  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)
+		0e11 0085  NC7780 Gigabit Server Adapter (embedded, WOL)
+		0e11 0099  NC7780 Gigabit Server Adapter (embedded, WOL)
+		0e11 009a  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		1028 0121  NetXtreme BCM5701 1000BaseTX
 		10b7 1004  3C996-SX 1000BaseSX
 		10b7 1006  3C996B-T 1000BaseTX
 		10b7 1007  3C1000-T 1000BaseTX
@@ -4216,15 +4755,21 @@
 		14e4 0008  NetXtreme BCM5701 1000BaseTX
 		14e4 8008  NetXtreme BCM5701 1000BaseTX
 	1646  NetXtreme BCM5702 Gigabit Ethernet
-		14e4 8009  Broadcom BCM5702
+		0e11 00bb  NC7760 1000BaseTX
+		1028 0126  NetXtreme BCM5702 1000BaseTX
+		14e4 8009  NetXtreme BCM5702 1000BaseTX
 	1647  NetXtreme BCM5703 Gigabit Ethernet
-		0e11 009a  NC7770
-		0e11 0099  NC7780
-		14e4 0009  Broadcom BCM5703
-		14e4 8009  Broadcom BCM5703
+		0e11 0099  NC7780 1000BaseTX
+		0e11 009a  NC7770 1000BaseTX
+		14e4 0009  NetXtreme BCM5703 1000BaseTX
+		14e4 000a  NetXtreme BCM5703 1000BaseSX
+		14e4 000b  NetXtreme BCM5703 1000BaseTX
+		14e4 8009  NetXtreme BCM5703 1000BaseTX
+		14e4 800a  NetXtreme BCM5703 1000BaseTX
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 	16a7  NetXtreme BCM5703X Gigabit Ethernet
+	4212  BCM v.90 56k modem
 	5820  BCM5820 Crypto Accelerator
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
@@ -4239,14 +4784,30 @@
 14ef  CARRY Computer ENG. CO Ltd
 14f0  CANON RESEACH CENTRE FRANCE
 14f1  Conexant
+	1002  HCF 56k Modem
+	1003  HCF 56k Modem
+	1004  HCF 56k Modem
+	1005  HCF 56k Modem
+	1006  HCF 56k Modem
+	1022  HCF 56k Modem
+	1023  HCF 56k Modem
+	1024  HCF 56k Modem
+	1025  HCF 56k Modem
+	1026  HCF 56k Modem
+	1032  HCF 56k Modem
 	1033  HCF 56k Data/Fax Modem
+		1033 8077  NEC
 		122d 4027  Dell Zeus - MDP3880-W(B) Data Fax Modem
 		122d 4030  Dell Mercury - MDP3880-U(B) Data Fax Modem
 		122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem
 		13e0 020d  Dell Copper
 		13e0 020e  Dell Silver
+		13e0 0261  IBM # GVC
 		13e0 0290  Compaq Goldwing
+		13e0 02a0  IBM # GVC
+		13e0 02b0  IBM # GVC
 		13e0 02c0  Compaq Scooter
+		13e0 02d0  IBM # GVC
 		144f 1500  IBM P85-DF (1)
 		144f 1501  IBM P85-DF (2)
 		144f 150a  IBM P85-DF (3)
@@ -4256,6 +4817,7 @@
 	1035  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 		10cf 1098  Fujitsu P85-DFSV
 	1036  HCF 56k Data/Fax/Voice/Spkp Modem
+		104d 8067  HCF 56k Modem
 		122d 4029  MDP3880SP-W
 		122d 4031  MDP3880SP-U
 		13e0 0209  Dell Titanium
@@ -4279,6 +4841,8 @@
 	1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
 	1436  HCF 56k Data/Fax Modem
 	1453  HCF 56k Data/Fax Modem
+		13e0 0240  IBM # GVC
+		13e0 0250  IBM # GVC
 		144f 1502  IBM P95-DF (1)
 		144f 1503  IBM P95-DF (2)
 	1454  HCF 56k Data/Fax/Voice Modem
@@ -4300,6 +4864,9 @@
 		0e11 b195  Bear
 		0e11 b196  Seminole 1
 		0e11 b1be  Seminole 2
+		1025 8013  Acer
+		1033 809d  NEC
+		1033 80bc  NEC
 		155d 6793  HP
 		155d 8850  E Machines
 	2014  HSF 56k Data/Fax/Voice Modem
@@ -4332,6 +4899,9 @@
 	2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)
 	2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA)
 	2443  HSF 56k Data/Fax Modem (Mob WorldW SmartDAA)
+		104d 8075  Modem # Sony
+		104d 8083  Modem # Sony
+		104d 8097  Modem # Sony
 	2444  HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA)
 	2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA)
 	2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA)
@@ -4401,9 +4971,16 @@
 151d  Fujitsu Computer Products Of America
 151e  MATRIX Corp
 151f  TOPIC SEMICONDUCTOR Corp
+	0000  TP560 Data/Fax/Voice 56k modem
 1520  CHAPLET System Inc
 1521  BELL Corp
 1522  MainPine Ltd
+	0100  PCI <-> IOBus Bridge
+		1522 0200  RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0300  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0400  RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0500  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0600  RockForce+ 2 Port V.90 Data/Fax/Voice Modem
 1523  MUSIC Semiconductors
 1524  ENE Technology Inc
 1525  IMPACT Technologies
@@ -4558,6 +5135,7 @@
 15a0  Compumaster SRL
 15a1  Geocast Network Systems
 15a2  Catalyst Enterprises Inc
+	0001  TA700 PCI Bus Analyzer/Exerciser
 15a3  Italtel
 15a4  X-Net OY
 15a5  Toyota Macs Inc
@@ -4574,6 +5152,7 @@
 15b1  Source Technology Inc
 15b2  Mosaid Technologies Inc
 15b3  Mellanox Technology
+	5274  MT21108 InfiniBridge
 15b4  CCI/TRIAD
 15b5  Cimetrics Inc
 15b6  Texas Memory Systems Inc
@@ -4583,6 +5162,7 @@
 15ba  Impacct Technology Corp
 15bb  Portwell Inc
 15bc  Agilent Technologies
+	2929  E2929A PCI/PCI-X Bus Analyzer
 15bd  DFI Inc
 15be  Sola Electronics
 15bf  High Tech Computer Corp (HTC)
@@ -4663,9 +5243,18 @@
 1619  FarSite Communications Ltd
 	0400  FarSync T2P (2 port X.21/V.35/V.24)
 	0440  FarSync T4P (4 port X.21/V.35/V.24)
+1629  Kongsberg Spacetec AS
+	1003  Format synchronizer v3.0
+	2002  Fast Universal Data Output
+1657  Brocade Communications Systems, Inc.
 1668  Action Tec Electronics Inc
+16f6  VideoTele.com, Inc.
+170b  NetOctave Inc
+170c  YottaYotta Inc.
 173b  Altima (nee BroadCom)
 	03e8  AC1000 Gigabit Ethernet
+1743  Peppercon AG
+	8139  ROL/F-100 Fast Ethernet Adapter with ROL
 1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
 	0000  SC15064
@@ -4691,6 +5280,7 @@
 3000  Hansol Electronics Inc.
 3142  Post Impression Systems.
 3388  Hint Corp
+	0021  HB1-SE33 PCI-PCI Bridge
 	8011  VXPro II Chipset
 		3388 8011  VXPro II Chipset CPU to PCI Bridge
 	8012  VXPro II Chipset
@@ -4710,6 +5300,7 @@
 	0007  3D Extreme
 	0008  GLINT Gamma G1
 	0009  Permedia II 2D+3D
+		1040 0011  AccelStar II
 		3d3d 0100  AccelStar II 3D Accelerator
 		3d3d 0111  Permedia 3:16
 		3d3d 0114  Santa Ana
@@ -4739,6 +5330,7 @@
 	2501  ALG-2564A/25128A
 	4000  ALS4000 Audio Chipset
 		4005 4000  ALS4000 Audio Chipset
+	4710  ALC200/200P
 4033  Addtron Technology Co, Inc.
 	1360  RTL8139 Ethernet
 4143  Digital Equipment Corp
@@ -4765,6 +5357,8 @@
 	0200  MQ-200
 4d54  Microtechnica Co Ltd
 4ddc  ILC Data Device Corp
+5046  GemTek Technology Corporation
+	1001  PCI Radio
 5053  Voyetra Technologies
 	2010  Daytona Audio Adapter
 5136  S S Technologies
@@ -4808,7 +5402,7 @@
 	88f3  86c968 [Vision 968 VRAM] rev 3
 	8900  86c755 [Trio 64V2/DX]
 		5333 8900  86C775 Trio64V2/DX
-	8901  Trio 64V2/DX or /GX
+	8901  86c775/86c785 [Trio 64V2/DX or /GX]
 		5333 8901  86C775 Trio64V2/DX, 86C785 Trio64V2/GX
 	8902  Plato/PX
 	8903  Trio 3D business multimedia
@@ -4837,9 +5431,11 @@
 		5333 8a13  Trio3D/2X
 	8a20  86c794 [Savage 3D]
 		5333 8a20  86C391 Savage3D
-	8a21  86c795 [Savage 3D/MV]
+	8a21  86c390 [Savage 3D/MV]
 		5333 8a21  86C390 Savage3D/MV
 	8a22  Savage 4
+		1033 8068  Savage 4
+		1033 8069  Savage 4
 		105d 0018  SR9 8Mb SDRAM
 		105d 002a  SR9 Pro 16Mb SDRAM
 		105d 003a  SR9 Pro 32Mb SDRAM
@@ -4921,21 +5517,51 @@
 	04d0  82437FX [Triton FX]
 	0600  RAID Controller
 	0960  80960RP [i960 RP Microprocessor/Bridge]
+	0962  80960RM [i960RM Bridge]
 	0964  80960RP [i960 RP Microprocessor/Bridge]
 	1000  82542 Gigabit Ethernet Controller
-		0e11 b0df  NC1632 Gigabit Ethernet Adapter
-		0e11 b0e0  NC1633 Gigabit Ethernet Adapter
-		0e11 b123  NC1634 Gigabit Ethernet Adapter
+		0e11 b0df  NC1632 Gigabit Ethernet Adapter (1000-SX)
+		0e11 b0e0  NC1633 Gigabit Ethernet Adapter (1000-LX)
+		0e11 b123  NC1634 Gigabit Ethernet Adapter (1000-SX)
 		1014 0119  Netfinity Gigabit Ethernet SX Adapter
+		8086 1000  PRO/1000 Gigabit Server Adapter
 	1001  82543GC Gigabit Ethernet Controller
+		0e11 004a  NC6136 Gigabit Server Adapter
+		1014 01ea  Netfinity Gigabit Ethernet SX Adapter
+		8086 1003  PRO/1000 F Server Adapter
+	1002  Pro 100 LAN Modem 56 Cardbus II
+		8086 200e  Pro 100 LAN Modem 56 Cardbus II
+		8086 2013  Pro 100 SR Mobile Combo Adapter
+		8086 2017  Pro 100 S Combo Mobile Adapter
 	1004  82543GC Gigabit Ethernet Controller
+		0e11 0049  NC7132 Gigabit Upgrade Module
+		0e11 b1a4  NC7131 Gigabit Server Adapter
+		1014 10f2  Gigabit Ethernet Server Adapter
+		8086 1004  PRO/1000 T Server Adapter
+		8086 2004  PRO/1000 T Server Adapter
 	1008  82544EI Gigabit Ethernet Controller
+		8086 1107  PRO/1000 XT Server Adapter
+		8086 2107  PRO/1000 XT Server Adapter
+		8086 2110  PRO/1000 XT Server Adapter
 	1009  82544EI Gigabit Ethernet Controller
+		8086 1109  PRO/1000 XF Server Adapter
+		8086 2109  PRO/1000 XF Server Adapter
 	100c  82544GC Gigabit Ethernet Controller
+		8086 1109  PRO/1000 T Desktop Adapter
+		8086 1112  PRO/1000 T Desktop Adapter
+		8086 2109  PRO/1000 T Desktop Adapter
+		8086 2112  PRO/1000 T Desktop Adapter
 	100d  82544GC Gigabit Ethernet Controller
 	1029  82559 Ethernet Controller
 	1030  82559 InBusiness 10/100
 	1031  82801CAM (ICH3) Chipset Ethernet Controller
+		1014 0209  EtherExpress PRO/100 VE
+		104d 80e7  Vaio PCG Series
+		107b 5350  EtherExpress PRO/100 VE
+		1179 0001  EtherExpress PRO/100 VE
+		144d c000  EtherExpress PRO/100 VE
+		144d c001  EtherExpress PRO/100 VE
+		144d c003  EtherExpress PRO/100 VE
 	1032  82801CAM (ICH3) Chipset Ethernet Controller
 	1033  82801CAM (ICH3) Chipset Ethernet Controller
 	1034  82801CAM (ICH3) Chipset Ethernet Controller
@@ -4944,8 +5570,12 @@
 	1037  82801CAM (ICH3) Chipset Ethernet Controller
 	1038  82801CAM (ICH3) Chipset Ethernet Controller
 	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
+	1131  82815 815 Chipset AGP Bridge
 	1132  82815 CGC [Chipset Graphics Controller]
 	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
+		8086 1161  82806AA PCI64 Hub APIC
+	1200  Unknown device
+		172a 0000  AEP SSL Accelerator
 	1209  82559ER
 	1221  82092AA_0
 	1222  82092AA_1
@@ -4954,31 +5584,61 @@
 	1226  82596 PRO/10 PCI
 	1227  82865 EtherExpress PRO/100A
 	1228  82556 EtherExpress PRO/100 Smart
-	1229  82557 [Ethernet Pro 100]
-		0e11 b01e  NC3120
-		0e11 b01f  NC3122
-		0e11 b02f  NC1120
+# the revision field differentiates between them (1-3 is 82557, 4-5 is 82558, 6-8 is 82559, 9 is 82559ER)
+	1229  82557/8/9 [Ethernet Pro 100]
+		0e11 3001  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3002  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3003  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3004  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3005  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3006  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3007  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 b01e  NC3120 Fast Ethernet NIC
+		0e11 b01f  NC3122 Fast Ethernet NIC (dual port)
+		0e11 b02f  NC1120 Ethernet NIC
 		0e11 b04a  Netelligent 10/100TX NIC with Wake on LAN
-		0e11 b0c6  Embedded NC3120 with Wake on LAN
-		0e11 b0c7  Embedded NC3121
-		0e11 b0d7  NC3121 with Wake on LAN
-		0e11 b0dd  NC3131 (82558B)
-		0e11 b0de  NC3132
-		0e11 b0e1  NC3133
-		0e11 b144  NC3123 (82559)
+		0e11 b0c6  NC3161 Fast Ethernet NIC (embedded, WOL)
+		0e11 b0c7  NC3160 Fast Ethernet NIC (embedded)
+		0e11 b0d7  NC3121 Fast Ethernet NIC (WOL)
+		0e11 b0dd  NC3131 Fast Ethernet NIC (dual port)
+		0e11 b0de  NC3132 Fast Ethernet Module (dual port)
+		0e11 b0e1  NC3133 Fast Ethernet Module (100-FX)
+		0e11 b134  NC3163 Fast Ethernet NIC (embedded, WOL)
+		0e11 b13c  NC3162 Fast Ethernet NIC (embedded)
+		0e11 b144  NC3123 Fast Ethernet NIC (WOL)
+		0e11 b163  NC3134 Fast Ethernet NIC (dual port)
+		0e11 b164  NC3135 Fast Ethernet Upgrade Module (dual port)
+		0e11 b1a4  NC7131 Gigabit Server Adapter
 		1014 005c  82558B Ethernet Pro 10/100
+		1014 01f1  10/100 Ethernet Server Adapter
+		1014 01f2  10/100 Ethernet Server Adapter
+		1014 0207  Ethernet Pro/100 S
+		1014 0232  10/100 Dual Port Server Adapter
 		1014 105c  Netfinity 10/100
+		1014 305c  10/100 EtherJet Management Adapter
+		1014 405c  10/100 EtherJet Adapter with Alert on LAN
+		1014 505c  10/100 EtherJet Secure Management Adapter
+		1014 605c  10/100 EtherJet Secure Management Adapter
+		1014 705c  10/100 Netfinity 10/100 Ethernet Security Adapter
+		1014 805c  10/100 Netfinity 10/100 Ethernet Security Adapter
 		1033 8000  PC-9821X-B06
 		1033 8016  PK-UG-X006
 		1033 801f  PK-UG-X006
-		103c 10c0  Ethernet Pro 10/100TX
-		103c 10c3  Ethernet Pro 10/100TX
-		103c 1200  Ethernet Pro 10/100TX
+		103c 10c0  NetServer 10/100TX
+		103c 10c3  NetServer 10/100TX
+		103c 10ca  NetServer 10/100TX
+		103c 10cb  NetServer 10/100TX
+		103c 10e3  NetServer 10/100TX
+		103c 10e4  NetServer 10/100TX
+		103c 1200  NetServer 10/100TX
 		10c3 1100  SmartEther100 SC1100
 		1179 0002  PCI FastEther LAN on Docker
 		1259 2560  AT-2560 100
 		1259 2561  AT-2560 100 FX Ethernet Adapter
 		1266 0001  NE10/100 Adapter
+		144d 2501  SEM-2000 MiniPCI LAN Adapter
+		144d 2502  SEM-2100IL MiniPCI LAN Adapter
+		1668 1100  EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem)
 		8086 0001  EtherExpress PRO/100B (TX)
 		8086 0002  EtherExpress PRO/100B (T4)
 		8086 0003  EtherExpress PRO/10+
@@ -4993,14 +5653,76 @@
 		8086 000c  EtherExpress PRO/100+ Management Adapter
 		8086 000d  EtherExpress PRO/100+ Alert On LAN II* Adapter
 		8086 000e  EtherExpress PRO/100+ Management Adapter with Alert On LAN*
+		8086 000f  EtherExpress PRO/100 Desktop Adapter
+		8086 0010  EtherExpress PRO/100 S Management Adapter
+		8086 0011  EtherExpress PRO/100 S Management Adapter
+		8086 0012  EtherExpress PRO/100 S Advanced Management Adapter (D)
+		8086 0013  EtherExpress PRO/100 S Advanced Management Adapter (E)
+		8086 0030  EtherExpress PRO/100  Management Adapter with Alert On LAN* GC
+		8086 0031  EtherExpress PRO/100 Desktop Adapter
+		8086 0040  EtherExpress PRO/100 S Desktop Adapter
+		8086 0041  EtherExpress PRO/100 S Desktop Adapter
+		8086 0042  EtherExpress PRO/100 Desktop Adapter
+		8086 0050  EtherExpress PRO/100 S Desktop Adapter
 		8086 1009  EtherExpress PRO/100+ Server Adapter
 		8086 100c  EtherExpress PRO/100+ Server Adapter (PILA8470B)
+		8086 1012  EtherExpress PRO/100 S Server Adapter (D)
+		8086 1013  EtherExpress PRO/100 S Server Adapter (E)
+		8086 1015  EtherExpress PRO/100 S Dual Port Server Adapter
+		8086 1017  EtherExpress PRO/100+ Dual Port Server Adapter
+		8086 1030  EtherExpress PRO/100+ Management Adapter with Alert On LAN* G Server
+		8086 1040  EtherExpress PRO/100 S Server Adapter
+		8086 1041  EtherExpress PRO/100 S Server Adapter
+		8086 1042  EtherExpress PRO/100 Server Adapter
+		8086 1050  EtherExpress PRO/100 S Server Adapter
+		8086 1051  EtherExpress PRO/100 Server Adapter
+		8086 1052  EtherExpress PRO/100 Server Adapter
 		8086 10f0  EtherExpress PRO/100+ Dual Port Adapter
+		8086 2009  EtherExpress PRO/100 S Mobile Adapter
 		8086 200d  EtherExpress PRO/100 Cardbus
 		8086 200e  EtherExpress PRO/100 LAN+V90 Cardbus Modem
+		8086 200f  EtherExpress PRO/100 SR Mobile Adapter
+		8086 2010  EtherExpress PRO/100 S Mobile Combo Adapter
+		8086 2013  EtherExpress PRO/100 SR Mobile Combo Adapter
+		8086 2016  EtherExpress PRO/100 S Mobile Adapter
+		8086 2017  EtherExpress PRO/100 S Combo Mobile Adapter
+		8086 2018  EtherExpress PRO/100 SR Mobile Adapter
+		8086 2019  EtherExpress PRO/100 SR Combo Mobile Adapter
+		8086 2101  EtherExpress PRO/100 P Mobile Adapter
+		8086 2102  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2103  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2104  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2105  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2106  EtherExpress PRO/100 P Mobile Adapter
+		8086 2107  EtherExpress PRO/100 Network Connection
+		8086 2108  EtherExpress PRO/100 Network Connection
+		8086 2200  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2201  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2202  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2203  EtherExpress PRO/100+ MiniPCI
+		8086 2204  EtherExpress PRO/100+ MiniPCI
+		8086 2205  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2206  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2207  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2208  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2402  EtherExpress PRO/100+ MiniPCI
+		8086 2407  EtherExpress PRO/100+ MiniPCI
+		8086 2408  EtherExpress PRO/100+ MiniPCI
+		8086 2409  EtherExpress PRO/100+ MiniPCI
+		8086 240f  EtherExpress PRO/100+ MiniPCI
+		8086 2410  EtherExpress PRO/100+ MiniPCI
+		8086 2411  EtherExpress PRO/100+ MiniPCI
+		8086 2412  EtherExpress PRO/100+ MiniPCI
+		8086 2413  EtherExpress PRO/100+ MiniPCI
 		8086 3000  82559 Fast Ethernet LAN on Motherboard
 		8086 3001  82559 Fast Ethernet LOM with Basic Alert on LAN*
 		8086 3002  82559 Fast Ethernet LOM with Alert on LAN II*
+		8086 3006  EtherExpress PRO/100 S Network Connection
+		8086 3007  EtherExpress PRO/100 S Network Connection
+		8086 3008  EtherExpress PRO/100 Network Connection
+		8086 3010  EtherExpress PRO/100 S Network Connection
+		8086 3011  EtherExpress PRO/100 S Network Connection
+		8086 3012  EtherExpress PRO/100 Network Connection
 	122d  430FX - 82437FX TSC [Triton I]
 	122e  82371FB PIIX ISA [Triton I]
 	1230  82371FB PIIX IDE [Triton I]
@@ -5012,24 +5734,38 @@
 	123b  82380PB
 	123c  82380AB
 	123d  683053 Programmable Interrupt Device
+	123f  82466GX Integrated Hot-Plug Controller (IHPC)
 	1240  752 AGP
 	124b  82380FB
 	1250  430HX - 82439HX TXC [Triton II]
 	1360  82806AA PCI64 Hub PCI Bridge
 	1361  82806AA PCI64 Hub Controller (HRes)
+	1460  82870P2 P64H2 Hub PCI Bridge
+	1461  82870P2 P64H2 I/OxAPIC
+	1462  82870P2 P64H2 Hot Plug Controller
 	1960  80960RP [i960RP Microprocessor]
-		101e 0438  MegaRaid 438
-		101e 0466  MegaRaid 466
-		101e 0467  MegaRaid 467
+		101e 0431  MegaRAID 431 RAID Controller
+		101e 0438  MegaRAID 438 Ultra2 LVD RAID Controller
+		101e 0466  MegaRAID 466 Express Plus RAID Controller
+		101e 0467  MegaRAID 467 Enterprise 1500 RAID Controller
+		101e 0490  MegaRAID 490 Express 300 RAID Controller
+		101e 0762  MegaRAID 762 Express RAID Controller
 		101e 09a0  PowerEdge Expandable RAID Controller 2/SC
 		1028 0467  PowerEdge Expandable RAID Controller 2/DC
 		1028 1111  PowerEdge Expandable RAID Controller 2/SC
-		103c 03a2  MegaRaid
-		103c 10c6  MegaRaid 438
-		103c 10c7  MegaRaid T5
-		103c 10cc  MegaRaid
-		1111 1111  MegaRaid 466
-		113c 03a2  MegaRaid
+		103c 03a2  MegaRAID
+		103c 10c6  MegaRAID 438, HP NetRAID-3Si
+		103c 10c7  MegaRAID T5, Integrated HP NetRAID
+		103c 10cc  MegaRAID, Integrated HP NetRAID
+		103c 10cd  HP NetRAID-1Si
+		105a 0000  SuperTrak
+		105a 2168  SuperTrak Pro
+		105a 5168  SuperTrak66/100
+		1111 1111  MegaRAID 466, PowerEdge Expandable RAID Controller 2/SC
+		1111 1112  PowerEdge Expandable RAID Controller 2/SC
+		113c 03a2  MegaRAID
+	1962  80960RM [i960RM Microprocessor]
+		105a 0000  SuperTrak SX6000 I2O CPU
 	1a21  82840 840 (Carmel) Chipset Host Bridge (Hub A)
 	1a23  82840 840 (Carmel) Chipset AGP Bridge
 	1a24  82840 840 (Carmel) Chipset PCI Bridge (Hub B)
@@ -5054,32 +5790,54 @@
 		11d4 0048  SoundMAX Integrated Digital Audio
 	2426  82801AB AC'97 Modem
 	2428  82801AB PCI Bridge
-	2440  82820 820 (Camino 2) Chipset ISA Bridge (ICH2)
-	2442  82820 820 (Camino 2) Chipset USB (Hub A)
-	2443  82820 820 (Camino 2) Chipset SMBus
-	2444  82820 820 (Camino 2) Chipset USB (Hub B)
-	2445  82820 820 (Camino 2) Chipset AC'97 Audio Controller
-	2446  82820 820 (Camino 2) Chipset AC'97 Modem Controller
-	2448  82820 820 (Camino 2) Chipset PCI (-M)
-	2449  82820 (ICH2) Chipset Ethernet Controller
-	244a  82820 820 (Camino 2) Chipset IDE U100 (-M)
-	244b  82820 820 (Camino 2) Chipset IDE U100
-	244c  82820 820 (Camino 2) Chipset ISA Bridge (ICH2-M)
-	244e  82820 820 (Camino 2) Chipset PCI
-	2485  AC'97 Audio Controller
+	2440  82801BA ISA Bridge (LPC)
+	2442  82801BA/BAM USB (Hub #1)
+	2443  82801BA/BAM SMBus
+	2444  82801BA/BAM USB (Hub #2)
+	2445  82801BA/BAM AC'97 Audio
+	2446  82801BA/BAM AC'97 Modem
+	2448  82801BAM/CAM PCI Bridge
+	2449  82801BA/BAM/CA/CAM Ethernet Controller
+	244a  82801BAM IDE U100
+	244b  82801BA IDE U100
+	244c  82801BAM ISA Bridge (LPC)
+	244e  82801BA/CA PCI Bridge
+	2480  82801CA ISA Bridge (LPC)
+	2482  82801CA/CAM USB (Hub #1)
+	2483  82801CA/CAM SMBus
+	2484  82801CA/CAM USB (Hub #2)
+	2485  82801CA/CAM AC'97 Audio
+	2486  82801CA/CAM AC'97 Modem
+	2487  82801CA/CAM USB (Hub #3)
+	248a  82801CAM IDE U100
+	248b  82801CA IDE U100
+	248c  82801CAM ISA Bridge (LPC)
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
 	250b  82820 820 (Camino) Chipset Host Bridge
-	250f  82820 820 (Camino) Chipset PCI to AGP Bridge
+	250f  82820 820 (Camino) Chipset AGP Bridge
 	2520  82805AA MTH Memory Translator Hub
 	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
 	2530  82850 850 (Tehama) Chipset Host Bridge (MCH)
 	2531  82850 860 (Wombat) Chipset Host Bridge (MCH)
 	2532  82850 850 (Tehama) Chipset AGP Bridge
 	2533  82860 860 (Wombat) Chipset AGP Bridge
+	2534  82860 860 (Wombat) Chipset PCI Bridge
+	2540  e7500 DRAM Controller
+	2541  e7500 DRAM Controller Error Reporting
+	2543  e7500 HI_B Virtual PCI-to-PCI Bridge (F0)
+	2544  e7500 HI_B Virtual PCI-to-PCI Bridge (F1)
+	2545  e7500 HI_C Virtual PCI-to-PCI Bridge (F0)
+	2546  e7500 HI_C Virtual PCI-to-PCI Bridge (F1)
+	2547  e7500 HI_D Virtual PCI-to-PCI Bridge (F0)
+	2548  e7500 HI_D Virtual PCI-to-PCI Bridge (F1)
 	3092  Integrated RAID
+	3575  82830 830 Chipset Host Bridge
+	3576  82830 830 Chipset AGP Bridge
+	3577  82830 CGC [Chipset Graphics Controller]
+	3578  82830 830 Chipset Host Bridge
 	5200  EtherExpress PRO/100 Intelligent Server
 	5201  EtherExpress PRO/100 Intelligent Server
 		8086 0001  EtherExpress PRO/100 Server Ethernet Adapter
@@ -5089,30 +5847,34 @@
 	7020  82371SB PIIX3 USB [Natoma/Triton II]
 	7030  430VX - 82437VX TVX [Triton VX]
 	7100  430TX - 82439TX MTXC
-	7110  82371AB PIIX4 ISA
-	7111  82371AB PIIX4 IDE
-	7112  82371AB PIIX4 USB
-	7113  82371AB PIIX4 ACPI
+	7110  82371AB/EB/MB PIIX4 ISA
+	7111  82371AB/EB/MB PIIX4 IDE
+	7112  82371AB/EB/MB PIIX4 USB
+	7113  82371AB/EB/MB PIIX4 ACPI
 	7120  82810 GMCH [Graphics Memory Controller Hub]
 	7121  82810 CGC [Chipset Graphics Controller]
-	7122  82810-DC100 GMCH [Graphics Memory Controller Hub]
-	7123  82810-DC100 CGC [Chipset Graphics Controller]
-	7124  82810E GMCH [Graphics Memory Controller Hub]
-	7125  82810E CGC [Chipset Graphics Controller]
-	7126  82810 810 Chipset Host Bridge and Memory Controller Hub
+	7122  82810 DC-100 GMCH [Graphics Memory Controller Hub]
+	7123  82810 DC-100 CGC [Chipset Graphics Controller]
+	7124  82810E DC-133 GMCH [Graphics Memory Controller Hub]
+	7125  82810E DC-133 CGC [Chipset Graphics Controller]
+	7126  82810 DC-133 System and Graphics Controller
+	7128  82810-M DC-100 System and Graphics Controller
+	712a  82810-M DC-133 System and Graphics Controller
 	7180  440LX/EX - 82443LX/EX Host bridge
 	7181  440LX/EX - 82443LX/EX AGP bridge
-	7190  440BX/ZX - 82443BX/ZX Host bridge
+	7190  440BX/ZX/DX - 82443BX/ZX/DX Host bridge
 		0e11 0500  Armada 1750 Laptop System Chipset
-	7191  440BX/ZX - 82443BX/ZX AGP bridge
-	7192  440BX/ZX - 82443BX/ZX Host bridge (AGP disabled)
+		1179 0001  Toshiba Tecra 8100 Laptop System Chipset
+	7191  440BX/ZX/DX - 82443BX/ZX/DX AGP bridge
+	7192  440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled)
 		0e11 0460  Armada 1700 Laptop System Chipset
-	7194  82440MX I/O Controller
+	7194  82440MX Host Bridge
 	7195  82440MX AC'97 Audio Controller
 		10cf 1099  QSound_SigmaTel Stac97 PCI Audio
 		11d4 0040  SoundMAX Integrated Digital Audio
 		11d4 0048  SoundMAX Integrated Digital Audio
-	7198  82440MX PCI to ISA Bridge
+	7196  82440MX AC'97 Modem Controller
+	7198  82440MX ISA Bridge
 	7199  82440MX EIDE Controller
 	719a  82440MX USB Universal Host Controller
 	719b  82440MX Power Management Controller
@@ -5124,7 +5886,12 @@
 	7602  82372FB [PCI-to-USB UHCI]
 	7603  82372FB System Management Bus Controller
 	7800  i740
+		003d 0008  Starfighter AGP
+		003d 000b  Starfighter AGP
 		1092 0100  Stealth II G460
+		10b4 201a  Lightspeed 740
+		10b4 202f  Lightspeed 740
+		8086 0000  Terminator 2x/i
 		8086 0100  Intel740 Graphics Accelerator
 	84c4  450KX/GX [Orion] - 82454KX/GX PCI bridge
 	84c5  450KX/GX [Orion] - 82453KX/GX Memory controller
@@ -5135,6 +5902,7 @@
 	84e2  460GX - 84460GX AGP Bridge (GXB)
 	84e3  460GX - 84460GX Memory Address Controller (MAC)
 	84e4  460GX - 84460GX Memory Data Controller (MDC)
+	84e6  460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB)
 	9621  Integrated RAID
 	9622  Integrated RAID
 	9641  Integrated RAID
@@ -5162,12 +5930,12 @@
 	5278  AIC-7852
 	5375  AIC-755x
 	5378  AIC-7850
-	5475  AIC-2930
+	5475  AIC-755x
 	5478  AIC-7850
 	5575  AVA-2930
 	5578  AIC-7855
 	5675  AIC-755x
-	5678  AIC-7850
+	5678  AIC-7856
 	5775  AIC-755x
 	5778  AIC-7850
 	5800  AIC-5800
@@ -5175,37 +5943,38 @@
 	5905  ANA-5910A/5930A/5940A ATM Adapter
 	6038  AIC-3860
 	6075  AIC-1480 / APA-1480
+		9004 7560  AIC-1480 / APA-1480 Cardbus
 	6078  AIC-7860
 	6178  AIC-7861
 		9004 7861  AHA-2940AU Single
 	6278  AIC-7860
 	6378  AIC-7860
-	6478  AIC-786
+	6478  AIC-786x
 	6578  AIC-786x
-	6678  AIC-786
+	6678  AIC-786x
 	6778  AIC-786x
 	6915  ANA620xx/ANA69011A
 		9004 0008  ANA69011A/TX 10/100
 		9004 0009  ANA69011A/TX 10/100
 		9004 0010  ANA62022 2-port 10/100
 		9004 0018  ANA62044 4-port 10/100
+		9004 0019  ANA62044 4-port 10/100
 		9004 0020  ANA62022 2-port 10/100
 		9004 0028  ANA69011A/TX 10/100
 		9004 8008  ANA69011A/TX 64 bit 10/100
 		9004 8009  ANA69011A/TX 64 bit 10/100
 		9004 8010  ANA62022 2-port 64 bit 10/100
 		9004 8018  ANA62044 4-port 64 bit 10/100
+		9004 8019  ANA62044 4-port 64 bit 10/100
 		9004 8020  ANA62022 2-port 64 bit 10/100
 		9004 8028  ANA69011A/TX 64 bit 10/100
 	7078  AHA-294x / AIC-7870
-	7178  AHA-294x / AIC-7871
-	7278  AHA-3940 / AIC-7872
+	7178  AHA-2940/2940W / AIC-7871
+	7278  AHA-3940/3940W / AIC-7872
 	7378  AHA-3985 / AIC-7873
-	7478  AHA-2944 / AIC-7874
-# DJ: Where did the 3rd number come from?
-	7578  AHA-3944 / AHA-3944W / 7875
-# DJ: Where did the 3rd number come from?
-	7678  AHA-4944W/UW / 7876
+	7478  AHA-2944/2944W / AIC-7874
+	7578  AHA-3944/3944W / AIC-7875
+	7678  AHA-4944W/UW / AIC-7876
 	7778  AIC-787x
 	7810  AIC-7810
 	7815  AIC-7815 RAID+Memory Controller IC
@@ -5226,49 +5995,69 @@
 	7893  AIC-789x
 	7894  AIC-789x
 	7895  AHA-2940U/UW / AHA-39xx / AIC-7895
+		9004 7890  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7891  AHA-2940U/2940UW Dual
+		9004 7892  AHA-3940AU/AUW/AUWD/UWD
+		9004 7894  AHA-3944AUWD
 		9004 7895  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7896  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7897  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
 	7896  AIC-789x
 	7897  AIC-789x
 	8078  AIC-7880U
 		9004 7880  AIC-7880P Ultra/Ultra Wide SCSI Chipset
-	8178  AIC-7881U
+	8178  AHA-2940U/UW/D / AIC-7881U
 		9004 7881  AHA-2940UW SCSI Host Adapter
-	8278  AHA-3940U/UW / AIC-7882U
+	8278  AHA-3940U/UW/UWD / AIC-7882U
 	8378  AHA-3940U/UW / AIC-7883U
-	8478  AHA-294x / AIC-7884U
-	8578  AHA-3944U / AHA-3944UWD / 7885
-	8678  AHA-4944UW / 7886
-	8778  AIC-788x
+	8478  AHA-2944UW / AIC-7884U
+	8578  AHA-3944U/UWD / AIC-7885
+	8678  AHA-4944UW / AIC-7886
+	8778  AHA-2940UW Pro / AIC-788x
 		9004 7887  2940UW Pro Ultra-Wide SCSI Controller
-	8878  7888
+	8878  AHA-2930UW / AIC-7888
+		9004 7888  AHA-2930UW SCSI Controller
 	8b78  ABA-1030
 	ec78  AHA-4944W/UW
 9005  Adaptec
-	0010  AHA-2940U2/W
-	0011  2930U2
+	0010  AHA-2940U2/U2W
+		9005 2180  AHA-2940U2 SCSI Controller
+		9005 8100  AHA-2940U2B SCSI Controller
+		9005 a180  AHA-2940U2W SCSI Controller
+		9005 e100  AHA-2950U2B SCSI Controller
+	0011  AHA-2930U2
 	0013  78902
 		9005 0003  AAA-131U2 Array1000 1 Channel RAID Controller
-	001f  AHA-2940U2/W / 7890
+	001f  AHA-2940U2/U2W / 7890/7891
 		9005 000f  2940U2W SCSI Controller
 		9005 a180  2940U2W SCSI Controller
 	0020  AIC-7890
 	002f  AIC-7890
 	0030  AIC-7890
 	003f  AIC-7890
-	0050  3940U2
-	0051  3950U2D
+	0050  AHA-3940U2x/395U2x
+		9005 f500  AHA-3950U2B
+	0051  AHA-3950U2D
+		9005 b500  AHA-3950U2D
 	0053  AIC-7896 SCSI Controller
 		9005 ffff  AIC-7896 SCSI Controller mainboard implementation
-	005f  7896
-	0080  7892A
-	0081  7892B
-	0083  7892D
-	008f  7892P
-	00c0  7899A
-	00c1  7899B
-	00c3  7899D
+	005f  AIC-7896U2/7897U2
+	0080  AIC-7892A U160/m
+		0e11 e2a0  Compaq 64-Bit/66MHz Wide Ultra3 SCSI Adapter
+		9005 62a0  29160N Ultra160 SCSI Controller
+		9005 e220  29160LP Low Profile Ultra160 SCSI Controller
+		9005 e2a0  29160 Ultra160 SCSI Controller
+	0081  AIC-7892B U160/m
+		9005 62a1  19160 Ultra160 SCSI Controller
+	0083  AIC-7892D U160/m
+	008f  AIC-7892P U160/m
+	00c0  AHA-3960D / AIC-7899A U160/m
+		0e11 f620  Compaq 64-Bit/66MHz Dual Channel Wide Ultra3 SCSI Adapter
+		9005 f620  AHA-3960D U160/m
+	00c1  AIC-7899B U160/m
+	00c3  AIC-7899D U160/m
 	00c5  RAID subsystem HBA
-	00cf  7899P
+	00cf  AIC-7899P U160/m
 907f  Atronics
 	2015  IDE-2015PL
 919a  Gigapixel Corp
@@ -5276,6 +6065,9 @@
 	6565  6565
 9699  Omni Media Technology Inc
 	6565  6565
+9710  NetMos Technology
+	9815  VScom 021H-EP2 2 port parallel adaptor
+	9835  2xserial 1xparallel port adapter
 a0a0  AOPEN Inc.
 a0f1  UNISYS Corporation
 a200  NEC Corporation
@@ -5295,7 +6087,9 @@
 cccc  Catapult Communications
 d4d4  Dy4 Systems Inc
 	0601  PCI Mezzanine Card
+d531  I+ME ACTIA GmbH
 d84d  Exsys
+dead  Indigita Corporation
 e000  Winbond
 	e000  W89C940
 e159  Tiger Jet Network Inc.
@@ -5305,6 +6099,7 @@
 e4bf  EKF Elektronik GmbH
 ea01  Eagle Technology
 eabb  Aashima Technology B.V.
+eace  Endace Measurement Systems, Ltd
 ecc0  Echo Corporation
 edd8  ARK Logic Inc
 	a091  1000PV [Stingray]
@@ -5312,6 +6107,7 @@
 	a0a1  2000MT
 	a0a9  2000MI
 fa57  Fast Search & Transfer ASA
+febd  Ultraview Corp.
 feda  Epigram Inc
 fffe  VMWare Inc
 	0710  Virtual SVGA
diff -urN linux-2.4.19-pre4/drivers/pcmcia/Config.in linux-2.4.19-pre5/drivers/pcmcia/Config.in
--- linux-2.4.19-pre4/drivers/pcmcia/Config.in	Fri Nov  9 14:03:11 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/Config.in	Fri Mar 29 14:49:43 2002
@@ -24,5 +24,6 @@
       dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
    fi
 fi
+dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
 
 endmenu
diff -urN linux-2.4.19-pre4/drivers/pcmcia/Makefile linux-2.4.19-pre5/drivers/pcmcia/Makefile
--- linux-2.4.19-pre4/drivers/pcmcia/Makefile	Mon Nov 12 09:39:01 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/Makefile	Fri Mar 29 14:49:43 2002
@@ -62,22 +62,24 @@
 obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
 
 sa1100_cs-objs-y				:= sa1100_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
-sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o
-sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_CERF)		+= sa1100_cerf.o
+sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
+sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
+sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT)	+= sa1100_graphicsclient.o
-sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o
+sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN)	+= sa1100_pangolin.o
-sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
-sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
-sa1100_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o
-sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o
-sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
+sa1100_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
 sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
-sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o
-sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o
 sa1100_cs-objs-$(CONFIG_SA1100_STORK)		+= sa1100_stork.o
+sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/ricoh.h linux-2.4.19-pre5/drivers/pcmcia/ricoh.h
--- linux-2.4.19-pre4/drivers/pcmcia/ricoh.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/ricoh.h	Fri Mar 29 14:49:43 2002
@@ -110,6 +110,8 @@
 #define  RL5C4XX_CMD_SHIFT		4
 #define  RL5C4XX_HOLD_MASK		0x1c00
 #define  RL5C4XX_HOLD_SHIFT		10
+#define  RL5C4XX_MISC_CONTROL           0x2F /* 8 bit */
+#define  RL5C4XX_ZV_ENABLE              0x08
 
 #ifdef __YENTA_H
 
@@ -134,14 +136,45 @@
 	return 0;
 }
 
+static void ricoh_zoom_video(pci_socket_t *socket, int onoff)
+{
+        u8 reg;
+
+        reg = exca_readb(socket, RL5C4XX_MISC_CONTROL);
+        if (onoff)
+                /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */
+                reg |=  RL5C4XX_ZV_ENABLE;
+        else
+                reg &= ~RL5C4XX_ZV_ENABLE;
+	
+        exca_writeb(socket, RL5C4XX_MISC_CONTROL, reg);
+}
+
+static void ricoh_set_zv(pci_socket_t *socket)
+{
+        if(socket->dev->vendor == PCI_VENDOR_ID_RICOH)
+        {
+                switch(socket->dev->device)
+                {
+                        /* There may be more .. */
+		case  PCI_DEVICE_ID_RICOH_RL5C478:
+			socket->zoom_video = ricoh_zoom_video;
+			break;  
+                }
+        }
+}
+
+
 static int ricoh_init(pci_socket_t *socket)
 {
 	yenta_init(socket);
+	ricoh_set_zv(socket);
 
 	config_writew(socket, RL5C4XX_MISC, rl_misc(socket));
 	config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
 	config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
 	config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
+
 	return 0;
 }
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100.h linux-2.4.19-pre5/drivers/pcmcia/sa1100.h
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100.h	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100.h	Fri Mar 29 14:49:43 2002
@@ -38,9 +38,7 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
-
-#include <asm/arch/pcmcia.h>
-
+#include "sa1100_generic.h"
 
 /* MECR: Expansion Memory Configuration Register
  * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
@@ -157,15 +155,24 @@
  * use when responding to a Card Services query of some kind.
  */
 struct sa1100_pcmcia_socket {
+  /*
+   * Core PCMCIA state
+   */
   socket_state_t        cs_state;
-  struct pcmcia_state   k_state;
-  unsigned int          irq;
-  void                  (*handler)(void *, unsigned int);
-  void                  *handler_info;
   pccard_io_map         io_map[MAX_IO_WIN];
   pccard_mem_map        mem_map[MAX_WIN];
-  ioaddr_t              virt_io, phys_attr, phys_mem;
+  void                  (*handler)(void *, unsigned int);
+  void                  *handler_info;
+
+  struct pcmcia_state   k_state;
+  ioaddr_t              phys_attr, phys_mem;
+  void			*virt_io;
   unsigned short        speed_io, speed_attr, speed_mem;
+
+  /*
+   * Info from low level handler
+   */
+  unsigned int          irq;
 };
 
 
@@ -189,6 +196,7 @@
 extern struct pcmcia_low_level gcplus_pcmcia_ops;
 extern struct pcmcia_low_level xp860_pcmcia_ops;
 extern struct pcmcia_low_level yopy_pcmcia_ops;
+extern struct pcmcia_low_level shannon_pcmcia_ops;
 extern struct pcmcia_low_level pangolin_pcmcia_ops;
 extern struct pcmcia_low_level freebird_pcmcia_ops;
 extern struct pcmcia_low_level pfs168_pcmcia_ops;
@@ -198,5 +206,6 @@
 extern struct pcmcia_low_level graphicsmaster_pcmcia_ops;
 extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
 extern struct pcmcia_low_level stork_pcmcia_ops;
+extern struct pcmcia_low_level badge4_pcmcia_ops;
 
 #endif  /* !defined(_PCMCIA_SA1100_H) */
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_adsbitsy.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_adsbitsy.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_adsbitsy.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_adsbitsy.c	Fri Mar 29 14:49:43 2002
@@ -12,205 +12,83 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
 static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
 {
-  int return_val=0;
-
   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
   /* Disable Power 3.3V/5V for PCMCIA/CF */
   PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-  INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-			 (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    		 (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    		 (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) BVD1", NULL);
-
+  /* Why? */			 
   MECR = 0x09430943;
 
-  return (return_val<0) ? -1 : 2;
-}
-
-static int adsbitsy_pcmcia_shutdown(void)
-{
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-			   (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      		   (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      		   (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array)
-{
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+static int
+adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+  unsigned int pa_dwr_mask, pa_dwr_set;
+  int ret;
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
 
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio |= GPIO_GPIO0 | GPIO_GPIO1;
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio &= ~GPIO_GPIO0;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio |= GPIO_GPIO0;
-      break;
-
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
+    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio |= GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio |= GPIO_GPIO3;
-      break;
+    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;				break;
+    case 33:	pa_dwr_set = GPIO_GPIO2;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO3;		break;
     }
 
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
-    }
-
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
-    break;
-
   default:
     return -1;
   }
 
-  PCCR = pccr;
-  PA_DWR = gpio;
+  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+		__FUNCTION__, conf->vpp);
+    return -1;
+  }
 
-  return 0;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    local_irq_restore(flags);
+  }
+
+  return ret;
 }
 
 struct pcmcia_low_level adsbitsy_pcmcia_ops = {
-  adsbitsy_pcmcia_init,
-  adsbitsy_pcmcia_shutdown,
-  adsbitsy_pcmcia_socket_state,
-  adsbitsy_pcmcia_get_irq_info,
-  adsbitsy_pcmcia_configure_socket
+  init:			adsbitsy_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	adsbitsy_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_assabet.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_assabet.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_assabet.c	Thu Oct 25 13:53:48 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_assabet.c	Fri Mar 29 14:49:43 2002
@@ -9,141 +9,194 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
 #include <asm/arch/assabet.h>
 
-static int assabet_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
+#include "sa1100_generic.h"
 
-  /* Enable CF bus: */
-  ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
-
-  /* All those are inputs */
-  GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ);
-
-  /* Set transition detect */
-  set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE );
-
-  /* Register interrupts */
-  irq = ASSABET_IRQ_GPIO_CF_CD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = ASSABET_IRQ_GPIO_CF_BVD2;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = ASSABET_IRQ_GPIO_CF_BVD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
-  if( res < 0 ) goto irq_err;
-
-  /* There's only one slot, but it's "Slot 1": */
-  return 2;
-
-irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq );
-  return -1;
-}
+static struct irqs {
+	int irq;
+	unsigned int gpio;
+	const char *str;
+} irqs[] = {
+	{ ASSABET_IRQ_GPIO_CF_CD,   ASSABET_GPIO_CF_CD,   "CF_CD"   },
+	{ ASSABET_IRQ_GPIO_CF_BVD2, ASSABET_GPIO_CF_BVD2, "CF_BVD2" },
+	{ ASSABET_IRQ_GPIO_CF_BVD1, ASSABET_GPIO_CF_BVD1, "CF_BVD1" },
+};
 
-static int assabet_pcmcia_shutdown(void)
+static int assabet_pcmcia_init(struct pcmcia_init *init)
 {
-  /* disable IRQs */
-  free_irq( ASSABET_IRQ_GPIO_CF_CD, NULL );
-  free_irq( ASSABET_IRQ_GPIO_CF_BVD2, NULL );
-  free_irq( ASSABET_IRQ_GPIO_CF_BVD1, NULL );
-  
-  /* Disable CF bus: */
-  ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF);
+	int i, res;
 
-  return 0;
-}
+	/* Set transition detect */
+	set_GPIO_IRQ_edge(ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE);
 
-static int assabet_pcmcia_socket_state(struct pcmcia_state_array
-				       *state_array){
-  unsigned long levels;
+	/* Register interrupts */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			goto irq_err;
+	}
+
+	/* There's only one slot, but it's "Slot 1": */
+	return 2;
+
+ irq_err:
+	printk(KERN_ERR "%s: request for IRQ%d failed\n",
+		__FUNCTION__, irqs[i].irq);
 
-  if(state_array->size<2) return -1;
+	while (i--)
+		free_irq(irqs[i].irq, NULL);
 
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  levels=GPLR;
-
-  state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0;
+	return -1;
+}
 
-  state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0;
+/*
+ * Release all resources.
+ */
+static int assabet_pcmcia_shutdown(void)
+{
+	int i;
 
-  state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0;
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
+  
+	return 0;
+}
 
-  state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0;
+static int
+assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+	unsigned long levels;
 
-  state_array->state[1].wrprot=0; /* Not available on Assabet. */
+	if (state_array->size < 2)
+		return -1;
 
-  state_array->state[1].vs_3v=1;  /* Can only apply 3.3V on Assabet. */
+	levels = GPLR;
 
-  state_array->state[1].vs_Xv=0;
+	state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
+	state_array->state[1].ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
+	state_array->state[1].bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
+	state_array->state[1].bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
+	state_array->state[1].wrprot = 0; /* Not available on Assabet. */
+	state_array->state[1].vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
+	state_array->state[1].vs_Xv  = 0;
 
-  return 1;
+	return 1;
 }
 
-static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  if(info->sock>1) return -1;
+static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	if (info->sock > 1)
+		return -1;
 
-  if(info->sock==1)
-    info->irq=ASSABET_IRQ_GPIO_CF_IRQ;
+	if (info->sock == 1)
+		info->irq = ASSABET_IRQ_GPIO_CF_IRQ;
 
-  return 0;
+	return 0;
 }
 
-static int assabet_pcmcia_configure_socket(const struct pcmcia_configure
-					   *configure)
+static int
+assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure)
 {
-  unsigned long value, flags;
-
-  if(configure->sock>1) return -1;
-
-  if(configure->sock==0) return 0;
+	unsigned int mask;
 
-  save_flags_cli(flags);
+	if (configure->sock > 1)
+		return -1;
 
-  value = BCR_value;
+	if (configure->sock == 0)
+		return 0;
 
-  switch(configure->vcc){
-  case 0:
-    value &= ~ASSABET_BCR_CF_PWR;
-    break;
+	switch (configure->vcc) {
+	case 0:
+		mask = 0;
+		break;
+
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+			__FUNCTION__);
+
+	case 33:  /* Can only apply 3.3V to the CF slot. */
+		mask = ASSABET_BCR_CF_PWR;
+		break;
+
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+			configure->vcc);
+		return -1;
+	}
+
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	if (configure->reset)
+		mask |= ASSABET_BCR_CF_RST;
+
+	ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
+
+	/*
+	 * Handle suspend mode properly.  This prevents a
+	 * flood of IRQs from the CF device.
+	 */
+	if (configure->irq)
+		enable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
+	else
+		disable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
 
-  case 50:
-    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
-	   __FUNCTION__);
-
-  case 33:  /* Can only apply 3.3V to the CF slot. */
-    value |= ASSABET_BCR_CF_PWR;
-    break;
+	return 0;
+}
 
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    restore_flags(flags);
-    return -1;
-  }
+/*
+ * Enable card status IRQs on (re-)initialisation.  This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+static int assabet_pcmcia_socket_init(int sock)
+{
+	int i;
 
-  value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST);
+	if (sock == 1) {
+		/*
+		 * Enable CF bus
+		 */
+		ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
+
+		for (i = 0; i < ARRAY_SIZE(irqs); i++)
+			set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
+	}
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	return 0;
+}
 
-  ASSABET_BCR = BCR_value = value;
+/*
+ * Disable card status IRQs on suspend.
+ */
+static int assabet_pcmcia_socket_suspend(int sock)
+{
+	int i;
 
-  restore_flags(flags);
+	if (sock == 1) {
+		for (i = 0; i < ARRAY_SIZE(irqs); i++)
+			set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+
+		/*
+		 * Tristate the CF bus signals.  Also assert CF
+		 * reset as per user guide page 4-11.
+		 */
+		ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST);
+	}
 
-  return 0;
+	return 0;
 }
 
 struct pcmcia_low_level assabet_pcmcia_ops = { 
-  assabet_pcmcia_init,
-  assabet_pcmcia_shutdown,
-  assabet_pcmcia_socket_state,
-  assabet_pcmcia_get_irq_info,
-  assabet_pcmcia_configure_socket
+	init:			assabet_pcmcia_init,
+	shutdown:		assabet_pcmcia_shutdown,
+	socket_state:		assabet_pcmcia_socket_state,
+	get_irq_info:		assabet_pcmcia_get_irq_info,
+	configure_socket:	assabet_pcmcia_configure_socket,
+
+	socket_init:		assabet_pcmcia_socket_init,
+	socket_suspend:		assabet_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_badge4.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_badge4.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_badge4.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_badge4.c	Fri Mar 29 14:49:43 2002
@@ -0,0 +1,172 @@
+/*
+ * linux/drivers/pcmcia/sa1100_badge4.c
+ *
+ * BadgePAD 4 PCMCIA specific routines
+ *
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
+
+/*
+ * BadgePAD 4 Details
+ *
+ * PCM Vcc:
+ *
+ *  PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3
+ *  on JP6) or 5V (short pins 3 and 5 on JP6).  N.B., 5V supply rail
+ *  is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24).
+ *
+ * PCM Vpp:
+ *
+ *  PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4
+ *  on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6).  N.B., 12V
+ *  operation requires that the power supply actually supply 12V.
+ *
+ * CF Vcc:
+ *
+ *  CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1
+ *  and 2 on JP10) or 5V (short pins 2 and 3 on JP10).  The note above
+ *  about the 5V supply rail applies.
+ *
+ * There's no way programmatically to determine how a given board is
+ * jumpered.  This code assumes a default jumpering: 5V PCM Vcc (pins
+ * 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and
+ * no jumpering for CF Vcc.  If this isn't correct, Override these
+ * defaults with a pcmv setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf
+ * vcc>.  E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp,
+ * and 5.0V CF Vcc.
+ *
+ */
+
+static int badge4_pcmvcc = 50;
+static int badge4_pcmvpp = 50;
+static int badge4_cfvcc = 0;
+
+static int badge4_pcmcia_init(struct pcmcia_init *init)
+{
+	printk(KERN_INFO __FUNCTION__
+	       ": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
+	       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
+
+	return sa1111_pcmcia_init(init);
+}
+
+static int badge4_pcmcia_shutdown(void)
+{
+	int rc = sa1111_pcmcia_shutdown();
+
+	/* be sure to disable 5V use */
+	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0);
+	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0);
+
+	return rc;
+}
+
+static void complain_about_jumpering(const char *whom,
+				     const char *supply,
+				     int given, int wanted)
+{
+	printk(KERN_ERR
+	 "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
+	 "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
+	       whom, supply,
+	       wanted / 10, wanted % 10,
+	       supply,
+	       given / 10, given % 10);
+}
+
+static unsigned badge4_need_5V_bitmap = 0;
+
+static int
+badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	int ret;
+
+	switch (conf->sock) {
+	case 0:
+		if ((conf->vcc != 0) &&
+		    (conf->vcc != badge4_pcmvcc)) {
+			complain_about_jumpering(__FUNCTION__, "pcmvcc",
+						 badge4_pcmvcc, conf->vcc);
+			return -1;
+		}
+		if ((conf->vpp != 0) &&
+		    (conf->vpp != badge4_pcmvpp)) {
+			complain_about_jumpering(__FUNCTION__, "pcmvpp",
+						 badge4_pcmvpp, conf->vpp);
+			return -1;
+		}
+		break;
+
+	case 1:
+		if ((conf->vcc != 0) &&
+		    (conf->vcc != badge4_cfvcc)) {
+			complain_about_jumpering(__FUNCTION__, "cfvcc",
+						 badge4_cfvcc, conf->vcc);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(conf);
+	if (ret == 0) {
+		unsigned long flags;
+		int need5V;
+
+		local_irq_save(flags);
+
+		need5V = ((conf->vcc == 50) || (conf->vpp == 50));
+
+		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V);
+
+		local_irq_restore(flags);
+	}
+
+	return 0;
+}
+
+struct pcmcia_low_level badge4_pcmcia_ops = {
+	init:			badge4_pcmcia_init,
+	shutdown:		badge4_pcmcia_shutdown,
+	socket_state:		sa1111_pcmcia_socket_state,
+	get_irq_info:		sa1111_pcmcia_get_irq_info,
+	configure_socket:	badge4_pcmcia_configure_socket,
+
+	socket_init:		sa1111_pcmcia_socket_init,
+	socket_suspend:		sa1111_pcmcia_socket_suspend,
+};
+
+
+static int __init pcmv_setup(char *s)
+{
+	int v[4];
+
+	s = get_options(s, ARRAY_SIZE(v), v);
+
+	if (v[0] >= 1) badge4_pcmvcc = v[1];
+	if (v[0] >= 2) badge4_pcmvpp = v[2];
+	if (v[0] >= 3) badge4_cfvcc = v[3];
+
+	return 1;
+}
+
+__setup("pcmv=", pcmv_setup);
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_cerf.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_cerf.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_cerf.c	Thu Oct 25 13:53:48 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_cerf.c	Fri Mar 29 14:49:43 2002
@@ -10,40 +10,55 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+#ifdef CONFIG_SA1100_CERF_CPLD
+#define CERF_SOCKET	0
+#else
+#define CERF_SOCKET	1
+#endif
 
-static int cerf_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
+static struct irqs {
+	int irq;
+	unsigned int gpio;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_CF_CD,   GPIO_CF_CD,   "CF_CD"   },
+	{ IRQ_GPIO_CF_BVD2, GPIO_CF_BVD2, "CF_BVD2" },
+	{ IRQ_GPIO_CF_BVD1, GPIO_CF_BVD1, "CF_BVD1" }
+};
 
-  GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
-  GPDR |= (GPIO_CF_RESET);
+static int cerf_pcmcia_init(struct pcmcia_init *init)
+{
+  int i, res;
 
-  set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
   set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
 
-  irq = IRQ_GPIO_CF_CD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_CF_BVD2;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_CF_BVD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
-  if( res < 0 ) goto irq_err;
+  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+    set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+    res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+		      irqs[i].str, NULL);
+    if (res)
+      goto irq_err;
+  }
 
   return 2;
 
-irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
+ irq_err:
+  printk(KERN_ERR "%s: Request for IRQ%d failed\n", __FUNCTION__, irqs[i].irq);
+
+  while (i--)
+    free_irq(irqs[i].irq, NULL);
+
   return -1;
 }
 
 static int cerf_pcmcia_shutdown(void)
 {
-  free_irq( IRQ_GPIO_CF_CD, NULL );
-  free_irq( IRQ_GPIO_CF_BVD2, NULL );
-  free_irq( IRQ_GPIO_CF_BVD1, NULL );
+  int i;
+
+  for (i = 0; i < ARRAY_SIZE(irqs); i++)
+    free_irq(irqs[i].irq, NULL);
 
   return 0;
 }
@@ -51,31 +66,18 @@
 static int cerf_pcmcia_socket_state(struct pcmcia_state_array
 				       *state_array){
   unsigned long levels;
-#ifdef CONFIG_SA1100_CERF_CPLD
-  int i = 0;
-#else
-  int i = 1;
-#endif
+  int i = CERF_SOCKET;
 
   if(state_array->size<2) return -1;
 
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
   levels=GPLR;
 
   state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0;
-
   state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0;
-
   state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0;
-
   state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
-
   state_array->state[i].wrprot=0;
-
   state_array->state[i].vs_3v=1;
-
   state_array->state[i].vs_Xv=0;
 
   return 1;
@@ -85,11 +87,7 @@
 
   if(info->sock>1) return -1;
 
-#ifdef CONFIG_SA1100_CERF_CPLD
-  if(info->sock==0)
-#else
-  if(info->sock==1)
-#endif
+  if (info->sock == CERF_SOCKET)
     info->irq=IRQ_GPIO_CF_IRQ;
 
   return 0;
@@ -98,20 +96,12 @@
 static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
 					   *configure)
 {
-  unsigned long flags;
-
   if(configure->sock>1)
     return -1;
 
-#ifdef CONFIG_SA1100_CERF_CPLD
-  if(configure->sock==1)
-#else
-  if(configure->sock==0)
-#endif
+  if (configure->sock != CERF_SOCKET)
     return 0;
 
-  save_flags_cli(flags);
-
   switch(configure->vcc){
   case 0:
     break;
@@ -119,43 +109,62 @@
   case 50:
   case 33:
 #ifdef CONFIG_SA1100_CERF_CPLD
-     GPDR |= GPIO_PWR_SHUTDOWN;
-     GPCR |= GPIO_PWR_SHUTDOWN;
+     GPCR = GPIO_PWR_SHUTDOWN;
 #endif
      break;
 
   default:
     printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 	   configure->vcc);
-    restore_flags(flags);
     return -1;
   }
 
   if(configure->reset)
   {
 #ifdef CONFIG_SA1100_CERF_CPLD
-    GPDR |= GPIO_CF_RESET;
-    GPSR |= GPIO_CF_RESET;
+    GPSR = GPIO_CF_RESET;
 #endif
   }
   else
   {
 #ifdef CONFIG_SA1100_CERF_CPLD
-    GPDR |= GPIO_CF_RESET;
-    GPCR |= GPIO_CF_RESET;
+    GPCR = GPIO_CF_RESET;
 #endif
   }
 
-  restore_flags(flags);
+  return 0;
+}
+
+static int cerf_pcmcia_socket_init(int sock)
+{
+  int i;
+
+  if (sock == CERF_SOCKET)
+    for (i = 0; i < ARRAY_SIZE(irqs); i++)
+      set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
+
+  return 0;
+}
+
+static int cerf_pcmcia_socket_suspend(int sock)
+{
+  int i;
+
+  if (sock == CERF_SOCKET)
+    for (i = 0; i < ARRAY_SIZE(irqs); i++)
+      set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
 
   return 0;
 }
 
 struct pcmcia_low_level cerf_pcmcia_ops = { 
-  cerf_pcmcia_init,
-  cerf_pcmcia_shutdown,
-  cerf_pcmcia_socket_state,
-  cerf_pcmcia_get_irq_info,
-  cerf_pcmcia_configure_socket
+  init:			cerf_pcmcia_init,
+  shutdown:		cerf_pcmcia_shutdown,
+  socket_state:		cerf_pcmcia_socket_state,
+  get_irq_info:		cerf_pcmcia_get_irq_info,
+  configure_socket:	cerf_pcmcia_configure_socket,
+
+  socket_init:		cerf_pcmcia_socket_init,
+  socket_suspend:	cerf_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_flexanet.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_flexanet.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_flexanet.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_flexanet.c	Fri Mar 29 14:49:43 2002
@@ -4,7 +4,6 @@
  * PCMCIA implementation routines for Flexanet.
  * by Jordi Colomer, 09/05/2001
  *
- * Yet to be defined.
  */
 
 #include <linux/kernel.h>
@@ -12,8 +11,18 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+static struct {
+  int irq;
+  unsigned int gpio;
+  const char *name;
+} irqs[] = {
+  { IRQ_GPIO_CF1_CD,   GPIO_CF1_NCD,  "CF1_CD"   },
+  { IRQ_GPIO_CF1_BVD1, GPIO_CF1_BVD1, "CF1_BVD1" },
+  { IRQ_GPIO_CF2_CD,   GPIO_CF2_NCD,  "CF2_CD"   },
+  { IRQ_GPIO_CF2_BVD1, GPIO_CF2_BVD1, "CF2_BVD1" }
+};
 
 /*
  * Socket initialization.
@@ -22,9 +31,36 @@
  * Must return the number of slots.
  *
  */
-static int flexanet_pcmcia_init(struct pcmcia_init *init){
+static int flexanet_pcmcia_init(struct pcmcia_init *init)
+{
+  int i, res;
 
-  return 0;
+  /* Configure the GPIOs as inputs (BVD2 is not implemented) */
+  GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ |
+            GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ );
+
+  /* Set IRQ edge */
+  set_GPIO_IRQ_edge( GPIO_CF1_IRQ | GPIO_CF2_IRQ, GPIO_FALLING_EDGE );
+
+  /* Register the socket interrupts (not the card interrupts) */
+  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+    set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+    res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+		      irqs[i].name, NULL);
+    if (res < 0)
+      break;
+  }
+
+  /* If we failed, then free all interrupts requested thus far. */
+  if (res < 0) {
+    printk(KERN_ERR "%s: Request for IRQ%u failed: %d\n", __FUNCTION__,
+           irqs[i].irq, res);
+    while (i--)
+      free_irq(irqs[i].irq, NULL);
+    return -1;
+  }
+
+  return 2;
 }
 
 
@@ -34,6 +70,12 @@
  */
 static int flexanet_pcmcia_shutdown(void)
 {
+  int i;
+
+  /* disable IRQs */
+  for (i = 0; i < ARRAY_SIZE(irqs); i++)
+    free_irq(irqs[i].irq, NULL);
+
   return 0;
 }
 
@@ -46,7 +88,33 @@
  */
 static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
 				       *state_array){
-  return -1;
+  unsigned long levels;
+
+  if (state_array->size < 2)
+    return -1;
+
+  /* Sense the GPIOs, asynchronously */
+  levels = GPLR;
+
+  /* Socket 0 */
+  state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
+  state_array->state[0].ready  = (levels & GPIO_CF1_IRQ)?1:0;
+  state_array->state[0].bvd1   = (levels & GPIO_CF1_BVD1)?1:0;
+  state_array->state[0].bvd2   = 1;
+  state_array->state[0].wrprot = 0;
+  state_array->state[0].vs_3v  = 1;
+  state_array->state[0].vs_Xv  = 0;
+
+  /* Socket 1 */
+  state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
+  state_array->state[1].ready  = (levels & GPIO_CF2_IRQ)?1:0;
+  state_array->state[1].bvd1   = (levels & GPIO_CF2_BVD1)?1:0;
+  state_array->state[1].bvd2   = 1;
+  state_array->state[1].wrprot = 0;
+  state_array->state[1].vs_3v  = 1;
+  state_array->state[1].vs_Xv  = 0;
+
+  return 1;
 }
 
 
@@ -56,7 +124,16 @@
  */
 static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
 
-  return -1;
+  /* check the socket index */
+  if (info->sock > 1)
+    return -1;
+
+  if (info->sock == 0)
+    info->irq = IRQ_GPIO_CF1_IRQ;
+  else if (info->sock == 1)
+    info->irq = IRQ_GPIO_CF2_IRQ;
+
+  return 0;
 }
 
 
@@ -66,19 +143,84 @@
 static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure
 					   *configure)
 {
-  return -1;
+  unsigned long value, flags, mask;
+
+
+  if (configure->sock > 1)
+    return -1;
+
+  /* Ignore the VCC level since it is 3.3V and always on */
+  switch (configure->vcc)
+  {
+    case 0:
+      printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__);
+      break;
+
+    case 50:
+      printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+  	   __FUNCTION__);
+
+    case 33:
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+  	   configure->vcc);
+      return -1;
+  }
+
+  /* Reset the slot(s) using the controls in the BCR */
+  mask = 0;
+
+  switch (configure->sock)
+  {
+    case 0 : mask = FHH_BCR_CF1_RST; break;
+    case 1 : mask = FHH_BCR_CF2_RST; break;
+  }
+
+  save_flags_cli(flags);
+
+  value = flexanet_BCR;
+  value = (configure->reset) ? (value | mask) : (value & ~mask);
+  FHH_BCR = flexanet_BCR = value;
+
+  restore_flags(flags);
+
+  return 0;
 }
 
+static int flexanet_pcmcia_socket_init(int sock)
+{
+  if (sock == 0)
+    set_GPIO_IRQ_edge(GPIO_CF1_NCD | GPIO_CF1_BVD1, GPIO_BOTH_EDGES);
+  else if (sock == 1)
+    set_GPIO_IRQ_edge(GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_BOTH_EDGES);
+
+  return 0;
+}
+
+static int flexanet_pcmcia_socket_suspend(int sock)
+{
+  if (sock == 0)
+    set_GPIO_IRQ_edge(GPIO_CF1_NCD | GPIO_CF1_BVD1, GPIO_NO_EDGES);
+  else if (sock == 1)
+    set_GPIO_IRQ_edge(GPIO_CF2_NCD | GPIO_CF2_BVD1, GPIO_NO_EDGES);
+
+  return 0;
+}
 
 /*
  * The set of socket operations
  *
  */
 struct pcmcia_low_level flexanet_pcmcia_ops = {
-  flexanet_pcmcia_init,
-  flexanet_pcmcia_shutdown,
-  flexanet_pcmcia_socket_state,
-  flexanet_pcmcia_get_irq_info,
-  flexanet_pcmcia_configure_socket
+  init:			flexanet_pcmcia_init,
+  shutdown:		flexanet_pcmcia_shutdown,
+  socket_state:		flexanet_pcmcia_socket_state,
+  get_irq_info:		flexanet_pcmcia_get_irq_info,
+  configure_socket:	flexanet_pcmcia_configure_socket,
+
+  socket_init:		flexanet_pcmcia_socket_init,
+  socket_suspend:	flexanet_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_freebird.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_freebird.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_freebird.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_freebird.c	Fri Mar 29 14:49:43 2002
@@ -9,7 +9,7 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 
 static int freebird_pcmcia_init(struct pcmcia_init *init){
@@ -26,14 +26,10 @@
   mdelay(100);
   LINKUP_PRC = 0xc0;
 
-  /* All those are inputs */
-  ////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
-  GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD);
-
   /* Set transition detect */
   //set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
   //set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
-  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES);
+  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_NO_EDGES);
   set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE);
 
   /* Register interrupts */
@@ -150,11 +146,26 @@
   return 0;
 }
 
+static int freebird_pcmcia_socket_init(int sock)
+{
+  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD, GPIO_BOTH_EDGES);
+  return 0;
+}
+
+static int freebird_pcmcia_socket_suspend(int sock)
+{
+  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD, GPIO_NO_EDGES);
+  return 0;
+}
+
 struct pcmcia_low_level freebird_pcmcia_ops = {
-  freebird_pcmcia_init,
-  freebird_pcmcia_shutdown,
-  freebird_pcmcia_socket_state,
-  freebird_pcmcia_get_irq_info,
-  freebird_pcmcia_configure_socket
+  init:			freebird_pcmcia_init,
+  shutdown:		freebird_pcmcia_shutdown,
+  socket_state:		freebird_pcmcia_socket_state,
+  get_irq_info:		freebird_pcmcia_get_irq_info,
+  configure_socket:	freebird_pcmcia_configure_socket,
+
+  socket_init:		freebird_pcmcia_socket_init,
+  socket_suspend:	freebird_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_generic.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_generic.c	Thu Oct 25 13:53:48 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.c	Fri Mar 29 14:49:43 2002
@@ -29,6 +29,10 @@
     file under either the MPL or the GPL.
     
 ======================================================================*/
+/*
+ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
+ * on the low-level kernel interface.
+ */
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -43,6 +47,7 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
+#include <linux/cpufreq.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -62,338 +67,94 @@
 static int pc_debug;
 #endif
 
-MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
-
 /* This structure maintains housekeeping state for each socket, such
  * as the last known values of the card detect pins, or the Card Services
  * callback value associated with the socket:
  */
-static struct sa1100_pcmcia_socket 
-sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
-
 static int sa1100_pcmcia_socket_count;
+static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
 
+#define PCMCIA_SOCKET(x)	(sa1100_pcmcia_socket + (x))
 
 /* Returned by the low-level PCMCIA interface: */
 static struct pcmcia_low_level *pcmcia_low_level;
 
-/* Event poll timer structure */
 static struct timer_list poll_timer;
-
-
-/* Prototypes for routines which are used internally: */
-
-static int  sa1100_pcmcia_driver_init(void);
-static void sa1100_pcmcia_driver_shutdown(void);
-static void sa1100_pcmcia_task_handler(void *data);
-static void sa1100_pcmcia_poll_event(unsigned long data);
-static void sa1100_pcmcia_interrupt(int irq, void *dev,
-				    struct pt_regs *regs);
 static struct tq_struct sa1100_pcmcia_task;
 
-#ifdef CONFIG_PROC_FS
-static int  sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
-				      int count, int *eof, void *data);
-#endif
-
-
-/* Prototypes for operations which are exported to the
- * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
- */
-
-static int sa1100_pcmcia_init(unsigned int sock);
-static int sa1100_pcmcia_suspend(unsigned int sock);
-static int sa1100_pcmcia_register_callback(unsigned int sock,
-					   void (*handler)(void *, 
-							   unsigned int),
-					   void *info);
-static int sa1100_pcmcia_inquire_socket(unsigned int sock, 
-					socket_cap_t *cap);
-static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value);
-static int sa1100_pcmcia_get_socket(unsigned int sock, 
-				    socket_state_t *state);
-static int sa1100_pcmcia_set_socket(unsigned int sock,
-				    socket_state_t *state);
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
-				    struct pccard_io_map *io);
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
-				    struct pccard_io_map *io);
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
-				     struct pccard_mem_map *mem);
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
-				     struct pccard_mem_map *mem);
-#ifdef CONFIG_PROC_FS
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
-				     struct proc_dir_entry *base);
-#endif
-
-static struct pccard_operations sa1100_pcmcia_operations = {
-  sa1100_pcmcia_init,
-  sa1100_pcmcia_suspend,
-  sa1100_pcmcia_register_callback,
-  sa1100_pcmcia_inquire_socket,
-  sa1100_pcmcia_get_status,
-  sa1100_pcmcia_get_socket,
-  sa1100_pcmcia_set_socket,
-  sa1100_pcmcia_get_io_map,
-  sa1100_pcmcia_set_io_map,
-  sa1100_pcmcia_get_mem_map,
-  sa1100_pcmcia_set_mem_map,
-#ifdef CONFIG_PROC_FS
-  sa1100_pcmcia_proc_setup
-#endif
-};
-
-#ifdef CONFIG_CPU_FREQ
-/* forward declaration */
-static struct notifier_block sa1100_pcmcia_notifier_block;
-#endif
-
-
-/* sa1100_pcmcia_driver_init()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
- * This routine performs a basic sanity check to ensure that this
- * kernel has been built with the appropriate board-specific low-level
- * PCMCIA support, performs low-level PCMCIA initialization, registers
- * this socket driver with Card Services, and then spawns the daemon
- * thread which is the real workhorse of the socket driver.
+/*
+ * sa1100_pcmcia_state_to_config
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *
- * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
- * on the low-level kernel interface.
- *
- * Returns: 0 on success, -1 on error
- */
-static int __init sa1100_pcmcia_driver_init(void){
-  servinfo_t info;
-  struct pcmcia_init pcmcia_init;
-  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
-  struct pcmcia_state_array state_array;
-  unsigned int i, clock;
-  unsigned long mecr;
-
-  printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
-
-  CardServices(GetCardServicesInfo, &info);
-
-  if(info.Revision!=CS_RELEASE_CODE){
-    printk(KERN_ERR "Card Services release codes do not match\n");
-    return -1;
-  }
-
-  if(machine_is_assabet()){
-#ifdef CONFIG_SA1100_ASSABET
-    if(machine_has_neponset()){
-#ifdef CONFIG_ASSABET_NEPONSET
-      pcmcia_low_level=&neponset_pcmcia_ops;
-#else
-      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
-      return -1;
-#endif
-    }else{
-      pcmcia_low_level=&assabet_pcmcia_ops;
-    }
-#endif
-  } else if (machine_is_freebird()) {
-#ifdef CONFIG_SA1100_FREEBIRD
-    pcmcia_low_level = &freebird_pcmcia_ops;
-#endif
-  } else if (machine_is_h3600()) {
-#ifdef CONFIG_SA1100_H3600
-    pcmcia_low_level = &h3600_pcmcia_ops;
-#endif    
-  } else if (machine_is_cerf()) {
-#ifdef CONFIG_SA1100_CERF
-    pcmcia_low_level = &cerf_pcmcia_ops;
-#endif
-  } else if (machine_is_graphicsclient()) {
-#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-    pcmcia_low_level = &gcplus_pcmcia_ops;
-#endif
-  } else if (machine_is_xp860()) {
-#ifdef CONFIG_SA1100_XP860
-    pcmcia_low_level = &xp860_pcmcia_ops;
-#endif
-  } else if (machine_is_yopy()) {
-#ifdef CONFIG_SA1100_YOPY
-    pcmcia_low_level = &yopy_pcmcia_ops;
-#endif
-  } else if (machine_is_pangolin()) {
-#ifdef CONFIG_SA1100_PANGOLIN
-    pcmcia_low_level = &pangolin_pcmcia_ops;
-#endif
-  } else if (machine_is_jornada720()) {
-#ifdef CONFIG_SA1100_JORNADA720
-    pcmcia_low_level = &jornada720_pcmcia_ops;
-#endif
-  } else if(machine_is_pfs168()){
-#ifdef CONFIG_SA1100_PFS168
-    pcmcia_low_level=&pfs168_pcmcia_ops;
-#endif
-  } else if(machine_is_flexanet()){
-#ifdef CONFIG_SA1100_FLEXANET
-    pcmcia_low_level=&flexanet_pcmcia_ops;
-#endif
- } else if(machine_is_simpad()){
-#ifdef CONFIG_SA1100_SIMPAD
-    pcmcia_low_level=&simpad_pcmcia_ops;
-#endif
-  } else if(machine_is_graphicsmaster()) {
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-    pcmcia_low_level=&graphicsmaster_pcmcia_ops;
-#endif
-  } else if(machine_is_adsbitsy()) {
-#ifdef CONFIG_SA1100_ADSBITSY
-    pcmcia_low_level=&adsbitsy_pcmcia_ops;
-#endif
-  } else if(machine_is_stork()) {
-#ifdef CONFIG_SA1100_STORK
-    pcmcia_low_level=&stork_pcmcia_ops;
-#endif
-  }
-
-  if (!pcmcia_low_level) {
-    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
-    return -ENODEV;
-  }
-
-  pcmcia_init.handler=sa1100_pcmcia_interrupt;
-
-  if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
-    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
-    return -EIO;
-  }
-
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
-
-  if(pcmcia_low_level->socket_state(&state_array)<0){
-    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
-    return -EIO;
-  }
-
-  /* We initialize the MECR to default values here, because we are
-   * not guaranteed to see a SetIOMap operation at runtime.
-   */
-  mecr=0;
-
-  clock = get_cclk_frequency() * 100;
-
-  for(i=0; i<sa1100_pcmcia_socket_count; ++i){
-    sa1100_pcmcia_socket[i].k_state=state[i];
-
-    /* This is an interim fix. Apparently, SetSocket is no longer
-     * called to initialize each socket (prior to the first detect
-     * event). For now, we'll just manually set up the mask.
-     */
-    sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
-
-    sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
-    sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
-    sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);
-
-    MECR_FAST_SET(mecr, i, 0);
-    MECR_BSIO_SET(mecr, i,
-		  sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock));
-    MECR_BSA_SET(mecr, i,
-		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
-    MECR_BSM_SET(mecr, i,
-		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
-
-    sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS;
-    sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS;
-    sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS;
-  }
-
-  MECR=mecr;
-
-#ifdef CONFIG_CPU_FREQ
-  if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){
-    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
-    return -ENXIO;
-  }
-#endif
-
-  /* Only advertise as many sockets as we can detect: */
-  if(register_ss_entry(sa1100_pcmcia_socket_count, 
-		       &sa1100_pcmcia_operations)<0){
-    printk(KERN_ERR "Unable to register socket service routine\n");
-    return -ENXIO;
-  }
-
-  /* Start the event poll timer.  It will reschedule by itself afterwards. */
-  sa1100_pcmcia_poll_event(0);
-
-  DEBUG(1, "sa1100: initialization complete\n");
-
-  return 0;
-
-}  /* sa1100_pcmcia_driver_init() */
-
-module_init(sa1100_pcmcia_driver_init);
-
-
-/* sa1100_pcmcia_driver_shutdown()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Invokes the low-level kernel service to free IRQs associated with this
- * socket controller and reset GPIO edge detection.
+ * Convert PCMCIA socket state to our socket configure structure.
  */
-static void __exit sa1100_pcmcia_driver_shutdown(void){
+static struct pcmcia_configure
+sa1100_pcmcia_state_to_config(unsigned int sock, socket_state_t *state)
+{
+  struct pcmcia_configure conf;
 
-  del_timer_sync(&poll_timer);
-  unregister_ss_entry(&sa1100_pcmcia_operations);
-#ifdef CONFIG_CPU_FREQ
-  cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
-#endif
-  pcmcia_low_level->shutdown();
-  flush_scheduled_tasks();
+  conf.sock    = sock;
+  conf.vcc     = state->Vcc;
+  conf.vpp     = state->Vpp;
+  conf.output  = state->flags & SS_OUTPUT_ENA ? 1 : 0;
+  conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0;
+  conf.reset   = state->flags & SS_RESET ? 1 : 0;
+  conf.irq     = state->io_irq != 0;
 
-  DEBUG(1, "sa1100: shutdown complete\n");
+  return conf;
 }
 
-module_exit(sa1100_pcmcia_driver_shutdown);
-
-
 /* sa1100_pcmcia_init()
  * ^^^^^^^^^^^^^^^^^^^^
- * We perform all of the interesting initialization tasks in 
- * sa1100_pcmcia_driver_init().
+ *
+ * (Re-)Initialise the socket, turning on status interrupts
+ * and PCMCIA bus.  This must wait for power to stabilise
+ * so that the card status signals report correctly.
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_init(unsigned int sock){
-  
+static int sa1100_pcmcia_init(unsigned int sock)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  struct pcmcia_configure conf;
+
   DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
 
-  return 0;
+  skt->cs_state = dead_socket;
+
+  conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
+
+  pcmcia_low_level->configure_socket(&conf);
+
+  return pcmcia_low_level->socket_init(sock);
 }
 
 
-/* sa1100_pcmcia_suspend()
+/*
+ * sa1100_pcmcia_suspend()
  * ^^^^^^^^^^^^^^^^^^^^^^^
- * We don't currently perform any actions on a suspend.
+ *
+ * Remove power on the socket, disable IRQs from the card.
+ * Turn off status interrupts, and disable the PCMCIA bus.
  *
  * Returns: 0
  */
 static int sa1100_pcmcia_suspend(unsigned int sock)
 {
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   struct pcmcia_configure conf;
   int ret;
 
   DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
 
-  conf.sock = sock;
-  conf.vcc = 0;
-  conf.vpp = 0;
-  conf.output = 0;
-  conf.speaker = 0;
-  conf.reset = 1;
+  conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
 
   ret = pcmcia_low_level->configure_socket(&conf);
 
-  if (ret == 0)
-    sa1100_pcmcia_socket[sock].cs_state = dead_socket;
+  if (ret == 0) {
+    skt->cs_state = dead_socket;
+    ret = pcmcia_low_level->socket_suspend(sock);
+  }
 
   return ret;
 }
@@ -407,52 +168,50 @@
  *
  * Returns: an event mask for the given socket state.
  */
-static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state,
-					    struct pcmcia_state *prev_state,
-					    unsigned int mask,
-					    unsigned int flags){
-  unsigned int events=0;
-
-  if(state->detect!=prev_state->detect){
+static inline unsigned int
+sa1100_pcmcia_events(struct pcmcia_state *state,
+		     struct pcmcia_state *prev_state,
+		     unsigned int mask, unsigned int flags)
+{
+  unsigned int events = 0;
 
-    DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
+  if (state->detect != prev_state->detect) {
+    DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
 
-    events|=mask&SS_DETECT;
+    events |= SS_DETECT;
   }
 
-  if(state->ready!=prev_state->ready){
+  if (state->ready != prev_state->ready) {
+    DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
 
-    DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
-
-    events|=mask&((flags&SS_IOCARD)?0:SS_READY);
+    events |= flags & SS_IOCARD ? 0 : SS_READY;
   }
 
-  if(state->bvd1!=prev_state->bvd1){
-
-    DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
+  if (state->bvd1 != prev_state->bvd1) {
+    DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
 
-    events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
+    events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD;
   }
 
-  if(state->bvd2!=prev_state->bvd2){
+  if (state->bvd2 != prev_state->bvd2) {
+    DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
 
-    DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
-
-    events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
+    events |= flags & SS_IOCARD ? 0 : SS_BATWARN;
   }
 
-  DEBUG(2, "events: %s%s%s%s%s%s\n",
-	(events==0)?"<NONE>":"",
-	(events&SS_DETECT)?"DETECT ":"",
-	(events&SS_READY)?"READY ":"",
-	(events&SS_BATDEAD)?"BATDEAD ":"",
-	(events&SS_BATWARN)?"BATWARN ":"",
-	(events&SS_STSCHG)?"STSCHG ":"");
+  *prev_state = *state;
 
-  *prev_state=*state;
+  events &= mask;
 
-  return events;
+  DEBUG(2, "events: %s%s%s%s%s%s\n",
+	events == 0         ? "<NONE>"   : "",
+	events & SS_DETECT  ? "DETECT "  : "",
+	events & SS_READY   ? "READY "   : "",
+	events & SS_BATDEAD ? "BATDEAD " : "",
+	events & SS_BATWARN ? "BATWARN " : "",
+	events & SS_STSCHG  ? "STSCHG "  : "");
 
+  return events;
 }  /* sa1100_pcmcia_events() */
 
 
@@ -464,38 +223,43 @@
  * callback) occurs in this thread rather than in the actual interrupt
  * handler due to the use of scheduling operations in the PCMCIA core.
  */
-static void sa1100_pcmcia_task_handler(void *data) {
+static void sa1100_pcmcia_task_handler(void *data)
+{
   struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
   struct pcmcia_state_array state_array;
-  int i, events, all_events, irq_status;
+  unsigned int all_events;
 
-  DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+  DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
 
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
+  state_array.size = sa1100_pcmcia_socket_count;
+  state_array.state = state;
 
   do {
+    unsigned int events;
+    int ret, i;
 
-    DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
+    memset(state, 0, sizeof(state));
 
-    if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
-      printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
+    DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
 
-    all_events=0;
+    ret = pcmcia_low_level->socket_state(&state_array);
+    if (ret < 0) {
+      printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n");
+      break;
+    }
 
-    if(irq_status>0){
+    all_events = 0;
 
-      for(i=0; i<state_array.size; ++i, all_events|=events)
-	if((events=
-	    sa1100_pcmcia_events(&state[i],
-				 &sa1100_pcmcia_socket[i].k_state,
-				 sa1100_pcmcia_socket[i].cs_state.csc_mask,
-				 sa1100_pcmcia_socket[i].cs_state.flags)))
-	  if(sa1100_pcmcia_socket[i].handler!=NULL)
-	    sa1100_pcmcia_socket[i].handler(sa1100_pcmcia_socket[i].handler_info,
-					    events);
-    }
+    for (i = 0; i < state_array.size; i++, all_events |= events) {
+      struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
 
+      events = sa1100_pcmcia_events(&state[i], &skt->k_state,
+				    skt->cs_state.csc_mask,
+				    skt->cs_state.flags);
+
+      if (events && sa1100_pcmcia_socket[i].handler != NULL)
+	skt->handler(skt->handler_info, events);
+    }
   } while(all_events);
 }  /* sa1100_pcmcia_task_handler() */
 
@@ -510,7 +274,7 @@
  */
 static void sa1100_pcmcia_poll_event(unsigned long dummy)
 {
-  DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
+  DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
   poll_timer.function = sa1100_pcmcia_poll_event;
   poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
   add_timer(&poll_timer);
@@ -527,7 +291,8 @@
  * handling code performs scheduling operations which cannot be
  * executed from within an interrupt context.
  */
-static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){
+static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
   DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
   schedule_task(&sa1100_pcmcia_task);
 }
@@ -546,17 +311,20 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_register_callback(unsigned int sock,
-					   void (*handler)(void *,
-							   unsigned int),
-					   void *info){
-  if(handler==NULL){
-    sa1100_pcmcia_socket[sock].handler=NULL;
+static int
+sa1100_pcmcia_register_callback(unsigned int sock,
+				void (*handler)(void *, unsigned int),
+				void *info)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+  if (handler == NULL) {
+    skt->handler = NULL;
     MOD_DEC_USE_COUNT;
   } else {
     MOD_INC_USE_COUNT;
-    sa1100_pcmcia_socket[sock].handler=handler;
-    sa1100_pcmcia_socket[sock].handler_info=info;
+    skt->handler_info = info;
+    skt->handler = handler;
   }
 
   return 0;
@@ -580,51 +348,41 @@
  * an offset which is applied to client-requested base I/O addresses
  * in alloc_io_space().
  *
- * Returns: 0 on success, -1 if no pin has been configured for `sock'
+ * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
+ *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
+ *   general, the mapped * addresses of the PCMCIA memory regions
+ *   will not be within 0xffff, setting force_low would be
+ *   undesirable.
+ *
+ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
+ *   resource database; we instead pass up physical address ranges
+ *   and allow other parts of Card Services to deal with remapping.
+ *
+ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
+ *   not 32-bit CardBus devices.
+ *
+ * Return value is irrelevant; the pcmcia subsystem ignores it.
  */
-static int sa1100_pcmcia_inquire_socket(unsigned int sock,
-					socket_cap_t *cap){
-  struct pcmcia_irq_info irq_info;
-
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if(sock>=sa1100_pcmcia_socket_count){
-    printk(KERN_ERR "sa1100: socket %u not configured\n", sock);
-    return -1;
-  }
+static int
+sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
-   *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
-   *   general, the mapped * addresses of the PCMCIA memory regions
-   *   will not be within 0xffff, setting force_low would be
-   *   undesirable.
-   *
-   * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
-   *   resource database; we instead pass up physical address ranges
-   *   and allow other parts of Card Services to deal with remapping.
-   *
-   * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
-   *   not 32-bit CardBus devices.
-   */
-  cap->features=(SS_CAP_PAGE_REGS  | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  irq_info.sock=sock;
-  irq_info.irq=-1;
+  if (sock < sa1100_pcmcia_socket_count) {
+    cap->features  = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+    cap->irq_mask  = 0;
+    cap->map_size  = PAGE_SIZE;
+    cap->pci_irq   = skt->irq;
+    cap->io_offset = (unsigned long)skt->virt_io;
 
-  if(pcmcia_low_level->get_irq_info(&irq_info)<0){
-    printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
-	   sock);
-    return -1;
+    ret = 0;
   }
 
-  cap->irq_mask=0;
-  cap->map_size=PAGE_SIZE;
-  cap->pci_irq=irq_info.irq;
-  cap->io_offset=sa1100_pcmcia_socket[sock].virt_io;
-
-  return 0;
-
-}  /* sa1100_pcmcia_inquire_socket() */
+  return ret;
+}
 
 
 /* sa1100_pcmcia_get_status()
@@ -643,58 +401,61 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_get_status(unsigned int sock,
-				    unsigned int *status){
+static int
+sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
   struct pcmcia_state_array state_array;
+  unsigned int stat;
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
+  state_array.size = sa1100_pcmcia_socket_count;
+  state_array.state = state;
 
-  if((pcmcia_low_level->socket_state(&state_array))<0){
-    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+  memset(state, 0, sizeof(state));
+
+  if ((pcmcia_low_level->socket_state(&state_array)) < 0) {
+    printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n");
     return -1;
   }
 
-  sa1100_pcmcia_socket[sock].k_state=state[sock];
-
-  *status=state[sock].detect?SS_DETECT:0;
+  skt->k_state = state[sock];
 
-  *status|=state[sock].ready?SS_READY:0;
+  stat = state[sock].detect ? SS_DETECT : 0;
+  stat |= state[sock].ready ? SS_READY  : 0;
+  stat |= state[sock].vs_3v ? SS_3VCARD : 0;
+  stat |= state[sock].vs_Xv ? SS_XVCARD : 0;
 
   /* The power status of individual sockets is not available
    * explicitly from the hardware, so we just remember the state
    * and regurgitate it upon request:
    */
-  *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
+  stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
 
-  if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
-    *status|=state[sock].bvd1?SS_STSCHG:0;
+  if (skt->cs_state.flags & SS_IOCARD)
+    stat |= state[sock].bvd1 ? SS_STSCHG : 0;
   else {
-    if(state[sock].bvd1==0)
-      *status|=SS_BATDEAD;
-    else if(state[sock].bvd2==0)
-      *status|=SS_BATWARN;
+    if (state[sock].bvd1 == 0)
+      stat |= SS_BATDEAD;
+    else if (state[sock].bvd2 == 0)
+      stat |= SS_BATWARN;
   }
 
-  *status|=state[sock].vs_3v?SS_3VCARD:0;
-
-  *status|=state[sock].vs_Xv?SS_XVCARD:0;
-
   DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
-	(*status&SS_DETECT)?"DETECT ":"",
-	(*status&SS_READY)?"READY ":"", 
-	(*status&SS_BATDEAD)?"BATDEAD ":"",
-	(*status&SS_BATWARN)?"BATWARN ":"",
-	(*status&SS_POWERON)?"POWERON ":"",
-	(*status&SS_STSCHG)?"STSCHG ":"",
-	(*status&SS_3VCARD)?"3VCARD ":"",
-	(*status&SS_XVCARD)?"XVCARD ":"");
+	stat & SS_DETECT  ? "DETECT "  : "",
+	stat & SS_READY   ? "READY "   : "", 
+	stat & SS_BATDEAD ? "BATDEAD " : "",
+	stat & SS_BATWARN ? "BATWARN " : "",
+	stat & SS_POWERON ? "POWERON " : "",
+	stat & SS_STSCHG  ? "STSCHG "  : "",
+	stat & SS_3VCARD  ? "3VCARD "  : "",
+	stat & SS_XVCARD  ? "XVCARD "  : "");
 
-  return 0;
+  *status = stat;
 
+  return 0;
 }  /* sa1100_pcmcia_get_status() */
 
 
@@ -706,20 +467,18 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_get_socket(unsigned int sock,
-				    socket_state_t *state){
+static int
+sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  /* This information was given to us in an earlier call to set_socket(),
-   * so we're just regurgitating it here:
-   */
-  *state=sa1100_pcmcia_socket[sock].cs_state;
+  *state = skt->cs_state;
 
   return 0;
 }
 
-
 /* sa1100_pcmcia_set_socket()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the set_socket() operation for the in-kernel PCMCIA
@@ -730,14 +489,15 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_set_socket(unsigned int sock,
-				    socket_state_t *state){
-  struct pcmcia_configure configure;
+static int
+sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  struct pcmcia_configure conf;
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
-	"\tVcc %d  Vpp %d  irq %d\n",
+  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n",
 	(state->csc_mask==0)?"<NONE>":"",
 	(state->csc_mask&SS_DETECT)?"DETECT ":"",
 	(state->csc_mask&SS_READY)?"READY ":"",
@@ -749,25 +509,20 @@
 	(state->flags&SS_IOCARD)?"IOCARD ":"",
 	(state->flags&SS_RESET)?"RESET ":"",
 	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
+  DEBUG(3, "\tVcc %d  Vpp %d  irq %d\n",
 	state->Vcc, state->Vpp, state->io_irq);
 
-  configure.sock=sock;
-  configure.vcc=state->Vcc;
-  configure.vpp=state->Vpp;
-  configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
-  configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
-  configure.reset=(state->flags&SS_RESET)?1:0;
+  conf = sa1100_pcmcia_state_to_config(sock, state);
 
-  if(pcmcia_low_level->configure_socket(&configure)<0){
-    printk(KERN_ERR "Unable to configure socket %u\n", sock);
+  if (pcmcia_low_level->configure_socket(&conf) < 0) {
+    printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock);
     return -1;
   }
 
-  sa1100_pcmcia_socket[sock].cs_state=*state;
+  skt->cs_state = *state;
   
   return 0;
-
 }  /* sa1100_pcmcia_set_socket() */
 
 
@@ -779,20 +534,20 @@
  *
  * Returns: 0 on success, -1 if the map index was out of range
  */
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
-				    struct pccard_io_map *map){
+static int
+sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  if(map->map>=MAX_IO_WIN){
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
+  if (map->map < MAX_IO_WIN) {
+    *map = skt->io_map[map->map];
+    ret = 0;
   }
 
-  *map=sa1100_pcmcia_socket[sock].io_map[map->map];
-
-  return 0;
+  return ret;
 }
 
 
@@ -805,16 +560,16 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
-				    struct pccard_io_map *map){
-  unsigned int clock, speed;
-  unsigned long mecr, start;
+static int
+sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(4, "\tmap %u  speed %u\n\tstart 0x%08lx  stop 0x%08lx\n"
-	"\tflags: %s%s%s%s%s%s%s%s\n",
-	map->map, map->speed, map->start, map->stop,
+  DEBUG(3, "\tmap %u  speed %u\n\tstart 0x%08x  stop 0x%08x\n",
+	map->map, map->speed, map->start, map->stop);
+  DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
 	(map->flags==0)?"<NONE>":"",
 	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
 	(map->flags&MAP_16BIT)?"16BIT ":"",
@@ -824,45 +579,45 @@
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
 	(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
 
-  if(map->map>=MAX_IO_WIN){
+  if (map->map >= MAX_IO_WIN) {
     printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
 	   map->map);
     return -1;
   }
 
-  if(map->flags&MAP_ACTIVE){
+  if (map->flags & MAP_ACTIVE) {
+    unsigned int clock, speed = map->speed;
+    unsigned long mecr;
 
-    speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS;
+    if (speed == 0)
+      speed = SA1100_PCMCIA_IO_ACCESS;
 
-    clock = get_cclk_frequency() * 100;
+    clock = cpufreq_get(0);
 
-    mecr=MECR;
+    mecr = MECR;
 
     MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
 
-    sa1100_pcmcia_socket[sock].speed_io=speed;
+    skt->speed_io = speed;
 
     DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
 	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
 	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
 	  sock, MECR_BSIO_GET(mecr, sock));
 
-    MECR=mecr;
-
+    MECR = mecr;
   }
 
-  start=map->start;
+  if (map->stop == 1)
+    map->stop = PAGE_SIZE-1;
 
-  if(map->stop==1)
-    map->stop=PAGE_SIZE-1;
+  map->stop -= map->start;
+  map->stop += (unsigned long)skt->virt_io;
+  map->start = (unsigned long)skt->virt_io;
 
-  map->start=sa1100_pcmcia_socket[sock].virt_io;
-  map->stop=map->start+(map->stop-start);
-
-  sa1100_pcmcia_socket[sock].io_map[map->map]=*map;
+  skt->io_map[map->map] = *map;
 
   return 0;
-
 }  /* sa1100_pcmcia_set_io_map() */
 
 
@@ -875,20 +630,20 @@
  *
  * Returns: 0 on success, -1 if the map index was out of range
  */
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
-				     struct pccard_mem_map *map){
+static int
+sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  if(map->map>=MAX_WIN){
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
+  if (map->map < MAX_WIN) {
+    *map = skt->mem_map[map->map];
+    ret = 0;
   }
 
-  *map=sa1100_pcmcia_socket[sock].mem_map[map->map];
-
-  return 0;
+  return ret;
 }
 
 
@@ -901,18 +656,18 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
-				     struct pccard_mem_map *map){
-  unsigned int clock, speed;
-  unsigned long mecr, start;
+static int
+sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  unsigned long start;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
-	"\tsys_stop   %#lx\n\tcard_start %#x\n"
-	"\tflags: %s%s%s%s%s%s%s%s\n",
-	map->map, map->speed, map->sys_start, map->sys_stop,
-	map->card_start, (map->flags==0)?"<NONE>":"",
+  DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n",
+	map->map, map->speed, map->sys_start, map->sys_stop, map->card_start);
+  DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
+	(map->flags==0)?"<NONE>":"",
 	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
 	(map->flags&MAP_16BIT)?"16BIT ":"",
 	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
@@ -921,177 +676,175 @@
 	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
 
-  if(map->map>=MAX_WIN){
+  if (map->map >= MAX_WIN){
     printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
 	   map->map);
     return -1;
   }
 
-  if(map->flags&MAP_ACTIVE){
-
-    /* When clients issue RequestMap, the access speed is not always
-     * properly configured:
+  if (map->flags & MAP_ACTIVE) {
+    unsigned int clock, speed = map->speed;
+    unsigned long mecr;
+
+    /*
+     * When clients issue RequestMap, the access speed is not always
+     * properly configured.  Choose some sensible defaults.
      */
-    if(map->speed > 0)
-      speed = map->speed;
-    else
-      switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){
-      case 33:
+    if (speed == 0) {
+      if (skt->cs_state.Vcc == 33)
 	speed = SA1100_PCMCIA_3V_MEM_ACCESS;
-	break;
-      default:
+      else
 	speed = SA1100_PCMCIA_5V_MEM_ACCESS;
-      }
+    }
 
-    clock = get_cclk_frequency() * 100;
-    
-    mecr=MECR;
-    
-    if(map->flags&MAP_ATTRIB){
+    clock = cpufreq_get(0);
 
-      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
-      sa1100_pcmcia_socket[sock].speed_attr=speed;
+    /* Fixme: MECR is not pre-empt safe. */
+    mecr = MECR;
 
+    if (map->flags & MAP_ATTRIB) {
+      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
+      skt->speed_attr = speed;
     } else {
-
       MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
-      sa1100_pcmcia_socket[sock].speed_mem=speed;
-
+      skt->speed_mem = speed;
     }
-    
+
     DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
 	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
 	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
 	  sock, MECR_BSIO_GET(mecr, sock));
-    
-    MECR=mecr;
 
+    MECR = mecr;
   }
 
-  start=map->sys_start;
-
-  if(map->sys_stop==0)
-    map->sys_stop=PAGE_SIZE-1;
+  start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem;
 
-  map->sys_start=(map->flags & MAP_ATTRIB)?\
-    sa1100_pcmcia_socket[sock].phys_attr:\
-    sa1100_pcmcia_socket[sock].phys_mem;
+  if (map->sys_stop == 0)
+    map->sys_stop = PAGE_SIZE-1;
 
-  map->sys_stop=map->sys_start+(map->sys_stop-start);
+  map->sys_stop -= map->sys_start;
+  map->sys_stop += start;
+  map->sys_start = start;
 
-  sa1100_pcmcia_socket[sock].mem_map[map->map]=*map;
+  skt->mem_map[map->map] = *map;
 
   return 0;
-
 }  /* sa1100_pcmcia_set_mem_map() */
 
 
 #if defined(CONFIG_PROC_FS)
 
-/* sa1100_pcmcia_proc_setup()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the proc_setup() operation for the in-kernel PCMCIA
- * service (formerly SS_ProcSetup in Card Services).
- *
- * Returns: 0 on success, -1 on error
- */
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
-				     struct proc_dir_entry *base){
-  struct proc_dir_entry *entry;
-
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if((entry=create_proc_entry("status", 0, base))==NULL){
-    printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
-    return;
-  }
-
-  entry->read_proc=sa1100_pcmcia_proc_status;
-  entry->data=(void *)sock;
-}
-
-
 /* sa1100_pcmcia_proc_status()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the /proc/bus/pccard/??/status file.
  *
  * Returns: the number of characters added to the buffer
  */
-static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
-				     int count, int *eof, void *data){
-  char *p=buf;
-  unsigned int sock=(unsigned int)data;
-  unsigned int clock = get_cclk_frequency() * 100;
+static int
+sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+  unsigned int sock = (unsigned int)data;
+  unsigned int clock = cpufreq_get(0);
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   unsigned long mecr = MECR;
+  char *p = buf;
 
-  p+=sprintf(p, "k_flags  : %s%s%s%s%s%s%s\n", 
-	     sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"",
-	     sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"",
-	     sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
-	     sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
-	     sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
+  p+=sprintf(p, "k_state  : %s%s%s%s%s%s%s\n", 
+	     skt->k_state.detect ? "detect " : "",
+	     skt->k_state.ready  ? "ready "  : "",
+	     skt->k_state.bvd1   ? "bvd1 "   : "",
+	     skt->k_state.bvd2   ? "bvd2 "   : "",
+	     skt->k_state.wrprot ? "wrprot " : "",
+	     skt->k_state.vs_3v  ? "vs_3v "  : "",
+	     skt->k_state.vs_Xv  ? "vs_Xv "  : "");
 
   p+=sprintf(p, "status   : %s%s%s%s%s%s%s%s%s\n",
-	     sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
-	     sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
-	      sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
-	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
-	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
+	     skt->k_state.detect ? "SS_DETECT " : "",
+	     skt->k_state.ready  ? "SS_READY " : "",
+	     skt->cs_state.Vcc   ? "SS_POWERON " : "",
+	     skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "",
+	     (skt->cs_state.flags & SS_IOCARD &&
+	      skt->k_state.bvd1) ? "SS_STSCHG " : "",
+	     ((skt->cs_state.flags & SS_IOCARD)==0 &&
+	      (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "",
+	     ((skt->cs_state.flags & SS_IOCARD)==0 &&
+	      (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "",
+	     skt->k_state.vs_3v  ? "SS_3VCARD " : "",
+	     skt->k_state.vs_Xv  ? "SS_XVCARD " : "");
 
   p+=sprintf(p, "mask     : %s%s%s%s%s\n",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
-	     "SS_DETECT ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
-	     "SS_READY ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
-	     "SS_BATDEAD ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
-	     "SS_BATWARN ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
-	     "SS_STSCHG ":"");
+	     skt->cs_state.csc_mask & SS_DETECT  ? "SS_DETECT "  : "",
+	     skt->cs_state.csc_mask & SS_READY   ? "SS_READY "   : "",
+	     skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "",
+	     skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "",
+	     skt->cs_state.csc_mask & SS_STSCHG  ? "SS_STSCHG "  : "");
 
   p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
-	     "SS_PWR_AUTO ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
-	     "SS_RESET ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
-	     "SS_SPKR_ENA ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
-	     "SS_OUTPUT_ENA ":"");
-
-  p+=sprintf(p, "Vcc      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc);
-
-  p+=sprintf(p, "Vpp      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp);
-
-  p+=sprintf(p, "irq      : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq);
+	     skt->cs_state.flags & SS_PWR_AUTO   ? "SS_PWR_AUTO "   : "",
+	     skt->cs_state.flags & SS_IOCARD     ? "SS_IOCARD "     : "",
+	     skt->cs_state.flags & SS_RESET      ? "SS_RESET "      : "",
+	     skt->cs_state.flags & SS_SPKR_ENA   ? "SS_SPKR_ENA "   : "",
+	     skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : "");
+
+  p+=sprintf(p, "Vcc      : %d\n", skt->cs_state.Vcc);
+  p+=sprintf(p, "Vpp      : %d\n", skt->cs_state.Vpp);
+  p+=sprintf(p, "IRQ      : %d\n", skt->cs_state.io_irq);
 
-  p+=sprintf(p, "I/O      : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_io,
+  p+=sprintf(p, "I/O      : %u (%u)\n", skt->speed_io,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock)));
 
-  p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr,
+  p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock)));
 
-  p+=sprintf(p, "common   : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem,
+  p+=sprintf(p, "common   : %u (%u)\n", skt->speed_mem,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock)));
 
   return p-buf;
 }
 
+/* sa1100_pcmcia_proc_setup()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the proc_setup() operation for the in-kernel PCMCIA
+ * service (formerly SS_ProcSetup in Card Services).
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static void
+sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+  struct proc_dir_entry *entry;
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  if ((entry = create_proc_entry("status", 0, base)) == NULL){
+    printk(KERN_ERR "unable to install \"status\" procfs entry\n");
+    return;
+  }
+
+  entry->read_proc = sa1100_pcmcia_proc_status;
+  entry->data = (void *)sock;
+}
+
 #endif  /* defined(CONFIG_PROC_FS) */
 
+static struct pccard_operations sa1100_pcmcia_operations = {
+  init:			sa1100_pcmcia_init,
+  suspend:		sa1100_pcmcia_suspend,
+  register_callback:	sa1100_pcmcia_register_callback,
+  inquire_socket:	sa1100_pcmcia_inquire_socket,
+  get_status:		sa1100_pcmcia_get_status,
+  get_socket:		sa1100_pcmcia_get_socket,
+  set_socket:		sa1100_pcmcia_set_socket,
+  get_io_map:		sa1100_pcmcia_get_io_map,
+  set_io_map:		sa1100_pcmcia_set_io_map,
+  get_mem_map:		sa1100_pcmcia_get_mem_map,
+  set_mem_map:		sa1100_pcmcia_set_mem_map,
+#ifdef CONFIG_PROC_FS
+  proc_setup:		sa1100_pcmcia_proc_setup
+#endif
+};
 
 #ifdef CONFIG_CPU_FREQ
 
@@ -1101,7 +854,8 @@
  * to a core clock frequency change) is needed, this routine establishes
  * new BS_xx values consistent with the clock speed `clock'.
  */
-static void sa1100_pcmcia_update_mecr(unsigned int clock){
+static void sa1100_pcmcia_update_mecr(unsigned int clock)
+{
   unsigned int sock;
   unsigned long mecr = MECR;
 
@@ -1132,53 +886,293 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_notifier(struct notifier_block *nb,
-				  unsigned long val, void *data){
+static int
+sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
+		       void *data)
+{
   struct cpufreq_info *ci = data;
 
-  switch(val){
-  case CPUFREQ_MINMAX:
-
-    break;
-
+  switch (val) {
   case CPUFREQ_PRECHANGE:
-
-    if(ci->new_freq > ci->old_freq){
+    if (ci->new_freq > ci->old_freq) {
       DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
 	    __FUNCTION__,
 	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
 	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
       sa1100_pcmcia_update_mecr(ci->new_freq);
     }
-
     break;
 
   case CPUFREQ_POSTCHANGE:
-
-    if(ci->new_freq < ci->old_freq){
+    if (ci->new_freq < ci->old_freq) {
       DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
 	    __FUNCTION__,
 	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
 	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
       sa1100_pcmcia_update_mecr(ci->new_freq);
     }
-
     break;
-
-  default:
-    printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
-	   val);
-    return -1;
-
   }
 
   return 0;
-
 }
 
 static struct notifier_block sa1100_pcmcia_notifier_block = {
   notifier_call: sa1100_pcmcia_notifier
 };
+#endif
 
+static int __init sa1100_pcmcia_machine_init(void)
+{
+#ifdef CONFIG_SA1100_ASSABET
+  if(machine_is_assabet()) {
+    if(machine_has_neponset()) {
+#ifdef CONFIG_ASSABET_NEPONSET
+      pcmcia_low_level = &neponset_pcmcia_ops;
+#else
+      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
+      return -1;
+#endif
+    } else
+      pcmcia_low_level = &assabet_pcmcia_ops;
+  }
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+  if (machine_is_badge4())
+    pcmcia_low_level = &badge4_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+  if (machine_is_freebird())
+    pcmcia_low_level = &freebird_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_H3600
+  if (machine_is_h3600())
+    pcmcia_low_level = &h3600_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_CERF
+  if (machine_is_cerf())
+    pcmcia_low_level = &cerf_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+  if (machine_is_graphicsclient())
+    pcmcia_low_level = &gcplus_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_XP860
+  if (machine_is_xp860())
+    pcmcia_low_level = &xp860_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_YOPY
+  if (machine_is_yopy())
+    pcmcia_low_level = &yopy_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+  if (machine_is_shannon())
+    pcmcia_low_level = &shannon_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+  if (machine_is_pangolin())
+    pcmcia_low_level = &pangolin_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+  if (machine_is_jornada720())
+    pcmcia_low_level = &jornada720_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_PFS168
+  if(machine_is_pfs168())
+    pcmcia_low_level = &pfs168_pcmcia_ops;
 #endif
+#ifdef CONFIG_SA1100_FLEXANET
+  if(machine_is_flexanet())
+    pcmcia_low_level = &flexanet_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+  if(machine_is_simpad())
+    pcmcia_low_level = &simpad_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+  if(machine_is_graphicsmaster())
+    pcmcia_low_level = &graphicsmaster_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_ADSBITSY
+  if(machine_is_adsbitsy())
+    pcmcia_low_level = &adsbitsy_pcmcia_ops;
+#endif
+#ifdef CONFIG_SA1100_STORK
+  if(machine_is_stork())
+    pcmcia_low_level = &stork_pcmcia_ops;
+#endif
+
+  if (!pcmcia_low_level) {
+    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
+    return -ENODEV;
+  }
+
+  return 0;
+}
+
+/* sa1100_pcmcia_driver_init()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * This routine performs a basic sanity check to ensure that this
+ * kernel has been built with the appropriate board-specific low-level
+ * PCMCIA support, performs low-level PCMCIA initialization, registers
+ * this socket driver with Card Services, and then spawns the daemon
+ * thread which is the real workhorse of the socket driver.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int __init sa1100_pcmcia_driver_init(void)
+{
+  servinfo_t info;
+  struct pcmcia_init pcmcia_init;
+  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
+  struct pcmcia_state_array state_array;
+  unsigned int i, clock;
+  unsigned long mecr;
+  int ret;
+
+  printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
+
+  CardServices(GetCardServicesInfo, &info);
+
+  if (info.Revision != CS_RELEASE_CODE) {
+    printk(KERN_ERR "Card Services release codes do not match\n");
+    return -EINVAL;
+  }
+
+  ret = sa1100_pcmcia_machine_init();
+  if (ret)
+    return ret;
+
+  pcmcia_init.handler = sa1100_pcmcia_interrupt;
+
+  ret = pcmcia_low_level->init(&pcmcia_init);
+  if (ret < 0) {
+    printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret);
+    return ret == -1 ? -EIO : ret;
+  }
+
+  sa1100_pcmcia_socket_count = ret;
+  state_array.size  = sa1100_pcmcia_socket_count;
+  state_array.state = state;
+
+  memset(state, 0, sizeof(state));
+
+  if (pcmcia_low_level->socket_state(&state_array) < 0) {
+    pcmcia_low_level->shutdown();
+    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+    return -EIO;
+  }
+
+  /*
+   * We initialize the MECR to default values here, because we are
+   * not guaranteed to see a SetIOMap operation at runtime.
+   */
+  mecr = 0;
+
+  clock = cpufreq_get(0);
+
+  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+    struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+    struct pcmcia_irq_info irq_info;
+
+    if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) {
+      ret = -EBUSY;
+      goto out_err;
+    }
+
+    irq_info.sock = i;
+    irq_info.irq  = -1;
+    ret = pcmcia_low_level->get_irq_info(&irq_info);
+    if (ret < 0)
+      printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret);
+
+    skt->irq        = irq_info.irq;
+    skt->k_state    = state[i];
+    skt->speed_io   = SA1100_PCMCIA_IO_ACCESS;
+    skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS;
+    skt->speed_mem  = SA1100_PCMCIA_5V_MEM_ACCESS;
+    skt->phys_attr  = _PCMCIAAttr(i);
+    skt->phys_mem   = _PCMCIAMem(i);
+    skt->virt_io    = ioremap(_PCMCIAIO(i), 0x10000);
+
+    if (skt->virt_io == NULL) {
+      ret = -ENOMEM;
+      goto out_err;
+    }
 
+    MECR_FAST_SET(mecr, i, 0);
+    MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock));
+    MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock));
+    MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock));
+  }
+
+  MECR = mecr;
+
+#ifdef CONFIG_CPU_FREQ
+  ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block);
+  if (ret < 0) {
+    printk(KERN_ERR "Unable to register CPU frequency change notifier (%d)\n", ret);
+    goto out_err;
+  }
+#endif
+
+  /* Only advertise as many sockets as we can detect */
+  ret = register_ss_entry(sa1100_pcmcia_socket_count,
+			  &sa1100_pcmcia_operations);
+  if (ret < 0) {
+    printk(KERN_ERR "Unable to register sockets\n");
+    goto out_err;
+  }
+
+  /*
+   * Start the event poll timer.  It will reschedule by itself afterwards.
+   */
+  sa1100_pcmcia_poll_event(0);
+
+  return 0;
+
+ out_err:
+  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+    iounmap(sa1100_pcmcia_socket[i].virt_io);
+    release_mem_region(_PCMCIA(i), PCMCIASp);
+  }
+
+  pcmcia_low_level->shutdown();
+
+  return ret;
+}  /* sa1100_pcmcia_driver_init() */
+
+/* sa1100_pcmcia_driver_shutdown()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit sa1100_pcmcia_driver_shutdown(void)
+{
+  int i;
+
+  del_timer_sync(&poll_timer);
+
+  unregister_ss_entry(&sa1100_pcmcia_operations);
+
+#ifdef CONFIG_CPU_FREQ
+  cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
+#endif
+
+  for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+    iounmap(sa1100_pcmcia_socket[i].virt_io);
+    release_mem_region(_PCMCIA(i), PCMCIASp);
+  }
+
+  pcmcia_low_level->shutdown();
+
+  flush_scheduled_tasks();
+}
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
+MODULE_LICENSE("Dual MPL/GPL");
+
+module_init(sa1100_pcmcia_driver_init);
+module_exit(sa1100_pcmcia_driver_shutdown);
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_generic.h linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.h
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_generic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_generic.h	Fri Mar 29 14:49:43 2002
@@ -0,0 +1,76 @@
+/*
+ * linux/include/asm/arch/pcmcia.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
+ *
+ * This file contains definitions for the low-level SA-1100 kernel PCMCIA
+ * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
+ */
+#ifndef _ASM_ARCH_PCMCIA
+#define _ASM_ARCH_PCMCIA
+
+/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
+ * has support for two. This shows up in lots of hardwired ways, such
+ * as the fact that MECR only has enough bits to configure two sockets.
+ * Since it's so entrenched in the hardware, limiting the software
+ * in this way doesn't seem too terrible.
+ */
+#define SA1100_PCMCIA_MAX_SOCK   (2)
+
+struct pcmcia_init {
+  void (*handler)(int irq, void *dev, struct pt_regs *regs);
+};
+
+struct pcmcia_state {
+  unsigned detect: 1,
+            ready: 1,
+             bvd1: 1,
+             bvd2: 1,
+           wrprot: 1,
+            vs_3v: 1,
+            vs_Xv: 1;
+};
+
+struct pcmcia_state_array {
+  unsigned int size;
+  struct pcmcia_state *state;
+};
+
+struct pcmcia_configure {
+  unsigned sock: 8,
+            vcc: 8,
+            vpp: 8,
+         output: 1,
+        speaker: 1,
+          reset: 1,
+            irq: 1;
+};
+
+struct pcmcia_irq_info {
+  unsigned int sock;
+  unsigned int irq;
+};
+
+struct pcmcia_low_level {
+  int (*init)(struct pcmcia_init *);
+  int (*shutdown)(void);
+  int (*socket_state)(struct pcmcia_state_array *);
+  int (*get_irq_info)(struct pcmcia_irq_info *);
+  int (*configure_socket)(const struct pcmcia_configure *);
+
+  /*
+   * Enable card status IRQs on (re-)initialisation.  This can
+   * be called at initialisation, power management event, or
+   * pcmcia event.
+   */
+  int (*socket_init)(int sock);
+
+  /*
+   * Disable card status IRQs and PCMCIA bus on suspend.
+   */
+  int (*socket_suspend)(int sock);
+};
+
+extern struct pcmcia_low_level *pcmcia_low_level;
+
+#endif
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_graphicsclient.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsclient.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_graphicsclient.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsclient.c	Fri Mar 29 14:49:43 2002
@@ -17,7 +17,9 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
+
+#error This is broken!
 
 #define	S0_CD_IRQ		60				// Socket 0 Card Detect IRQ
 #define	S0_STS_IRQ		55				// Socket 0 PCMCIA IRQ
@@ -144,11 +146,24 @@
   return 0;
 }
 
+static int gcplus_pcmcia_socket_init(int sock)
+{
+  return 0;
+}
+
+static int gcplus_pcmcia_socket_suspend(int sock)
+{
+  return 0;
+}
+
 struct pcmcia_low_level gcplus_pcmcia_ops = { 
-  gcplus_pcmcia_init,
-  gcplus_pcmcia_shutdown,
-  gcplus_pcmcia_socket_state,
-  gcplus_pcmcia_get_irq_info,
-  gcplus_pcmcia_configure_socket
+  init:			gcplus_pcmcia_init,
+  shutdown:		gcplus_pcmcia_shutdown,
+  socket_state:		gcplus_pcmcia_socket_state,
+  get_irq_info:		gcplus_pcmcia_get_irq_info,
+  configure_socket:	gcplus_pcmcia_configure_socket,
+
+  socket_init:		gcplus_pcmcia_socket_init,
+  socket_suspend:	gcplus_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_graphicsmaster.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsmaster.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_graphicsmaster.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_graphicsmaster.c	Fri Mar 29 14:49:43 2002
@@ -11,10 +11,10 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
 static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
 {
@@ -26,190 +26,67 @@
   /* Disable Power 3.3V/5V for PCMCIA/CF */
   PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-  INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-			 (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    		 (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    		 (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) BVD1", NULL);
-
+  /* why? */
   MECR = 0x09430943;
 
-  return (return_val<0) ? -1 : 2;
-}
-
-static int graphicsmaster_pcmcia_shutdown(void)
-{
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-			   (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      		   (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      		   (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array)
-{
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+static int
+graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+  unsigned int pa_dwr_mask, pa_dwr_set;
+  int ret;
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
 
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio |= GPIO_GPIO0 | GPIO_GPIO1;
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio &= ~GPIO_GPIO0;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio |= GPIO_GPIO0;
-      break;
-
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
+    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      gpio |= GPIO_GPIO2 | GPIO_GPIO3;
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio &= ~GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio |= GPIO_GPIO2;
-      break;
+    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
+    case 0:	pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3;	break;
+    case 33:	pa_dwr_set = GPIO_GPIO3;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO2;		break;
     }
+  }
 
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
-    break;
-
-  default:
+  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	   conf->vpp);
     return -1;
   }
 
-  PCCR = pccr;
-  PA_DWR = gpio;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    local_irq_restore(flags);
+  }
 
-  return 0;
+  return ret;
 }
 
 struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
-  graphicsmaster_pcmcia_init,
-  graphicsmaster_pcmcia_shutdown,
-  graphicsmaster_pcmcia_socket_state,
-  graphicsmaster_pcmcia_get_irq_info,
-  graphicsmaster_pcmcia_configure_socket
+  init:			graphicsmaster_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	graphicsmaster_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_h3600.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_h3600.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_h3600.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_h3600.c	Fri Mar 29 14:49:43 2002
@@ -9,139 +9,188 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
+	{ IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
+};
 
-static int h3600_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
-
-  /* Enable CF bus: */
-  set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON);
-  clr_h3600_egpio(EGPIO_H3600_OPT_RESET);
-
-  /* All those are inputs */
-  GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1);
-
-  /* Set transition detect */
-  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE );
-
-  /* Register interrupts */
-  irq = IRQ_GPIO_H3600_PCMCIA_CD0;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_H3600_PCMCIA_CD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
-  if( res < 0 ) goto irq_err;
+static int h3600_pcmcia_init(struct pcmcia_init *init)
+{
+	int i, res;
 
-  return 2;
+	/*
+	 * Set transition detect
+	 */
+	set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1,
+			  GPIO_FALLING_EDGE);
+
+	/*
+	 * Register interrupts
+	 */
+	for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			break;
+	}
+
+	if (res) {
+		printk(KERN_ERR "h3600_pcmcia: request for IRQ%d failed: %d\n",
+		       irqs[i].irq, res);
+
+		while (i--)
+			free_irq(irqs[i].irq, NULL);
+	}
 
-irq_err:
-  printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
-  return -1;
+	return res ? -1 : 2;
 }
 
 static int h3600_pcmcia_shutdown(void)
 {
-  /* disable IRQs */
-  free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
-  free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL );
+	int i;
+
+	/*
+	 * disable IRQs
+	 */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
   
-  /* Disable CF bus: */
-  clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON);
-  set_h3600_egpio(EGPIO_H3600_OPT_RESET);
+	/* Disable CF bus: */
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+	set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
 
-  return 0;
+	return 0;
 }
 
-static int h3600_pcmcia_socket_state(struct pcmcia_state_array
-				       *state_array){
-  unsigned long levels;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
+static int
+h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
+{
+	unsigned long levels;
 
-  levels=GPLR;
+	if (state->size < 2)
+		return -1;
 
-  state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0;
-  state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0;
-  state_array->state[0].bvd1= 0;
-  state_array->state[0].bvd2= 0;
-  state_array->state[0].wrprot=0; /* Not available on H3600. */
-  state_array->state[0].vs_3v=0;
-  state_array->state[0].vs_Xv=0;
+	levels = GPLR;
 
-  state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0;
-  state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0;
-  state_array->state[1].bvd1=0;
-  state_array->state[1].bvd2=0;
-  state_array->state[1].wrprot=0; /* Not available on H3600. */
-  state_array->state[1].vs_3v=0;
-  state_array->state[1].vs_Xv=0;
+	state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
+	state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
+	state->state[0].bvd1 = 0;
+	state->state[0].bvd2 = 0;
+	state->state[0].wrprot = 0; /* Not available on H3600. */
+	state->state[0].vs_3v = 0;
+	state->state[0].vs_Xv = 0;
+
+	state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
+	state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
+	state->state[1].bvd1 = 0;
+	state->state[1].bvd2 = 0;
+	state->state[1].wrprot = 0; /* Not available on H3600. */
+	state->state[1].vs_3v = 0;
+	state->state[1].vs_Xv = 0;
 
-  return 1;
+	return 1;
 }
 
-static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch (info->sock) {
-  case 0:
-    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0;
-    break;
-  case 1:
-    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1;
-    break;
-  default:
-    return -1;
-  }
-  return 0;
+static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	switch (info->sock) {
+	case 0:
+		info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
+		break;
+	case 1:
+		info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
 }
 
-static int h3600_pcmcia_configure_socket(const struct pcmcia_configure
-					   *configure)
+static int
+h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long flags;
-
-  if(configure->sock>1) return -1;
+	if (conf->sock > 1)
+		return -1;
 
-  save_flags_cli(flags);
+	if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
+		printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
+		       conf->vcc / 10, conf->vcc % 10);
+		return -1;
+	}
+
+	if (conf->reset)
+		set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
+	else
+		clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
 
-  switch (configure->vcc) {
-  case 0:
-    clr_h3600_egpio(EGPIO_H3600_OPT_ON);
-    break;
+	/* Silently ignore Vpp, output enable, speaker enable. */
 
-  case 33:
-  case 50:
-    set_h3600_egpio(EGPIO_H3600_OPT_ON);
-    break;
-
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    restore_flags(flags);
-    return -1;
-  }
+	return 0;
+}
 
-  if (configure->reset)
-    set_h3600_egpio(EGPIO_H3600_CARD_RESET);
-  else
-    clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
+static int h3600_pcmcia_socket_init(int sock)
+{
+	/* Enable CF bus: */
+	set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+	set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(10*HZ / 1000);
+
+	switch (sock) {
+	case 0:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_BOTH_EDGES);
+		break;
+	case 1:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES);
+		break;
+	}
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	return 0;
+}
 
-  restore_flags(flags);
+static int h3600_pcmcia_socket_suspend(int sock)
+{
+	switch (sock) {
+	case 0:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_NO_EDGES);
+		break;
+	case 1:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_NO_EDGES);
+		break;
+	}
+
+	/*
+	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
+	 * the generic PCMCIA layer to deal with the idea of two sockets
+	 * on one bus.  We rely on the cs.c behaviour shutting down
+	 * socket 0 then socket 1.
+	 */
+	if (sock == 1) {
+		clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+		clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+		/* hmm, does this suck power? */
+		set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
+	}
 
-  return 0;
+	return 0;
 }
 
 struct pcmcia_low_level h3600_pcmcia_ops = { 
-  h3600_pcmcia_init,
-  h3600_pcmcia_shutdown,
-  h3600_pcmcia_socket_state,
-  h3600_pcmcia_get_irq_info,
-  h3600_pcmcia_configure_socket
+	init:			h3600_pcmcia_init,
+	shutdown:		h3600_pcmcia_shutdown,
+	socket_state:		h3600_pcmcia_socket_state,
+	get_irq_info:		h3600_pcmcia_get_irq_info,
+	configure_socket:	h3600_pcmcia_configure_socket,
+
+	socket_init:		h3600_pcmcia_socket_init,
+	socket_suspend:		h3600_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_jornada720.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_jornada720.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_jornada720.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_jornada720.c	Fri Mar 29 14:49:43 2002
@@ -7,20 +7,22 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
 #define SOCKET0_POWER   GPIO_GPIO0
 #define SOCKET0_3V      GPIO_GPIO2
 #define SOCKET1_POWER   (GPIO_GPIO1 | GPIO_GPIO3)
-#define SOCKET1_3V   GPIO_GPIO3
+#warning *** Does SOCKET1_3V actually do anything?
+#define SOCKET1_3V	GPIO_GPIO3
 
 static int jornada720_pcmcia_init(struct pcmcia_init *init)
 {
-  int return_val=0;
-
+  /*
+   * What is all this crap for?
+   */
   GRER |= 0x00000002;
   /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
   PA_DDR = 0;
@@ -38,178 +40,68 @@
   PC_SDR = 0;
   PC_SSR = 0;
 
-  INTPOL1 |=
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Jornada720 PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Jornada720 CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Jornada720 PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Jornada720 CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
+  return sa1111_pcmcia_init(init);
 }
 
-static int jornada720_pcmcia_shutdown(void)
+static int
+jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &=
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int jornada720_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array)
-{
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-  status=PCSR;
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-  return return_val;
-}
-
-static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-  return 0;
-}
-
-static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure)
-{
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+  unsigned int pa_dwr_mask, pa_dwr_set;
+  int ret;
 
 printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
-	       configure->sock, configure->vcc, configure->vpp);
-  switch(configure->sock){
+	       conf->sock, conf->vcc, conf->vpp);
+
+  switch (conf->sock) {
   case 0:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio&=~(SOCKET0_POWER | SOCKET0_3V);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio |= SOCKET0_POWER | SOCKET0_3V;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER;
-      break;
+    pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-    switch(configure->vpp){
-    case 0:
-      break;
-    case 50:
-	printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-      break;
-    case 120:
-	printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-      break;
-    default:
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-	return -1;
+    case 0:	pa_dwr_set = 0;					break;
+    case 33:	pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;	break;
+    case 50:	pa_dwr_set = SOCKET0_POWER;			break;
     }
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      gpio &= ~(SOCKET1_POWER);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio |= SOCKET1_POWER;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER;
-      break;
+    pa_dwr_mask = SOCKET1_POWER;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
+    case 0:	pa_dwr_set = 0;					break;
+    case 33:	pa_dwr_set = SOCKET1_POWER;			break;
+    case 50:	pa_dwr_set = SOCKET1_POWER;			break;
     }
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
     break;
-  default:
+  }
+
+  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
+	   __FUNCTION__, conf->vpp);
     return -1;
   }
-  PCCR = pccr;
-  PA_DWR = gpio;
-  return 0;
+
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    locla_irq_restore(flags);
+  }
+
+  return ret;
 }
 
 struct pcmcia_low_level jornada720_pcmcia_ops = {
-  jornada720_pcmcia_init,
-  jornada720_pcmcia_shutdown,
-  jornada720_pcmcia_socket_state,
-  jornada720_pcmcia_get_irq_info,
-  jornada720_pcmcia_configure_socket
+  init:			jornada720_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	jornada720_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_neponset.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_neponset.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_neponset.c	Thu Oct 25 13:53:48 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_neponset.c	Fri Mar 29 14:49:43 2002
@@ -1,249 +1,129 @@
 /*
- * drivers/pcmcia/sa1100_neponset.c
+ * linux/drivers/pcmcia/sa1100_neponset.c
  *
  * Neponset PCMCIA specific routines
- *
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
 #include <asm/arch/assabet.h>
+#include <asm/hardware/sa1111.h>
 
-static int neponset_pcmcia_init(struct pcmcia_init *init){
-  int return_val=0;
-
-  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
-  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-  
-  /* MAX1600 to standby mode: */
-  PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-  NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
-
-  INTPOL1 |= 
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Neponset PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Neponset CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Neponset PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Neponset CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
-}
-
-static int neponset_pcmcia_shutdown(void){
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= 
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int neponset_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array){
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
+static int neponset_pcmcia_init(struct pcmcia_init *init)
+{
+	/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+	PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
+	/* MAX1600 to standby mode: */
+	PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+	NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
 
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
+	return sa1111_pcmcia_init(init);
 }
 
-static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
+static int
+neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	unsigned int ncr_mask, pa_dwr_mask;
+	unsigned int ncr_set, pa_dwr_set;
+	int ret;
+
+	/* Neponset uses the Maxim MAX1600, with the following connections:
+
+	 *   MAX1600      Neponset
+	 *
+	 *    A0VCC        SA-1111 GPIO A<1>
+	 *    A1VCC        SA-1111 GPIO A<0>
+	 *    A0VPP        CPLD NCR A0VPP
+	 *    A1VPP        CPLD NCR A1VPP
+	 *    B0VCC        SA-1111 GPIO A<2>
+	 *    B1VCC        SA-1111 GPIO A<3>
+	 *    B0VPP        ground (slot B is CF)
+	 *    B1VPP        ground (slot B is CF)
+	 *
+	 *     VX          VCC (5V)
+	 *     VY          VCC3_3 (3.3V)
+	 *     12INA       12V
+	 *     12INB       ground (slot B is CF)
+	 *
+	 * The MAX1600 CODE pin is tied to ground, placing the device in 
+	 * "Standard Intel code" mode. Refer to the Maxim data sheet for
+	 * the corresponding truth table.
+	 */
+
+	switch (conf->sock) {
+	case 0:
+		pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
+		ncr_mask = NCR_A0VPP | NCR_A1VPP;
+
+		switch (conf->vcc) {
+		default:
+		case 0:		pa_dwr_set = 0;			break;
+		case 33:	pa_dwr_set = GPIO_GPIO1;	break;
+		case 50:	pa_dwr_set = GPIO_GPIO0;	break;
+		}
+
+		switch (conf->vpp) {
+		case 0:		ncr_set = 0;			break;
+		case 120:	ncr_set = NCR_A1VPP;		break;
+		default:
+			if (conf->vpp == conf->vcc)
+				ncr_set = NCR_A0VPP;
+			else {
+				printk(KERN_ERR "%s(): unrecognized VPP %u\n",
+				       __FUNCTION__, conf->vpp);
+				return -1;
+			}
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
+		ncr_mask = 0;
+		ncr_set = 0;
+
+		switch (conf->vcc) {
+		default:
+		case 0:		pa_dwr_set = 0;			break;
+		case 33:	pa_dwr_set = GPIO_GPIO2;	break;
+		case 50:	pa_dwr_set = GPIO_GPIO3;	break;
+		}
+
+		if (conf->vpp != conf->vcc && conf->vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+			       __FUNCTION__, conf->vpp);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(conf);
+	if (ret == 0) {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
+		PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+		local_irq_restore(flags);
+	}
 
-  return 0;
+	return 0;
 }
 
-static int neponset_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure){
-  unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR;
-
-  /* Neponset uses the Maxim MAX1600, with the following connections:
-   *
-   *   MAX1600      Neponset
-   *
-   *    A0VCC        SA-1111 GPIO A<1>
-   *    A1VCC        SA-1111 GPIO A<0>
-   *    A0VPP        CPLD NCR A0VPP
-   *    A1VPP        CPLD NCR A1VPP
-   *    B0VCC        SA-1111 GPIO A<2>
-   *    B1VCC        SA-1111 GPIO A<3>
-   *    B0VPP        ground (slot B is CF)
-   *    B1VPP        ground (slot B is CF)
-   *
-   *     VX          VCC (5V)
-   *     VY          VCC3_3 (3.3V)
-   *     12INA       12V
-   *     12INB       ground (slot B is CF)
-   *
-   * The MAX1600 CODE pin is tied to ground, placing the device in 
-   * "Standard Intel code" mode. Refer to the Maxim data sheet for
-   * the corresponding truth table.
-   */
-
-  switch(configure->sock){
-  case 0:
-    
-    switch(configure->vcc){
-    case 0:
-      pccr=(pccr & ~PCCR_S0_FLT);
-      gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
-      break;
-
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-
-    switch(configure->vpp){
-    case 0:
-      ncr&=~(NCR_A0VPP | NCR_A1VPP);
-      break;
-
-    case 120:
-      ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
-      break;
-
-    default:
-      if(configure->vpp == configure->vcc)
-	ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
-      else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-	return -1;
-      }
-    }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
-    break;
-
-  case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr=(pccr & ~PCCR_S1_FLT);
-      gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
-      break;
-
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
-    }
-
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
-    break;
-
-  default:
-    return -1;
-  }
-
-  PCCR = pccr;
-  NCR_0 = ncr;
-  PA_DWR = gpio;
+struct pcmcia_low_level neponset_pcmcia_ops = {
+	init:			neponset_pcmcia_init,
+	shutdown:		sa1111_pcmcia_shutdown,
+	socket_state:		sa1111_pcmcia_socket_state,
+	get_irq_info:		sa1111_pcmcia_get_irq_info,
+	configure_socket:	neponset_pcmcia_configure_socket,
 
-  return 0;
-}
-
-struct pcmcia_low_level neponset_pcmcia_ops = { 
-  neponset_pcmcia_init,
-  neponset_pcmcia_shutdown,
-  neponset_pcmcia_socket_state,
-  neponset_pcmcia_get_irq_info,
-  neponset_pcmcia_configure_socket
+	socket_init:		sa1111_pcmcia_socket_init,
+	socket_suspend:		sa1111_pcmcia_socket_suspend,
 };
-
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_pangolin.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_pangolin.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_pangolin.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_pangolin.c	Fri Mar 29 14:49:43 2002
@@ -9,22 +9,16 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 static int pangolin_pcmcia_init(struct pcmcia_init *init){
   int irq, res;
 
-  /* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */
-  GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ);
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-  /* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */
-  GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET);
   /* Enable PCMCIA bus: */
   GPCR = GPIO_PCMCIA_BUS_ON;
-#else
-  /* set GPIO pin GPIO_PCMCIA_RESET as output */
-  GPDR |= GPIO_PCMCIA_RESET;
 #endif
+
   /* Set transition detect */
   set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES );
   set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE );
@@ -147,11 +141,26 @@
   return 0;
 }
 
+static int pangolin_pcmcia_socket_init(int sock)
+{
+  /* enable card status IRQs - see sa1100_assabet.c for details  */
+  return -1;
+}
+
+static int pangolin_pcmcia_socket_suspend(int sock)
+{
+  /* disable card status IRQs - see sa1100_assabet.c for details */
+  return -1;
+}
+
 struct pcmcia_low_level pangolin_pcmcia_ops = { 
-  pangolin_pcmcia_init,
-  pangolin_pcmcia_shutdown,
-  pangolin_pcmcia_socket_state,
-  pangolin_pcmcia_get_irq_info,
-  pangolin_pcmcia_configure_socket
+  init:			pangolin_pcmcia_init,
+  shutdown:		pangolin_pcmcia_shutdown,
+  socket_state:		pangolin_pcmcia_socket_state,
+  get_irq_info:		pangolin_pcmcia_get_irq_info,
+  configure_socket:	pangolin_pcmcia_configure_socket,
+
+  socket_init:		pangolin_pcmcia_socket_init,
+  socket_suspend,	pangolin_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_pfs168.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_pfs168.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_pfs168.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_pfs168.c	Fri Mar 29 14:49:43 2002
@@ -11,117 +11,26 @@
 #include <asm/delay.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
 
-static int pfs168_pcmcia_init(struct pcmcia_init *init){
-  int return_val=0;
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
+static int pfs168_pcmcia_init(struct pcmcia_init *init)
+{
   /* TPS2211 to standby mode: */
   PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
   /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
-  INTPOL1 |=
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "PFS168 PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "PFS168 CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "PFS168 PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "PFS168 CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
-}
-
-static int pfs168_pcmcia_shutdown(void){
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &=
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int pfs168_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array){
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int pfs168_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int pfs168_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure){
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+static int
+pfs168_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+  unsigned int pa_dwr_mask = 0, pa_dwr_set = 0;
+  int ret;
 
   /* PFS168 uses the Texas Instruments TPS2211 for PCMCIA (socket 0) voltage control only,
    * with the following connections:
@@ -135,103 +44,85 @@
    *
    */
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
-      break;
-
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;			break;
+    case 33:	pa_dwr_set = GPIO_GPIO0;	break;
+    case 50:	pa_dwr_set = GPIO_GPIO1;	break;
     }
 
-    switch(configure->vpp){
+    switch (conf->vpp) {
     case 0:
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
       break;
 
     case 120:
-      printk(KERN_ERR "%s(): PFS-168 does not support Vpp %uV\n", __FUNCTION__,
-	     configure->vpp/10);
+      printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n",
+	     __FUNCTION__, conf->vpp / 10);
       return -1;
       break;
 
     default:
-      if(configure->vpp == configure->vcc)
-        gpio = (gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
+      if (conf->vpp == conf->vcc)
+        pa_dwr_set |= GPIO_GPIO3;
       else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
+	printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__,
+	       conf->vpp);
 	return -1;
       }
     }
-
-    pccr = (configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
-    PA_DWR = gpio;
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      break;
+    pa_dwr_mask = 0;
+    pa_dwr_set = 0;
 
+    switch (conf->vcc) {
+    case 0:
     case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
       break;
 
     case 50:
-      printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support Vcc %uV\n", __FUNCTION__,
-	     configure->vcc/10);
+      printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n",
+	     __FUNCTION__, conf->vcc / 10);
       return -1;
-      break;
 
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
+      printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__,
+	     conf->vcc);
       return -1;
     }
 
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CompactFlash socket does not support Vpp %uV\n", __FUNCTION__,
-	     configure->vpp/10);
+    if (conf->vpp != conf->vcc && conf->vpp != 0) {
+      printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n"
+	      __FUNCTION__, conf->vpp/10);
       return -1;
     }
-
-    pccr = (configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
     break;
-
-  default:
-    return -1;
   }
 
-  PCCR = pccr;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    local_irq_restore(flags);
+  }
 
   return 0;
 }
 
 struct pcmcia_low_level pfs168_pcmcia_ops = {
-  pfs168_pcmcia_init,
-  pfs168_pcmcia_shutdown,
-  pfs168_pcmcia_socket_state,
-  pfs168_pcmcia_get_irq_info,
-  pfs168_pcmcia_configure_socket
+  init:			pfs168_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	pfs168_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_shannon.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_shannon.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_shannon.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_shannon.c	Fri Mar 29 14:49:43 2002
@@ -0,0 +1,144 @@
+/*
+ * drivers/pcmcia/sa1100_shannon.c
+ *
+ * PCMCIA implementation routines for Shannon
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/shannon.h>
+#include <asm/irq.h>
+#include "sa1100_generic.h"
+
+static int shannon_pcmcia_init(struct pcmcia_init *init)
+{
+	int irq, res;
+
+	/* All those are inputs */
+	GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
+		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
+	GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
+		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
+
+	/* Set transition detect */
+	set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1, GPIO_NO_EDGES);
+	set_GPIO_IRQ_edge(SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1, GPIO_FALLING_EDGE);
+
+	/* Register interrupts */
+	irq = SHANNON_IRQ_GPIO_EJECT_0;
+	res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA_CD_0", NULL);
+	if (res < 0) goto irq_err;
+	irq = SHANNON_IRQ_GPIO_EJECT_1;
+	res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA_CD_1", NULL);
+	if (res < 0) goto irq_err;
+
+	return 2;
+irq_err:
+	printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__, irq);
+	return -1;
+}
+
+static int shannon_pcmcia_shutdown(void)
+{
+	/* disable IRQs */
+	free_irq(SHANNON_IRQ_GPIO_EJECT_0, NULL);
+	free_irq(SHANNON_IRQ_GPIO_EJECT_1, NULL);
+
+	return 0;
+}
+
+static int shannon_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+	unsigned long levels;
+
+	memset(state_array->state, 0,
+	       state_array->size * sizeof(struct pcmcia_state));
+
+	levels = GPLR;
+
+	state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
+	state_array->state[0].ready  = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0;
+	state_array->state[0].wrprot = 0; /* Not available on Shannon. */
+	state_array->state[0].bvd1 = 1; 
+	state_array->state[0].bvd2 = 1; 
+	state_array->state[0].vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
+	state_array->state[0].vs_Xv  = 0;
+
+	state_array->state[1].detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1;
+	state_array->state[1].ready  = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0;
+	state_array->state[1].wrprot = 0; /* Not available on Shannon. */
+	state_array->state[1].bvd1 = 1; 
+	state_array->state[1].bvd2 = 1; 
+	state_array->state[1].vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
+	state_array->state[1].vs_Xv  = 0;
+
+	return 1;
+}
+
+static int shannon_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	if (info->sock == 0)
+		info->irq = SHANNON_IRQ_GPIO_RDY_0;
+	else if (info->sock == 1)
+		info->irq = SHANNON_IRQ_GPIO_RDY_1;
+	else return -1;
+	
+	return 0;
+}
+
+static int shannon_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+
+	switch (configure->vcc) {
+	case 0:	/* power off */;
+		printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n");
+		break;
+	case 50:
+		printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n");
+	case 33:
+		break;
+	default:
+		printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
+		       configure->vcc);
+		return -1;
+	}
+
+	printk(KERN_WARNING __FUNCTION__"(): Warning, Can't perform reset\n");
+	
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	return 0;
+}
+
+static int shannon_pcmcia_socket_init(int sock)
+{
+	if (sock == 0)
+		set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_0, GPIO_BOTH_EDGES);
+	else if (sock == 1)
+		set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_1, GPIO_BOTH_EDGES);
+
+	return 0;
+}
+
+static int shannon_pcmcia_socket_suspend(int sock)
+{
+	if (sock == 0)
+		set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_0, GPIO_NO_EDGES);
+	else if (sock == 1)
+		set_GPIO_IRQ_edge(SHANNON_GPIO_EJECT_1, GPIO_NO_EDGES);
+
+	return 0;
+}
+
+struct pcmcia_low_level shannon_pcmcia_ops = {
+	init:			shannon_pcmcia_init,
+	shutdown:		shannon_pcmcia_shutdown,
+	socket_state:		shannon_pcmcia_socket_state,
+	get_irq_info:		shannon_pcmcia_get_irq_info,
+	configure_socket:	shannon_pcmcia_configure_socket,
+
+	socket_init:		shannon_pcmcia_socket_init,
+	socket_suspend:		shannon_pcmcia_socket_suspend,
+};
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_simpad.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_simpad.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_simpad.c	Thu Oct 25 13:53:48 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_simpad.c	Fri Mar 29 14:49:43 2002
@@ -9,7 +9,7 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
  
 extern long get_cs3_shadow(void);
 extern void set_cs3_bit(int value); 
@@ -19,9 +19,6 @@
 static int simpad_pcmcia_init(struct pcmcia_init *init){
   int irq, res;
 
-  /* set GPIO_CF_CD & GPIO_CF_IRQ as inputs */
-  GPDR &= ~(GPIO_CF_CD|GPIO_CF_IRQ);
-  
   set_cs3_bit(PCMCIA_RESET);
   clear_cs3_bit(PCMCIA_BUFF_DIS);
   clear_cs3_bit(PCMCIA_RESET);
@@ -29,7 +26,7 @@
   clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
 
   /* Set transition detect */
-  set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_BOTH_EDGES );
+  set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_NO_EDGES );
   set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
 
   /* Register interrupts */
@@ -146,11 +143,26 @@
   return 0;
 }
 
+static int simpad_pcmcia_socket_init(int sock)
+{
+  set_GPIO_IRQ_edge(GPIO_CF_CD, GPIO_BOTH_EDGES);
+  return 0;
+}
+
+static int simpad_pcmcia_socket_suspend(int sock)
+{
+  set_GPIO_IRQ_edge(GPIO_CF_CD, GPIO_NO_EDGES);
+  return 0;
+}
+
 struct pcmcia_low_level simpad_pcmcia_ops = { 
-  simpad_pcmcia_init,
-  simpad_pcmcia_shutdown,
-  simpad_pcmcia_socket_state,
-  simpad_pcmcia_get_irq_info,
-  simpad_pcmcia_configure_socket
+  init:			simpad_pcmcia_init,
+  shutdown:		simpad_pcmcia_shutdown,
+  socket_state:		simpad_pcmcia_socket_state,
+  get_irq_info:		simpad_pcmcia_get_irq_info,
+  configure_socket:	simpad_pcmcia_configure_socket,
+
+  socket_init:		simpad_pcmcia_socket_init,
+  socket_suspend:	simpad_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_stork.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_stork.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_stork.c	Thu Oct 25 13:53:48 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_stork.c	Fri Mar 29 14:49:43 2002
@@ -28,7 +28,7 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 static int debug = 0;
 
@@ -41,14 +41,8 @@
 
         sa1100_stork_pcmcia_init = *init;
 
-        /* Enable CF bus: */
-        storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
-
-        /* All those are inputs */
-	GPDR &= ~(GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT | GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY);
-
 	/* Set transition detect */
-	set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES );
+	set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_NO_EDGES );
         set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY, GPIO_FALLING_EDGE );
 
 	/* Register interrupts */
@@ -192,11 +186,41 @@
         return 0;
 }
 
+static int stork_pcmcia_socket_init(int sock)
+{
+        storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+
+        if (sock == 0)
+		set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_A_CARD_DETECT, GPIO_BOTH_EDGES);
+        else if (sock == 1)
+		set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES);
+
+	return 0;
+}
+
+static int stork_pcmcia_socket_suspend(int sock)
+{
+        if (sock == 0)
+		set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_A_CARD_DETECT, GPIO_NO_EDGES);
+        else if (sock == 1) {
+		set_GPIO_IRQ_edge(GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_NO_EDGES);
+
+		/*
+		 * Hack!
+		 */
+	        storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+	}
+
+	return 0;
+}
+
 struct pcmcia_low_level stork_pcmcia_ops = { 
-        stork_pcmcia_init,
-        stork_pcmcia_shutdown,
-        stork_pcmcia_socket_state,
-        stork_pcmcia_get_irq_info,
-        stork_pcmcia_configure_socket
-};
+	init:			stork_pcmcia_init,
+	shutdown:		stork_pcmcia_shutdown,
+	socket_state:		stork_pcmcia_socket_state,
+	get_irq_info:		stork_pcmcia_get_irq_info,
+	configure_socket:	stork_pcmcia_configure_socket,
 
+	socket_init:		stork_pcmcia_socket_init,
+	socket_suspend:		stork_pcmcia_socket_suspend,
+};
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_xp860.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_xp860.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_xp860.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_xp860.c	Fri Mar 29 14:49:43 2002
@@ -10,125 +10,42 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 #define NCR_A0VPP	(1<<16)
 #define NCR_A1VPP	(1<<17)
 
-static int xp860_pcmcia_init(struct pcmcia_init *init){
-  int return_val=0;
-
+static int xp860_pcmcia_init(struct pcmcia_init *init)
+{
   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
   
   /* MAX1600 to standby mode: */
   PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+
+#error Consider the following comment
+  /*
+   * 1- Please move GPDR initialisation  where it is interrupt or preemption
+   *    safe (like from xp860_map_io).
+   * 2- The GPCR line is bogus i.e. it will simply have absolutely no effect.
+   *    Please see its definition in the SA1110 manual.
+   * 3- Please do not use NCR_* values!
+   */
   GPDR |= (NCR_A0VPP | NCR_A1VPP);
   GPCR &= ~(NCR_A0VPP | NCR_A1VPP);
 
-  INTPOL1 |= 
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "XP860 PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "XP860 CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "XP860 PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "XP860 CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
+  return sa1111_pcmcia_init(init);
 }
 
-static int xp860_pcmcia_shutdown(void){
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= 
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int xp860_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array){
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int xp860_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
-}
-
-static int xp860_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure){
-  unsigned long pccr=PCCR, ncr=GPLR, gpio=PA_DWR;
-
+static int
+xp860_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+  unsigned int gpio_mask, pa_dwr_mask;
+  unsigned int gpio_set, pa_dwr_set;
+  int ret;
 
   /* Neponset uses the Maxim MAX1600, with the following connections:
+#warning ^^^ This isn't a neponset!
    *
    *   MAX1600      Neponset
    *
@@ -151,105 +68,75 @@
    * the corresponding truth table.
    */
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
-    
-    switch(configure->vcc){
-    case 0:
-      gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S0_PSE);
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S0_PSE);
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
-      break;
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
+    gpio_mask = NCR_A0VPP | NCR_A1VPP;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;			break;
+    case 33:	pa_dwr_set = GPIO_GPIO1;	break;
+    case 50:	pa_dwr_set = GPIO_GPIO0;	break;
     }
 
-    switch(configure->vpp){
-    case 0:
-      ncr&=~(NCR_A0VPP | NCR_A1VPP);
-      break;
-
-    case 120:
-      ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
-      break;
+    switch (conf->vpp) {
+    case 0:	gpio_set = 0;			break;
+    case 120:	gpio_set = NCR_A1VPP;		break;
 
     default:
-      if(configure->vpp == configure->vcc)
-	ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
+      if (conf->vpp == conf->vcc)
+	gpio_set = NCR_A0VPP;
       else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
+	printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
+	       __FUNCTION__, conf->vpp);
 	return -1;
       }
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-    pccr=(configure->output)?(pccr | PCCR_S0_FLT):(pccr & ~PCCR_S0_FLT);
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S1_PSE);
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S1_PSE);
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
-      break;
+    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
+    gpio_mask = 0;
+    gpio_set = 0;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;			break;
+    case 33:	pa_dwr_set = GPIO_GPIO2;	break;
+    case 50:	pa_dwr_set = GPIO_GPIO3;	break;
     }
 
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
+    if (conf->vpp != conf->vcc && conf->vpp != 0) {
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+	     __FUNCTION__, conf->vpp);
       return -1;
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-    pccr=(configure->output)?(pccr | PCCR_S1_FLT):(pccr & ~PCCR_S1_FLT);
-
     break;
-
-  default:
-    return -1;
   }
 
-  PCCR = pccr;
-  ncr &= NCR_A0VPP|NCR_A1VPP;
-  GPSR = ncr;
-  GPCR = (~ncr)&(NCR_A0VPP|NCR_A1VPP);
-  PA_DWR = gpio;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    GPSR = gpio_set;
+    GPCR = gpio_set ^ gpio_mask;
+    local_irq_restore(flags);
+  }
 
-  return 0;
+  return ret;
 }
 
 struct pcmcia_low_level xp860_pcmcia_ops = { 
-  xp860_pcmcia_init,
-  xp860_pcmcia_shutdown,
-  xp860_pcmcia_socket_state,
-  xp860_pcmcia_get_irq_info,
-  xp860_pcmcia_configure_socket
+  init:			xp860_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	xp860_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1100_yopy.c linux-2.4.19-pre5/drivers/pcmcia/sa1100_yopy.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1100_yopy.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1100_yopy.c	Fri Mar 29 14:49:43 2002
@@ -9,7 +9,7 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 
 static inline void pcmcia_power(int on) {
@@ -30,13 +30,9 @@
 	pcmcia_power(0);
 	pcmcia_reset(1);
 
-	/* All those are inputs */
-	GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
-	GAFR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
-
 	/* Set transition detect */
-	set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1,
-			   GPIO_BOTH_EDGES );
+	set_GPIO_IRQ_edge(GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1,
+			  GPIO_NO_EDGES);
 	set_GPIO_IRQ_edge( GPIO_CF_IREQ, GPIO_FALLING_EDGE );
 
 	/* Register interrupts */
@@ -130,10 +126,27 @@
 	return 0;
 }
 
+static int yopy_pcmcia_socket_init(int sock)
+{
+	set_GPIO_IRQ_edge(GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1,
+			  GPIO_BOTH_EDGES);
+	return 0;
+}
+
+static int yopy_pcmcia_socket_suspend(int sock)
+{
+	set_GPIO_IRQ_edge(GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1,
+			  GPIO_NO_EDGES);
+	return 0;
+}
+
 struct pcmcia_low_level yopy_pcmcia_ops = {
-	yopy_pcmcia_init,
-	yopy_pcmcia_shutdown,
-	yopy_pcmcia_socket_state,
-	yopy_pcmcia_get_irq_info,
-	yopy_pcmcia_configure_socket
+	init:			yopy_pcmcia_init,
+	shutdown:		yopy_pcmcia_shutdown,
+	socket_state:		yopy_pcmcia_socket_state,
+	get_irq_info:		yopy_pcmcia_get_irq_info,
+	configure_socket:	yopy_pcmcia_configure_socket,
+
+	socket_init:		yopy_pcmcia_socket_init,
+	socket_suspend:		yopy_pcmcia_socket_suspend,
 };
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1111_generic.c linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.c
--- linux-2.4.19-pre4/drivers/pcmcia/sa1111_generic.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.c	Fri Mar 29 14:49:43 2002
@@ -0,0 +1,189 @@
+/*
+ * linux/drivers/pcmcia/sa1100_sa1111.c
+ *
+ * We implement the generic parts of a SA1111 PCMCIA driver.  This
+ * basically means we handle everything except controlling the
+ * power.  Power is machine specific...
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/irq.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
+
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ S0_CD_VALID,    "SA1111 PCMCIA card detect" },
+	{ S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
+	{ S1_CD_VALID,    "SA1111 CF card detect"     },
+	{ S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
+};
+
+int sa1111_pcmcia_init(struct pcmcia_init *init)
+{
+	int i, ret;
+
+	if (!request_mem_region(_PCCR, 512, "PCMCIA"))
+		return -1;
+
+	INTPOL1 |= SA1111_IRQMASK_HI(S0_CD_VALID) |
+		   SA1111_IRQMASK_HI(S1_CD_VALID) |
+		   SA1111_IRQMASK_HI(S0_BVD1_STSCHG) |
+		   SA1111_IRQMASK_HI(S1_BVD1_STSCHG);
+
+	for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
+		ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (ret)
+			break;
+	}
+
+	if (i < ARRAY_SIZE(irqs)) {
+		printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n",
+			irqs[i].irq, ret);
+		while (i--)
+			free_irq(irqs[i].irq, NULL);
+
+		release_mem_region(_PCCR, 16);
+	}
+
+	return ret ? -1 : 2;
+}
+
+int sa1111_pcmcia_shutdown(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
+
+	INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) |
+		     SA1111_IRQMASK_HI(S1_CD_VALID) |
+		     SA1111_IRQMASK_HI(S0_BVD1_STSCHG) |
+		     SA1111_IRQMASK_HI(S1_BVD1_STSCHG));
+
+	release_mem_region(_PCCR, 512);
+
+	return 0;
+}
+
+int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state)
+{
+	unsigned long status;
+
+	if (state->size < 2)
+		return -1;
+
+	status = PCSR;
+
+	state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
+	state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
+	state->state[0].bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
+	state->state[0].bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
+	state->state[0].wrprot = status & PCSR_S0_WP     ? 1 : 0;
+	state->state[0].vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
+	state->state[0].vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
+
+	state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1;
+	state->state[1].ready  = status & PCSR_S1_READY  ? 1 : 0;
+	state->state[1].bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
+	state->state[1].bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
+	state->state[1].wrprot = status & PCSR_S1_WP     ? 1 : 0;
+	state->state[1].vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
+	state->state[1].vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
+
+	return 1;
+}
+
+int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	int ret = 0;
+
+	switch (info->sock) {
+	case 0:	info->irq = S0_READY_NINT;	break;
+	case 1: info->irq = S1_READY_NINT;	break;
+	default: ret = 1;
+	}
+
+	return ret;
+}
+
+int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	unsigned int rst, flt, wait, pse, irq, pccr_mask;
+	unsigned long flags;
+
+	switch (conf->sock) {
+	case 0:
+		rst = PCCR_S0_RST;
+		flt = PCCR_S0_FLT;
+		wait = PCCR_S0_PWAITEN;
+		pse = PCCR_S0_PSE;
+		irq = S0_READY_NINT;
+		break;
+
+	case 1:
+		rst = PCCR_S1_RST;
+		flt = PCCR_S1_FLT;
+		wait = PCCR_S1_PWAITEN;
+		pse = PCCR_S1_PSE;
+		irq = S1_READY_NINT;
+		break;
+
+	default:
+		return -1;
+	}
+
+	switch (conf->vcc) {
+	case 0:
+		pccr_mask = 0;
+		break;
+
+	case 33:
+		pccr_mask = wait;
+		break;
+
+	case 50:
+		pccr_mask = pse | wait;
+		break;
+
+	default:
+		printk(KERN_ERR "sa1111_pcmcia: unrecognised VCC %u\n",
+			conf->vcc);
+		return -1;
+	}
+
+	if (conf->reset)
+		pccr_mask |= rst;
+
+	if (conf->output)
+		pccr_mask |= flt;
+
+	local_irq_save(flags);
+	PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask;
+	local_irq_restore(flags);
+
+	if (conf->irq)
+		enable_irq(irq);
+	else
+		disable_irq(irq);
+
+	return 0;
+}
+
+int sa1111_pcmcia_socket_init(int sock)
+{
+	return 0;
+}
+
+int sa1111_pcmcia_socket_suspend(int sock)
+{
+	return 0;
+}
diff -urN linux-2.4.19-pre4/drivers/pcmcia/sa1111_generic.h linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.h
--- linux-2.4.19-pre4/drivers/pcmcia/sa1111_generic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/drivers/pcmcia/sa1111_generic.h	Fri Mar 29 14:49:43 2002
@@ -0,0 +1,15 @@
+extern int sa1111_pcmcia_init(struct pcmcia_init *);
+extern int sa1111_pcmcia_shutdown(void);
+extern int sa1111_pcmcia_socket_state(struct pcmcia_state_array *);
+extern int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *);
+extern int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *);
+extern int sa1111_pcmcia_socket_init(int);
+extern int sa1111_pcmcia_socket_suspend(int);
+
+/*
+ * I'd really like to move the INTPOL stuff to arch/arm/mach-sa1100/sa1111.c
+ */
+#define SA1111_IRQMASK_LO(x)	(1 << (x - IRQ_SA1111_START))
+#define SA1111_IRQMASK_HI(x)	(1 << (x - IRQ_SA1111_START - 32))
+
+
diff -urN linux-2.4.19-pre4/drivers/s390/char/hwc_con.c linux-2.4.19-pre5/drivers/s390/char/hwc_con.c
--- linux-2.4.19-pre4/drivers/s390/char/hwc_con.c	Wed Jul 25 14:12:02 2001
+++ linux-2.4.19-pre5/drivers/s390/char/hwc_con.c	Fri Mar 29 14:49:43 2002
@@ -31,20 +31,12 @@
 
 #define  HWC_CON_PRINT_HEADER "hwc console driver: "
 
-struct console hwc_console =
-{
-
-	hwc_console_name,
-	hwc_console_write,
-	NULL,
-	hwc_console_device,
-	NULL,
-	hwc_console_unblank,
-	NULL,
-	CON_PRINTBUFFER,
-	0,
-	0,
-	NULL
+struct console hwc_console = {
+	name:	hwc_console_name,
+	write:	hwc_console_write,
+	device:	hwc_console_device,
+	unblank:hwc_console_unblank,
+	flags:	CON_PRINTBUFFER,
 };
 
 void 
diff -urN linux-2.4.19-pre4/drivers/s390/net/ctctty.c linux-2.4.19-pre5/drivers/s390/net/ctctty.c
--- linux-2.4.19-pre4/drivers/s390/net/ctctty.c	Wed Jul 25 14:12:02 2001
+++ linux-2.4.19-pre5/drivers/s390/net/ctctty.c	Fri Mar 29 14:49:43 2002
@@ -286,7 +286,7 @@
 
 	if (!info->netdev) {
 		if (skb)
-			kfree(skb);
+			kfree_skb(skb);
 		return 0;
 	}
 	if (info->flags & CTC_ASYNC_TX_LINESTAT) {
diff -urN linux-2.4.19-pre4/drivers/sbus/audio/amd7930.c linux-2.4.19-pre5/drivers/sbus/audio/amd7930.c
--- linux-2.4.19-pre4/drivers/sbus/audio/amd7930.c	Wed Oct 17 14:16:39 2001
+++ linux-2.4.19-pre5/drivers/sbus/audio/amd7930.c	Fri Mar 29 14:49:44 2002
@@ -1619,7 +1619,6 @@
 	info->irq = irq.pri;
 	request_irq(info->irq, amd7930_interrupt,
 		    SA_INTERRUPT, "amd7930", drv);
-	enable_irq(info->irq);
 	amd7930_enable_ints(info);
 
 	/* Initalize the local copy of the MAP registers. */
@@ -1644,7 +1643,6 @@
 	err = register_sparcaudio_driver(drv, 1);
 	if (err < 0) {
 		printk(KERN_ERR "amd7930: unable to register\n");
-		disable_irq(info->irq);
 		free_irq(info->irq, drv);
 		sbus_iounmap(info->regs, info->regs_size);
 		kfree(drv->private);
@@ -1666,7 +1664,6 @@
 
 	unregister_sparcaudio_driver(drv, 1);
 	amd7930_idle(info);
-	disable_irq(info->irq);
 	free_irq(info->irq, drv);
 	sbus_iounmap(info->regs, info->regs_size);
 	kfree(drv->private);
diff -urN linux-2.4.19-pre4/drivers/sbus/audio/cs4231.c linux-2.4.19-pre5/drivers/sbus/audio/cs4231.c
--- linux-2.4.19-pre4/drivers/sbus/audio/cs4231.c	Wed Oct 10 23:42:46 2001
+++ linux-2.4.19-pre5/drivers/sbus/audio/cs4231.c	Fri Mar 29 14:49:44 2002
@@ -2210,7 +2210,6 @@
         /* Attach the interrupt handler to the audio interrupt. */
         cs4231_chip->irq = sdev->irqs[0];
         request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv);
-        enable_irq(cs4231_chip->irq);
 
         cs4231_chip->nirqs = 1;
         cs4231_enable_interrupts(drv);
@@ -2224,7 +2223,6 @@
         if (err < 0) {
                 printk(KERN_ERR "cs4231: unable to register\n");
                 cs4231_disable_interrupts(drv);
-                disable_irq(cs4231_chip->irq);
                 free_irq(cs4231_chip->irq, drv);
                 sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
                 kfree(drv->private);
@@ -2312,9 +2310,7 @@
         bail:
                 printk(KERN_ERR "cs4231: unable to register\n");
                 cs4231_disable_interrupts(drv);
-                disable_irq(cs4231_chip->irq);
                 free_irq(cs4231_chip->irq, drv);
-                disable_irq(cs4231_chip->irq2);
                 free_irq(cs4231_chip->irq2, drv);
                 kfree(drv->private);
                 return -EIO;
@@ -2371,7 +2367,6 @@
 
 	cs4231_disable_interrupts(drv);
 	unregister_sparcaudio_driver(drv, 1);
-	disable_irq(cs4231_chip->irq);
 	free_irq(cs4231_chip->irq, drv);
 	if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
 		sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
@@ -2380,7 +2375,6 @@
 		iounmap(cs4231_chip->regs);
 		iounmap(cs4231_chip->eb2p);
 		iounmap(cs4231_chip->eb2c);
-		disable_irq(cs4231_chip->irq2);
 		free_irq(cs4231_chip->irq2, drv);
 #endif
 	}
diff -urN linux-2.4.19-pre4/drivers/sbus/char/uctrl.c linux-2.4.19-pre5/drivers/sbus/char/uctrl.c
--- linux-2.4.19-pre4/drivers/sbus/char/uctrl.c	Wed Oct 10 23:42:47 2001
+++ linux-2.4.19-pre5/drivers/sbus/char/uctrl.c	Fri Mar 29 14:49:44 2002
@@ -389,15 +389,11 @@
 	if(!driver->irq) 
 		driver->irq = tmp_irq[0].pri;
 
-	request_irq(driver->irq, uctrl_interrupt, 0, 
-		    "uctrl", driver);
-
-	enable_irq(driver->irq);
+	request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
 
 	if (misc_register(&uctrl_dev)) {
 		printk("%s: unable to get misc minor %d\n",
 		       __FUNCTION__, uctrl_dev.minor);
-		disable_irq(driver->irq);
 		free_irq(driver->irq, driver);
 		return -ENODEV;
 	}
@@ -414,10 +410,8 @@
 	struct uctrl_driver *driver = &drv;
 
 	misc_deregister(&uctrl_dev);
-	if (driver->irq) {
-		disable_irq(driver->irq);
+	if (driver->irq)
 		free_irq(driver->irq, driver);
-	}
 	if (driver->regs)
 		driver->regs = 0;
 }
diff -urN linux-2.4.19-pre4/drivers/scsi/3w-xxxx.c linux-2.4.19-pre5/drivers/scsi/3w-xxxx.c
--- linux-2.4.19-pre4/drivers/scsi/3w-xxxx.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre5/drivers/scsi/3w-xxxx.c	Fri Mar 29 14:49:45 2002
@@ -121,13 +121,28 @@
    1.02.00.015 - Re-write raw command post with data ioctl method.
    1.02.00.016 - Set max_cmd_len for 3dm.
                  Set max sectors to 256 for non raid5 & 6XXX.          
+   1.02.00.017 - Modified pci parity error handling/clearing from config space
+                 during initialization.
+   1.02.00.018 - Better handling of request sense opcode and sense information
+                 for failed commands.  Add tw_decode_sense().
+                 Replace all mdelay()'s with scsi_sleep().
+   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
+                 some SMP systems.
+   1.02.00.020 - Bump cmd_per_lun in SHT to 255 for better jbod performance.
+                 Make module license ifdef'd for backward compatibility.
+                 Improve handling of errors in tw_interrupt().
+                 Add handling/clearing of controller queue error.
+                 Better alignment checking in tw_allocate_memory().
+                 Cleanup tw_initialize_device_extension().
+                 Empty stale responses before draining aen queue.
+                 Fix tw_scsi_eh_abort() to not reset on every io abort.
+                 Set can_queue in SHT to 255 to prevent hang from AEN.
 */
 
 #include <linux/module.h>
 
 MODULE_AUTHOR ("3ware Inc.");
 MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
-MODULE_LICENSE("GPL");
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -156,6 +171,10 @@
 
 #include "3w-xxxx.h"
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+MODULE_LICENSE("GPL");
+#endif
+
 static int tw_copy_info(TW_Info *info, char *fmt, ...);
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -167,7 +186,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.016";
+char *tw_driver_version="1.02.00.020";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -269,6 +288,9 @@
 	}
 	tw_clear_attention_interrupt(tw_dev);
 
+	/* Empty response queue */
+	tw_empty_response_que(tw_dev);
+
 	/* Initialize command packet */
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
 		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
@@ -322,7 +344,7 @@
 			status_reg_value = inl(status_reg_addr);
 			if (tw_check_bits(status_reg_value)) {
 				dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value);
+				tw_decode_bits(tw_dev, status_reg_value, 0);
 				return 1;
 			}
 			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -338,8 +360,7 @@
 				if (command_packet->status != 0) {
 					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
 						/* Bad response */
-						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-						tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+						tw_decode_sense(tw_dev, request_id, 0);
 						return 1;
 					} else {
 						/* We know this is a 3w-1x00, and doesn't support aen's */
@@ -437,7 +458,7 @@
 	status_reg_value = inl(status_reg_addr);
 	if (tw_check_bits(status_reg_value)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
+		tw_decode_bits(tw_dev, status_reg_value, 1);
 		return 1;
 	}
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -504,9 +525,9 @@
 		return 1;
 	}
 
-	if ((u32)virt_addr % TW_ALIGNMENT) {
+	if ((u32)virt_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
 		kfree(virt_addr);
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
+		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
 		return 1;
 	}
 
@@ -552,12 +573,24 @@
 	status_reg_addr = tw_dev->registers.status_reg_addr;
 	status_reg_value = inl(status_reg_addr);
 
-	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value))
+	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
+		tw_decode_bits(tw_dev, status_reg_value, 0);
 		return 1;
+	}
 
 	return 0;
 } /* End tw_check_errors() */
 
+/* This function will clear all interrupts on the controller */
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
+{
+	u32 control_reg_addr, control_reg_value;
+
+	control_reg_addr = tw_dev->registers.control_reg_addr;
+	control_reg_value = TW_STATUS_VALID_INTERRUPT;
+	outl(control_reg_value, control_reg_addr);
+} /* End tw_clear_all_interrupts() */
+
 /* This function will clear the attention interrupt */
 void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -613,47 +646,90 @@
 } /* End tw_copy_mem_info() */
 
 /* This function will print readable messages from status register errors */
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
 {
+	char host[16];
+	
 	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
+
+	if (print_host)
+		sprintf(host, " scsi%d:", tw_dev->host->host_no);
+	else
+		host[0] = '\0';
+
 	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
 	case TW_STATUS_PCI_PARITY_ERROR:
-		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n");
+		printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
-		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS);
 		break;
 	case TW_STATUS_MICROCONTROLLER_ERROR:
-		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
-		break;
+		if (tw_dev->reset_print == 0) {
+			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+			tw_dev->reset_print = 1;
+		}
+		return 1;
 	case TW_STATUS_PCI_ABORT:
-		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
+		printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
 		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
 		break;
-  }
+	case TW_STATUS_QUEUE_ERROR:
+		printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
+		break;
+	case TW_STATUS_SBUF_WRITE_ERROR:
+		printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
+		break;
+	}
+
+	return 0;
 } /* End tw_decode_bits() */
 
-/* This function will print readable messages from flags and status values */
-void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit)
+/* This function will return valid sense buffer information for failed cmds */
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
 {
-	dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n");
-	switch (status) {
-	case 0xc7:
-		switch (flags) {
-		case 0x1b: 
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit);
-			break;
-		case 0x51:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit);
-			break;
-		default:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
+	int i;
+	TW_Command *command;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
+	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit);
+
+	/* Attempt to return intelligent sense information */
+	if (fill_sense) {
+		if ((command->status == 0xc7) || (command->status == 0xcb)) {
+			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
+				if (command->flags == tw_sense_table[i][0]) {
+
+					/* Valid bit and 'current errors' */
+					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
+
+					/* Sense key */
+					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
+
+					/* Additional sense length */
+					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
+
+					/* Additional sense code */
+					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
+
+					/* Additional sense code qualifier */
+					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
+
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+					return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
+				}
+			}
 		}
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
+
+		/* If no table match, error so we get a reset */
+		return 1;
 	}
-} /* End tw_decode_error() */
+
+	return 0;
+} /* End tw_decode_sense() */
 
 /* This function will disable interrupts on the controller */  
 void tw_disable_interrupts(TW_Device_Extension *tw_dev) 
@@ -666,7 +742,7 @@
 } /* End tw_disable_interrupts() */
 
 /* This function will empty the response que */
-int tw_empty_response_que(TW_Device_Extension *tw_dev) 
+void tw_empty_response_que(TW_Device_Extension *tw_dev) 
 {
 	u32 status_reg_addr, status_reg_value;
 	u32 response_que_addr, response_que_value;
@@ -676,22 +752,10 @@
   
 	status_reg_value = inl(status_reg_addr);
 
-	if (tw_check_bits(status_reg_value)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
-		return 1;
-	}
-  
 	while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
 		response_que_value = inl(response_que_addr);
 		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
-			return 1;
-		}
 	}
-	return 0;
 } /* End tw_empty_response_que() */
 
 /* This function will enable interrupts on the controller */
@@ -744,6 +808,9 @@
 			}
 			memset(tw_dev, 0, sizeof(TW_Device_Extension));
 
+			/* Save pci_dev struct to device extension */
+			tw_dev->tw_pci_dev = tw_pci_dev;
+
 			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
@@ -758,13 +825,11 @@
 			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
 			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
 			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
-			/* Save pci_dev struct to device extension */
-			tw_dev->tw_pci_dev = tw_pci_dev;
 
 			/* Check for errors and clear them */
 			status_reg_value = inl(tw_dev->registers.status_reg_addr);
-			if (TW_STATUS_ERRORS(status_reg_value)) 
-			  tw_decode_bits(tw_dev, status_reg_value);
+			if (TW_STATUS_ERRORS(status_reg_value))
+				tw_decode_bits(tw_dev, status_reg_value, 0);
 			
 			/* Poll status register for 60 secs for 'Controller Ready' flag */
 			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
@@ -780,7 +845,7 @@
 			while (tries < TW_MAX_RESET_TRIES) {
 				/* Do soft reset */
 				tw_soft_reset(tw_dev);
-			  
+
 				error = tw_aen_drain_queue(tw_dev);
 				if (error) {
 					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
@@ -795,14 +860,6 @@
 					continue;
 				}
 
-				/* Empty the response queue */
-				error = tw_empty_response_que(tw_dev);
-				if (error) {
-					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
-					tries++;
-					continue;
-				}
-
 				/* Now the controller is in a good state */
 				break;
 			}
@@ -829,7 +886,7 @@
 			request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
 			error = tw_initialize_units(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", numcards);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -853,7 +910,7 @@
 					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
 					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
 				} else {
-					tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
+					/* Use SHT cmd_per_lun here */
 					tw_dev->free_head = TW_Q_START;
 					tw_dev->free_tail = TW_Q_LENGTH - 1;
 					tw_dev->free_wrap = TW_Q_LENGTH - 1;
@@ -1033,7 +1090,7 @@
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 0);
 			return 1;
 		}
 		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1046,8 +1103,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			break;	/* Response was okay, so we exit */
@@ -1059,12 +1115,11 @@
 /* This function will initialize the fields of a device extension */
 int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i, imax;
+	int i;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
-	imax = TW_Q_LENGTH;
 
-	for (i=0; i<imax; i++) {
+	for (i=0;i<TW_Q_LENGTH;i++) {
 		/* Initialize command packet buffers */
 		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
 		if (tw_dev->command_packet_virtual_address[i] == NULL) {
@@ -1083,34 +1138,12 @@
 
 		tw_dev->free_queue[i] = i;
 		tw_dev->state[i] = TW_S_INITIAL;
-		tw_dev->ioctl_size[i] = 0;
-		tw_dev->aen_queue[i] = 0;
-		tw_dev->ioctl_data[i] = NULL;
-	}
-
-	for (i=0;i<TW_MAX_UNITS;i++) {
-		tw_dev->is_unit_present[i] = 0;
-		tw_dev->is_raid_five[i] = 0;
 	}
 
-	tw_dev->num_units = 0;
-	tw_dev->num_aborts = 0;
-	tw_dev->num_resets = 0;
-	tw_dev->posted_request_count = 0;
-	tw_dev->max_posted_request_count = 0;
-	tw_dev->max_sgl_entries = 0;
-	tw_dev->sgl_entries = 0;
-	tw_dev->host = NULL;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
-	tw_dev->aen_head = 0;
-	tw_dev->aen_tail = 0;
-	tw_dev->sector_count = 0;
-	tw_dev->max_sector_count = 0;
-	tw_dev->aen_count = 0;
-	tw_dev->num_raid_five = 0;
 	spin_lock_init(&tw_dev->tw_lock);
-	tw_dev->flags = 0;
+
 	return 0;
 } /* End tw_initialize_device_extension() */
 
@@ -1187,7 +1220,7 @@
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 0);
 			return 1;
 		}
 		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1200,8 +1233,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			found = 1;
@@ -1291,7 +1323,7 @@
 			status_reg_value = inl(status_reg_addr);
 			if (tw_check_bits(status_reg_value)) {
 				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value);
+				tw_decode_bits(tw_dev, status_reg_value, 0);
 				return 1;
 			}
 			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1304,8 +1336,7 @@
 				}
 				if (command_packet->status != 0) {
 					/* bad response */
-					dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+					tw_decode_sense(tw_dev, request_id, 0);
 					return 1;
 				}
 				found = 1;
@@ -1351,46 +1382,52 @@
 	u32 response_que_addr;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
 	TW_Response_Queue response_que;
-	int error = 0;
-	int do_response_interrupt=0;
-	int do_attention_interrupt=0;
-	int do_host_interrupt=0;
-	int do_command_interrupt=0;
+	int error = 0, retval = 0;
 	unsigned long flags = 0;
 	TW_Command *command_packet;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
+
+	/* See if we are already running on another processor */
 	if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
 		return;
-	spin_lock_irqsave(&io_request_lock, flags);
 
+	/* Get the block layer lock for io completions */
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	/* See if the interrupt matches this instance */
 	if (tw_dev->tw_pci_dev->irq == irq) {
+
+		/* Make sure io isn't queueing */
 		spin_lock(&tw_dev->tw_lock);
-		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
 
 		/* Read the registers */
 		status_reg_addr = tw_dev->registers.status_reg_addr;
 		response_que_addr = tw_dev->registers.response_que_addr;
 		status_reg_value = inl(status_reg_addr);
 
-		/* Check which interrupt */
-		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
-			do_host_interrupt=1;
-		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT)
-			do_attention_interrupt=1;
-		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT)
-			do_command_interrupt=1;
-		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT)
-			do_response_interrupt=1;
+		/* Check if this is our interrupt, otherwise bail */
+		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+			goto tw_interrupt_bail;
+
+		/* Check controller for errors */
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+			if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+				tw_clear_all_interrupts(tw_dev);
+				goto tw_interrupt_bail;
+			}
+		}
 
 		/* Handle host interrupt */
-		if (do_host_interrupt) {
+		if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
 			tw_clear_host_interrupt(tw_dev);
 		}
 
 		/* Handle attention interrupt */
-		if (do_attention_interrupt) {
+		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
-			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
 			tw_clear_attention_interrupt(tw_dev);
 			tw_state_request_start(tw_dev, &request_id);
 			error = tw_aen_read_queue(tw_dev, request_id);
@@ -1402,7 +1439,7 @@
 		}
 
 		/* Handle command interrupt */
-		if (do_command_interrupt) {
+		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
 			/* Drain as many pending commands as we can */
 			while (tw_dev->pending_request_count > 0) {
 				request_id = tw_dev->pending_queue[tw_dev->pending_head];
@@ -1418,6 +1455,7 @@
 					}
 					tw_dev->pending_request_count--;
 				} else {
+					printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no);
 					break;
 				}
 			}
@@ -1427,40 +1465,41 @@
 		}
 
 		/* Handle response interrupt */
-		if (do_response_interrupt) {
+		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
 			/* Drain the response queue from the board */
 			while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+				/* Read response queue register */
 				response_que.value = inl(response_que_addr);
 				request_id = response_que.u.response_id;
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
 				error = 0;
+
+				/* Check for bad response */
 				if (command_packet->status != 0) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					error = 1;
+					/* If internal command, don't error, don't fill sense */
+					if (tw_dev->srb[request_id] == 0) {
+						tw_decode_sense(tw_dev, request_id, 0);
+					} else {
+						error = tw_decode_sense(tw_dev, request_id, 1);
+					}
 				}
+
+				/* Check for correct state */
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
 					error = 1;
 				}
-				if (TW_STATUS_ERRORS(status_reg_value)) {
-				  tw_decode_bits(tw_dev, status_reg_value);
-				  error = 1;
-				}
+
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
-				/* Check for internal command */
+
+				/* Check for internal command completion */
 				if (tw_dev->srb[request_id] == 0) {
 					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-					error = tw_aen_complete(tw_dev, request_id);
-					if (error) {
+					retval = tw_aen_complete(tw_dev, request_id);
+					if (retval) {
 						printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
 					}
-					status_reg_value = inl(status_reg_addr);
-					if (tw_check_bits(status_reg_value)) {
-						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-						tw_decode_bits(tw_dev, status_reg_value);
-					}
-		} else {
+				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
 					case READ_10:
 					case READ_6:
@@ -1483,35 +1522,45 @@
 						error = tw_ioctl_complete(tw_dev, request_id);
 						break;
 					default:
-						printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]);
-						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
-						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-					}
-					if (error == 1) {
-						/* Tell scsi layer there was an error */
-						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
-						tw_dev->srb[request_id]->result = (DID_RESET << 16);
+						printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+						error = 1;
 					}
+
+					/* If no error command was a success */
 					if (error == 0) {
-						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
 					}
-					if (error != 2) {
+
+					/* If error, command failed */
+					if (error == 1) {
+						tw_dev->srb[request_id]->result = (DID_RESET << 16);
+					}
+					
+					/* Now complete the io */
+					if ((error != TW_ISR_DONT_COMPLETE)) {
 						tw_dev->state[request_id] = TW_S_COMPLETED;
 						tw_state_request_finish(tw_dev, request_id);
 						tw_dev->posted_request_count--;
 						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
 					}
-					status_reg_value = inl(status_reg_addr);
-					if (tw_check_bits(status_reg_value)) {
-						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-						tw_decode_bits(tw_dev, status_reg_value);
+				}
+
+				/* Check for valid status after each drain */
+				status_reg_value = inl(status_reg_addr);
+				if (tw_check_bits(status_reg_value)) {
+					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+					if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+						tw_clear_all_interrupts(tw_dev);
+						goto tw_interrupt_bail;
 					}
 				}
 			}
 		}
+tw_interrupt_bail:
 		spin_unlock(&tw_dev->tw_lock);
-	}
+	} else
+		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n");
+
 	spin_unlock_irqrestore(&io_request_lock, flags);
 	clear_bit(TW_IN_INTR, &tw_dev->flags);
 } /* End tw_interrupt() */
@@ -1871,7 +1920,7 @@
 			break;
 		case TW_CMD_PACKET_WITH_DATA:
 			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
-			return 2; /* Special case for isr to not complete io */
+			return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */
 		default:
 			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
 			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -1905,14 +1954,25 @@
 	do_gettimeofday(&before);
 	status_reg_value = inl(status_reg_addr);
 
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value, 0);
+	}
+
 	while ((status_reg_value & flag) != flag) {
 		status_reg_value = inl(status_reg_addr);
+
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value, 0);
+		}
+
 		do_gettimeofday(&timeout);
 		if (before.tv_sec + seconds < timeout.tv_sec) { 
 			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
 			return 1;
 		}
-		mdelay(1);
+		mdelay(5);
 	}
 	return 0;
 } /* End tw_poll_status() */
@@ -1931,7 +1991,7 @@
 
 	if (tw_check_bits(status_reg_value)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
+		tw_decode_bits(tw_dev, status_reg_value, 1);
 	}
 
 	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
@@ -1985,7 +2045,6 @@
 		    (tw_dev->state[i] != TW_S_COMPLETED)) {
 			srb = tw_dev->srb[i];
 			if (srb != NULL) {
-				srb = tw_dev->srb[i];
 				srb->result = (DID_RESET << 16);
 				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
 			}
@@ -2003,6 +2062,7 @@
 	tw_dev->pending_request_count = 0;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->reset_print = 0;
 
 	return 0;
 } /* End tw_reset_device_extension() */
@@ -2034,14 +2094,6 @@
 			continue;
 		}
 
-		/* Empty the response queue again */
-		error = tw_empty_response_que(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no);
-			tries++;
-			continue;
-		}
-
 		/* Now the controller is in a good state */
 		break;
 	}
@@ -2131,11 +2183,6 @@
 		return (FAILED);
 	}
 
-	/* We have to let AEN requests through before the reset */
-	spin_unlock_irq(&io_request_lock);
-	mdelay(TW_AEN_WAIT_TIME);
-	spin_lock_irq(&io_request_lock);
-
 	spin_lock(&tw_dev->tw_lock);
 	tw_dev->num_aborts++;
 
@@ -2162,18 +2209,26 @@
 				spin_unlock(&tw_dev->tw_lock);
 				return (SUCCESS);
 			}
+			if (tw_dev->state[i] == TW_S_POSTED) {
+				/* If the command has already been posted, we have to reset the card */
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
+				/* We have to let AEN requests through before the reset */
+				spin_unlock(&tw_dev->tw_lock);
+				spin_unlock_irq(&io_request_lock);
+				mdelay(TW_AEN_WAIT_TIME);
+				spin_lock_irq(&io_request_lock);
+				spin_lock(&tw_dev->tw_lock);
+
+				if (tw_reset_device_extension(tw_dev)) {
+					dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
+					spin_unlock(&tw_dev->tw_lock);
+					return (FAILED);
+				}
+			}
 		}
 	}
 
-	/* If the command has already been posted, we have to reset the card */
-	printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
-	if (tw_reset_device_extension(tw_dev)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
-		spin_unlock(&tw_dev->tw_lock);
-		return (FAILED);
-	}
 	spin_unlock(&tw_dev->tw_lock);
-
 	return (SUCCESS);
 } /* End tw_scsi_eh_abort() */
 
@@ -2638,7 +2693,7 @@
 	}
 
 	command_packet->byte0.sgl_offset = 3;
-	command_packet->size = 5;
+	command_packet->size = 3;
 	command_packet->request_id = request_id;
 	command_packet->byte3.unit = srb->target;
 	command_packet->byte3.host_id = 0;
@@ -2673,6 +2728,7 @@
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
 			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+			command_packet->size+=2;
 		}
 
 		/* Do this if we have multiple sg list entries */
@@ -2682,8 +2738,6 @@
 				command_packet->byte8.io.sgl[i].length = sglist[i].length;
 				command_packet->size+=2;
 			}
-			if (tw_dev->srb[request_id]->use_sg >= 1)
-				command_packet->size-=2;
 		}
 	} else {
                 /* Do this if there are no sg list entries for raid 5 */
@@ -2692,6 +2746,7 @@
 			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
 			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+			command_packet->size+=2;
                 }
 
                 /* Do this if we have multiple sg list entries for raid 5 */
@@ -2727,18 +2782,19 @@
 /* This function will handle the request sense scsi command */
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
   
-       /* For now we just zero the sense buffer */
-       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-       tw_dev->state[request_id] = TW_S_COMPLETED;
-       tw_state_request_finish(tw_dev, request_id);
+	/* For now we just zero the request buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+       
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
   
-       /* If we got a request_sense, we probably want a reset, return error */
-       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
-       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
   
-       return 0;
+	return 0;
 } /* End tw_scsiop_request_sense() */
 
 /* This function will handle test unit ready scsi command */
@@ -2819,7 +2875,7 @@
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 1);
 			return 1;
 		}
 		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -2832,8 +2888,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			break; /* Response was okay, so we exit */
diff -urN linux-2.4.19-pre4/drivers/scsi/3w-xxxx.h linux-2.4.19-pre5/drivers/scsi/3w-xxxx.h
--- linux-2.4.19-pre4/drivers/scsi/3w-xxxx.h	Fri Mar 29 14:49:11 2002
+++ linux-2.4.19-pre5/drivers/scsi/3w-xxxx.h	Fri Mar 29 14:49:45 2002
@@ -92,10 +92,35 @@
 	"Verify failed: Port #",                // 0x02A
 	"Verify complete: Unit #",              // 0x02B
 	"Overwrote bad sector during rebuild: Port #",  //0x2C
-	"Encountered bad sector during rebuild: Port #" //0x2D
+	"Encountered bad sector during rebuild: Port #", //0x2D
+	"Replacement drive is too small: Port #" //0x2E
 };
 
-#define TW_AEN_STRING_MAX                      0x02E
+#define TW_AEN_STRING_MAX                      0x02F
+
+/* 
+   Sense key lookup table 
+   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
+*/
+static unsigned char tw_sense_table[][4] =
+{
+  /* Codes for newer firmware */
+                            // ATA Error                    SCSI Error
+  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
+  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
+  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
+  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
+  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
+  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
+  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+
+  /* Codes for older firmware */
+                            // 3ware Error                  SCSI Error
+  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
+  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
+  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
+};
 
 /* Control register bit definitions */
 #define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
@@ -110,7 +135,9 @@
 #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
 #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
 #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
 #define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
 
 /* Status register bit definitions */
 #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
@@ -130,7 +157,9 @@
 #define TW_STATUS_ALL_INTERRUPTS	       0x000F0000
 #define TW_STATUS_CLEARABLE_BITS	       0x00D00000
 #define TW_STATUS_EXPECTED_BITS		       0x00002000
-#define TW_STATUS_UNEXPECTED_BITS	       0x00F80000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
 
 /* RESPONSE QUEUE BIT DEFINITIONS */
 #define TW_RESPONSE_ID_MASK		       0x00000FF0
@@ -174,7 +203,8 @@
 #define TW_AEN_SBUF_FAIL         0x0024
 
 /* Misc defines */
-#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
+#define TW_ALIGNMENT_6000                     64 /* 64 bytes */
+#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
 #define TW_MAX_UNITS			      16
 #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
 #define TW_INIT_MESSAGE_CREDITS		      0x100
@@ -190,7 +220,7 @@
 #define TW_MAX_PCI_BUSES		      255
 #define TW_MAX_RESET_TRIES		      3
 #define TW_UNIT_INFORMATION_TABLE_BASE	      0x300
-#define TW_MAX_CMDS_PER_LUN		      (TW_Q_LENGTH-2)/TW_MAX_UNITS
+#define TW_MAX_CMDS_PER_LUN		      255
 #define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
 #define TW_IOCTL                              0x80
 #define TW_MAX_AEN_TRIES                      100
@@ -201,6 +231,8 @@
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
 #define TW_MAX_CDB_LEN                        16
+#define TW_ISR_DONT_COMPLETE                  2
+#define TW_ISR_DONT_RESULT                    3
 
 /* Macros */
 #define TW_STATUS_ERRORS(x) \
@@ -386,8 +418,9 @@
 	unsigned short		aen_queue[TW_Q_LENGTH];
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
-	long			flags; /* long req'd for set_bit --RR */
+	volatile long		flags; /* long req'd for set_bit --RR */
 	char			*ioctl_data[TW_Q_LENGTH];
+	int			reset_print;
 } TW_Device_Extension;
 
 /* Function prototypes */
@@ -397,12 +430,13 @@
 int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
 int tw_check_bits(u32 status_reg_value);
 int tw_check_errors(TW_Device_Extension *tw_dev);
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev);
 void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
 void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
-void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit);
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host);
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
 void tw_disable_interrupts(TW_Device_Extension *tw_dev);
-int tw_empty_response_que(TW_Device_Extension *tw_dev);
+void tw_empty_response_que(TW_Device_Extension *tw_dev);
 void tw_enable_interrupts(TW_Device_Extension *tw_dev);
 void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
 int tw_findcards(Scsi_Host_Template *tw_host);
@@ -462,7 +496,7 @@
 	reset : NULL,					\
 	slave_attach : NULL,				\
 	bios_param : tw_scsi_biosparam,			\
-	can_queue : TW_Q_LENGTH,			\
+	can_queue : TW_Q_LENGTH-1,			\
 	this_id: -1,					\
 	sg_tablesize : TW_MAX_SGL_LENGTH,		\
 	cmd_per_lun: TW_MAX_CMDS_PER_LUN,		\
diff -urN linux-2.4.19-pre4/drivers/scsi/gdth_proc.c linux-2.4.19-pre5/drivers/scsi/gdth_proc.c
--- linux-2.4.19-pre4/drivers/scsi/gdth_proc.c	Fri Sep  7 09:28:37 2001
+++ linux-2.4.19-pre5/drivers/scsi/gdth_proc.c	Fri Mar 29 14:49:47 2002
@@ -1464,7 +1464,7 @@
             timer_table[SCSI_TIMER].expires = jiffies + timeout;
             timer_active |= 1 << SCSI_TIMER;
         } else {
-            if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
+            if (time_before(jiffies + timeout, timer_table[SCSI_TIMER].expires))
                 timer_table[SCSI_TIMER].expires = jiffies + timeout;
         }
     }
diff -urN linux-2.4.19-pre4/drivers/scsi/qlogicfas.c linux-2.4.19-pre5/drivers/scsi/qlogicfas.c
--- linux-2.4.19-pre4/drivers/scsi/qlogicfas.c	Thu Oct 25 13:53:51 2001
+++ linux-2.4.19-pre5/drivers/scsi/qlogicfas.c	Fri Mar 29 14:49:47 2002
@@ -271,11 +271,11 @@
 int	i,k;
 	k = 0;
 	i = jiffies + WATCHDOG;
-	while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) {
+	while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) {
 		barrier();
 		cpu_relax();
 	}
-	if (i <= jiffies)
+	if (time_after_eq(jiffies, i))
 		return (DID_TIME_OUT);
 	if (qabort)
 		return (qabort == 1 ? DID_ABORT : DID_RESET);
@@ -405,8 +405,8 @@
 	}
 /*** Enter Status (and Message In) Phase ***/
 	k = jiffies + WATCHDOG;
-	while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));	/* wait for status phase */
-	if ( k <= jiffies ) {
+	while ( time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6));	/* wait for status phase */
+	if ( time_after_eq(jiffies, k) ) {
 		ql_zap();
 		return (DID_TIME_OUT << 16);
 	}
diff -urN linux-2.4.19-pre4/drivers/scsi/qlogicfc.c linux-2.4.19-pre5/drivers/scsi/qlogicfc.c
--- linux-2.4.19-pre4/drivers/scsi/qlogicfc.c	Thu Oct 25 13:53:51 2001
+++ linux-2.4.19-pre5/drivers/scsi/qlogicfc.c	Fri Mar 29 14:49:47 2002
@@ -803,7 +803,7 @@
 			outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
 			isp2x00_enable_irqs(host);
 			/* wait for the loop to come up */
-			for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) {
+			for (wait_time = jiffies + 10 * HZ; time_before(jiffies, wait_time) && hostdata->adapter_state == AS_LOOP_DOWN;) {
 			        barrier();
 				cpu_relax();
 			}
@@ -820,7 +820,7 @@
 	   some time before recognizing it is attached to a fabric */
 
 #if ISP2x00_FABRIC
-	for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) {
+	for (wait_time = jiffies + 5 * HZ; time_before(jiffies, wait_time);) {
 		barrier();
 		cpu_relax();
 	}
diff -urN linux-2.4.19-pre4/drivers/scsi/scsi_scan.c linux-2.4.19-pre5/drivers/scsi/scsi_scan.c
--- linux-2.4.19-pre4/drivers/scsi/scsi_scan.c	Fri Mar 29 14:49:11 2002
+++ linux-2.4.19-pre5/drivers/scsi/scsi_scan.c	Fri Mar 29 14:49:48 2002
@@ -155,7 +155,8 @@
 	{"DELL", "PV660F   PSEUDO",   "*", BLIST_SPARSELUN},
 	{"DELL", "PSEUDO DEVICE .",   "*", BLIST_SPARSELUN}, // Dell PV 530F
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN}, // Dell PV 530F
-	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN},     // Chaparral G7324 RAID
 	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
@@ -167,6 +168,8 @@
 	{"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
 	{"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
 	{"COMPAQ", "MSA1000", "*", BLIST_FORCELUN},
+	{"HP", "C1557A", "*", BLIST_FORCELUN},
+	{"IBM", "AuSaV1S2", "*", BLIST_FORCELUN},
 
 	/*
 	 * Must be at end of list...
diff -urN linux-2.4.19-pre4/drivers/scsi/sg.c linux-2.4.19-pre5/drivers/scsi/sg.c
--- linux-2.4.19-pre4/drivers/scsi/sg.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre5/drivers/scsi/sg.c	Fri Mar 29 14:49:48 2002
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char sg_version_str[] = "Version: 3.1.22 (20011208)";
+ static char sg_version_str[] = "Version: 3.1.23 (20020318)";
 #endif
- static int sg_version_num = 30122; /* 2 digits for each component */
+ static int sg_version_num = 30123; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -287,7 +287,7 @@
 
     if (flags & O_EXCL) {
         if (O_RDONLY == (flags & O_ACCMODE))  {
-            retval = -EACCES;   /* Can't lock it with read only access */
+            retval = -EPERM;   /* Can't lock it with read only access */
 	    goto error_out;
 	}
 	if (sdp->headfp && (flags & O_NONBLOCK))
@@ -580,7 +580,7 @@
     hp->iovec_count = 0;
     hp->mx_sb_len = 0;
     if (input_size > 0)
-	hp->dxfer_direction = ((old_hdr.reply_len - SZ_SG_HEADER) > 0) ?
+	hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
 			      SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
     else
 	hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
@@ -649,7 +649,7 @@
     if (read_only &&
 	(! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
 	sg_remove_request(sfp, srp);
-	return -EACCES;
+	return -EPERM;
     }
     k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
     if (k < 0) return k;
@@ -981,7 +981,7 @@
 
 	    copy_from_user(&opcode, siocp->data, 1);
 	    if (! sg_allow_access(opcode, sdp->device->type))
-		return -EACCES;
+		return -EPERM;
 	}
         return scsi_ioctl_send_command(sdp->device, (void *)arg);
     case SG_SET_DEBUG:
@@ -998,7 +998,7 @@
         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
     default:
 	if (read_only)
-            return -EACCES; /* don't know so take safe approach */
+            return -EPERM; /* don't know so take safe approach */
         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
     }
 }
@@ -2632,9 +2632,9 @@
     }
 }
 
-static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY,
-READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
-MODE_SENSE, MODE_SENSE_10};
+static unsigned char allow_ops[] = {TEST_UNIT_READY, REQUEST_SENSE,
+INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
+MODE_SENSE, MODE_SENSE_10, LOG_SENSE};
 
 static int sg_allow_access(unsigned char opcode, char dev_type)
 {
@@ -3036,17 +3036,28 @@
 				 int size, int * eof, void * data)
 { SG_PROC_READ_FN(sg_proc_hoststrs_info); }
 
+#define SG_MAX_HOST_STR_LEN 256
+
 static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin,
 				 off_t offset, int size)
 {
     struct Scsi_Host * shp;
     int k;
+    char buff[SG_MAX_HOST_STR_LEN];
+    char * cp;
 
     for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
     	for ( ; k < shp->host_no; ++k)
 	    PRINT_PROC("<no active host>\n");
-	PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) :
-		    (shp->hostt->name ? shp->hostt->name : "<no name>"));
+	strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) :
+		    (shp->hostt->name ? shp->hostt->name : "<no name>"),
+		SG_MAX_HOST_STR_LEN);
+	buff[SG_MAX_HOST_STR_LEN - 1] = '\0';
+	for (cp = buff; *cp; ++cp) {
+	    if ('\n' == *cp)
+		*cp = ' '; /* suppress imbedded newlines */
+	}
+	PRINT_PROC("%s\n", buff);
     }
     return 1;
 }
diff -urN linux-2.4.19-pre4/drivers/sound/ac97_codec.c linux-2.4.19-pre5/drivers/sound/ac97_codec.c
--- linux-2.4.19-pre4/drivers/sound/ac97_codec.c	Mon Nov 12 10:02:54 2001
+++ linux-2.4.19-pre5/drivers/sound/ac97_codec.c	Fri Mar 29 14:49:48 2002
@@ -105,7 +105,9 @@
 	{0x41445340, "Analog Devices AD1881",	&null_ops},
 	{0x41445348, "Analog Devices AD1881A",	&null_ops},
 	{0x41445360, "Analog Devices AD1885",	&default_ops},
+	{0x41445361, "Analog Devices AD1886",	&default_ops},
 	{0x41445460, "Analog Devices AD1885",	&default_ops},
+	{0x41445461, "Analog Devices AD1886",	&default_ops},
 	{0x414B4D00, "Asahi Kasei AK4540",	&null_ops},
 	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
 	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
diff -urN linux-2.4.19-pre4/drivers/sound/rme96xx.c linux-2.4.19-pre5/drivers/sound/rme96xx.c
--- linux-2.4.19-pre4/drivers/sound/rme96xx.c	Thu Oct 25 13:53:52 2001
+++ linux-2.4.19-pre5/drivers/sound/rme96xx.c	Fri Mar 29 14:49:50 2002
@@ -2,14 +2,23 @@
    with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
    based on es1370.c
 
-
-
    *  10 Jan 2001: 0.1 initial version
    *  19 Jan 2001: 0.2 fixed bug in select()
    *  27 Apr 2001: 0.3 more than one card usable
    *  11 May 2001: 0.4 fixed for SMP, included into kernel source tree
    *  17 May 2001: 0.5 draining code didn't work on new cards
    *  18 May 2001: 0.6 remove synchronize_irq() call 
+   *  17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards
+   *   2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!)
+                       Marcus Meissner <Marcus.Meissner@caldera.de>
+
+		       Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
+		       HP20020108 fixed handling of "large" read()
+		       HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
+		       HP20020118 made mixer ioctl and handling of devices>1 more safe
+		       HP20020201 fixed handling of "large" read() properly
+		       added REV 1.5 S/P-DIF receiver support
+		       SNDCTL_DSP_SPEED now returns the actual speed
 
 TODO:
    - test more than one card --- done
@@ -19,15 +28,18 @@
    - mixer mmap interface
    - mixer ioctl
    - get rid of noise upon first open (why ??)
-   - allow multiple open(at least for read)
+   - allow multiple open (at least for read)
    - allow multiple open for non overlapping regions
    - recheck the multiple devices part (offsets of different devices, etc)
    - do decent draining in _release --- done
    - SMP support
+   - what about using fragstotal>2 for small fragsize? (HP20020118)
+   - add support for AFMT_S32_LE
 */
 
+
 #ifndef RMEVERSION
-#define RMEVERSION "0.6"
+#define RMEVERSION "0.8"
 #endif
 
 #include <linux/version.h>
@@ -54,7 +66,7 @@
 
 MODULE_AUTHOR("Guenter Geiger, geiger@debian.org");
 MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver");
-MODULE_LICENSE("GPL");
+/*MODULE_LICENSE("GPL");*/
 
 
 #ifdef DEBUG
@@ -125,48 +137,60 @@
 
 #define RME96xx_tc_busy      0x0100000 /* 1=time-code copy in progress (960ms) */
 #define RME96xx_tc_out       0x0200000 /* time-code out bit */
-#define RME96xx_F_0          0x0400000 /*  000=64kHz, 100=88.2kHz, 011=96kHz  */
-#define RME96xx_F_1          0x0800000 /*  111=32kHz, 110=44.1kHz, 101=48kHz, */
+#define RME96xx_F_0          0x0400000 /*  000=64kHz, 100=88.2kHz, 011=96kHz */
+#define RME96xx_F_1          0x0800000 /*  111=32kHz, 110=44.1kHz, 101=48kHz */
 
-#define RME96xx_F_2          0x1000000 /*  od external Crystal Chip if ERF=1*/
+#define RME96xx_F_2          0x1000000 /*  001=Rev 1.5+ external Crystal Chip */
 #define RME96xx_ERF          0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/
 #define RME96xx_buffer_id    0x4000000 /* toggles by each interrupt on rec/play */
 #define RME96xx_tc_valid     0x8000000 /* 1 = a signal is detected on time-code input */
+#define RME96xx_SPDIF_READ  0x10000000 /* byte available from Rev 1.5+ SPDIF interface */
 
 /* Status Register Fields */
 
 #define RME96xx_lock            (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2)
-#define RME96xx_buf_pos          0x000FFC0 
 #define RME96xx_sync            (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2)
 #define RME96xx_F               (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2)
+#define rme96xx_decode_spdif_rate(x) ((x)>>22)
 
+/* Bit 6..15 : h/w buffer pointer */
+#define RME96xx_buf_pos          0x000FFC0 
+/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
+   Rev G EEPROMS and Rev 1.5 cards or later.
+*/ 
+#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos))
 
 
 /* Control-Register: */			    
 /*--------------------------------------------------------------------------------*/
 
-#define RME96xx_start_bit	   0x0001    /* start record/play */
-#define RME96xx_latency0	   0x0002    /* Bit 0 -  Buffer size or latency */
-#define RME96xx_latency1	   0x0004    /* Bit 1 - Buffer size or latency */
-#define RME96xx_latency2	   0x0008    /* Bit 2 - Buffer size or latency */
-
-#define RME96xx_Master		   0x0010   /* Clock Mode Master=1,Slave/Auto=0 */
-#define RME96xx_IE		   0x0020   /* Interupt Enable */
-#define RME96xx_freq		   0x0040   /* samplerate 0=44.1/88.2, 1=48/96 kHz*/
-
-
-#define RME96xx_DS                 0x0100   /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */
-#define RME96xx_PRO		   0x0200    /* spdif 0=consumer, 1=professional Mode*/
-#define RME96xx_EMP		   0x0400    /* spdif Emphasis 0=None, 1=ON */
-#define RME96xx_Dolby		   0x0800    /* spdif Non-audio bit 1=set, 0=unset */
-
-#define RME96xx_opt_out	           0x1000  /* Use 1st optical OUT as SPDIF: 1=yes,0=no */
-#define RME96xx_wsel               0x2000  /* use Wordclock as sync (overwrites master)*/
-#define RME96xx_inp_0              0x4000  /* SPDIF-IN: 00=optical (ADAT1),     */
-#define RME96xx_inp_1              0x8000  /* 01=koaxial (Cinch), 10=Internal CDROM*/
-
-#define RME96xx_SyncRef0           0x10000  /* preferred sync-source in autosync */
-#define RME96xx_SyncRef1           0x20000  /* 00=ADAT1,01=ADAT2,10=ADAT3,11=SPDIF */
+#define RME96xx_start_bit	0x0001 /* start record/play */
+#define RME96xx_latency0	0x0002 /* Buffer size / latency */
+#define RME96xx_latency1	0x0004 /*   buffersize = 512Bytes * 2^n */
+#define RME96xx_latency2	0x0008 /*   0=64samples ... 7=8192samples */
+
+#define RME96xx_Master		0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */
+#define RME96xx_IE		0x0020 /* Interupt Enable */
+#define RME96xx_freq		0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/
+#define RME96xx_freq1		0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */
+#define RME96xx_DS              0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */
+#define RME96xx_PRO		0x0200 /* SPDIF-OUT 0=consumer, 1=professional */
+#define RME96xx_EMP		0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */
+#define RME96xx_Dolby		0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */
+
+#define RME96xx_opt_out	        0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */
+#define RME96xx_wsel            0x2000 /* use Wordclock as sync (overwrites master) */
+#define RME96xx_inp_0           0x4000 /* SPDIF-IN 00=optical (ADAT1), */
+#define RME96xx_inp_1           0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */
+
+#define RME96xx_SyncRef0       0x10000 /* preferred sync-source in autosync */
+#define RME96xx_SyncRef1       0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
+
+#define RME96xx_SPDIF_RESET    (1<<18) /* Rev 1.5+: h/w SPDIF receiver */
+#define RME96xx_SPDIF_SELECT   (1<<19)
+#define RME96xx_SPDIF_CLOCK    (1<<20)
+#define RME96xx_SPDIF_WRITE    (1<<21)
+#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */
 
 
 #define RME96xx_ctrl_init            (RME96xx_latency0 |\
@@ -174,13 +198,14 @@
                                      RME96xx_inp_1)
                               
 
-
 /* Control register fields and shortcuts */
 
 #define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2)
 #define RME96xx_inp         (RME96xx_inp_0|RME96xx_inp_1)
 #define RME96xx_SyncRef    (RME96xx_SyncRef0|RME96xx_SyncRef1)
-/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit0 */
+#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL)
+
+/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1  (??? HP20020201) */
 
 #define RME96xx_SET_LATENCY(x)   (((x)&0x7)<<1)
 #define RME96xx_GET_LATENCY(x)   (((x)>>1)&0x7)
@@ -205,8 +230,10 @@
 
 
 #define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */
+#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */
 
 #define RME_MESS "rme96xx:"
+
 /*------------------------------------------------------------------------ 
                   Types, struct and function declarations 
  ------------------------------------------------------------------------*/
@@ -253,8 +280,10 @@
 
 	u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
 
-	int open_count;
+	int hw_rev;             /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
+	char *card_name;	/* hammerfall or hammerfall light names */
 
+	int open_count;         /* unused ???   HP20020201 */
 
 	int rate;
 	int latency;
@@ -318,6 +347,181 @@
 
 }
 
+inline int rme96xx_get_sample_rate_status(rme96xx_info* s)
+{
+	int val;
+	u32 status;
+	status = readl(s->iobase + RME96xx_status_register);
+	val = (status & RME96xx_fs48) ? 48000 : 44100;
+	if (status & RME96xx_DS_rd)
+		val *= 2;
+	return val;
+}
+
+inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s)
+{
+	int val;
+	val = (s->control_register & RME96xx_freq) ? 48000 : 44100;
+	if (s->control_register & RME96xx_DS)
+		val *= 2;
+	return val;
+}
+
+
+/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver   HP 20020201 */
+
+static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff)
+{
+	if (onoff) 
+		s->control_register |= mask;
+	else 
+		s->control_register &= ~mask;
+		
+	writel(s->control_register,s->iobase + RME96xx_control_register);
+}
+
+static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val)
+{
+	long mask;
+	long i;
+
+	for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
+		if (val & mask)
+			rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1);
+		else 
+			rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0);
+
+		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
+		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
+	}
+}
+
+static int rme96xx_spdif_read_byte (rme96xx_info* s)
+{
+	long mask;
+	long val;
+	long i;
+
+	val = 0;
+
+	for (i = 0, mask = 0x80;  i < 8; i++, mask >>= 1) {
+		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
+		if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ)
+			val |= mask;
+		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
+	}
+
+	return val;
+}
+
+static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data)
+{
+	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
+	rme96xx_spdif_write_byte (s, 0x20);
+	rme96xx_spdif_write_byte (s, address);
+	rme96xx_spdif_write_byte (s, data);
+	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
+}
+
+
+static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address)
+{
+	int ret;
+
+	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
+	rme96xx_spdif_write_byte (s, 0x20);
+	rme96xx_spdif_write_byte (s, address);
+	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
+	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
+
+	rme96xx_spdif_write_byte (s, 0x21);
+	ret = rme96xx_spdif_read_byte (s);
+	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
+
+	return ret;
+}
+
+static void rme96xx_initialize_spdif_receiver (rme96xx_info* s)
+{
+	/* XXX what unsets this ? */
+	/* no idea ???   HP 20020201 */
+
+	s->control_register |= RME96xx_SPDIF_RESET;
+
+	rme96xx_write_spdif_codec (s, 4, 0x40);
+	rme96xx_write_spdif_codec (s, 17, 0x13);
+	rme96xx_write_spdif_codec (s, 6, 0x02);
+}
+
+static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate)
+{
+	unsigned int rate_bits;
+
+	*spdifrate = 0x1;
+	if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) {
+		return -1;	/* error condition */
+	}
+	
+	if (s->hw_rev == 15) {
+
+		int x, y, ret;
+		
+		x = rme96xx_spdif_read_codec (s, 30);
+
+		if (x != 0) 
+			y = 48000 * 64 / x;
+		else
+			y = 0;
+
+		if      (y > 30400 && y < 33600)  {ret = 32000; *spdifrate = 0x7;}
+		else if (y > 41900 && y < 46000)  {ret = 44100; *spdifrate = 0x6;}
+		else if (y > 46000 && y < 50400)  {ret = 48000; *spdifrate = 0x5;}
+		else if (y > 60800 && y < 67200)  {ret = 64000; *spdifrate = 0x0;}
+		else if (y > 83700 && y < 92000)  {ret = 88200; *spdifrate = 0x4;}
+		else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;}
+		else                              {ret = 0; *spdifrate = 0x1;}
+		return ret;
+	}
+
+	rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F;
+
+	switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) {
+	case 0x7:
+		return 32000;
+		break;
+
+	case 0x6:
+		return 44100;
+		break;
+
+	case 0x5:
+		return 48000;
+		break;
+
+	case 0x4:
+		return 88200;
+		break;
+
+	case 0x3:
+		return 96000;
+		break;
+
+	case 0x0:
+		return 64000;
+		break;
+
+	default:
+		/* was an ALSA warning ...
+		  snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n",
+		  s->card_name, rate_bits);
+		*/
+		return 0;
+		break;
+	}
+}
+
+/* end of code from ALSA card-rme9652.c */
+
 
 
 /* the hwbuf in the status register seems to have some jitter, to get rid of
@@ -656,6 +860,9 @@
 int rme96xx_init(rme96xx_info* s)
 {
 	int i;
+	int status;
+	unsigned short rev;
+
 	DBG(printk(__FUNCTION__"\n"));
 	numcards++;
 
@@ -688,6 +895,56 @@
 		rme96xx_dmabuf_init(s,dma,2*i,2*i);
 	}
 
+	/* code from ALSA card-rme9652.c   HP 20020201 */
+        /* Determine the h/w rev level of the card. This seems like
+	   a particularly kludgy way to encode it, but its what RME
+	   chose to do, so we follow them ...
+	*/
+
+	status = readl(s->iobase + RME96xx_status_register);
+	if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) {
+		s->hw_rev = 15;
+	} else {
+		s->hw_rev = 11;
+	}
+
+	/* Differentiate between the standard Hammerfall, and the
+	   "Light", which does not have the expansion board. This
+	   method comes from information received from Mathhias
+	   Clausen at RME. Display the EEPROM and h/w revID where
+	   relevant.  
+	*/
+
+	pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev);
+	switch (rev & 0xff) {
+	case 8: /* original eprom */
+		if (s->hw_rev == 15) {
+			s->card_name = "RME Digi9636 (Rev 1.5)";
+		} else {
+			s->card_name = "RME Digi9636";
+		}
+		break;
+	case 9: /* W36_G EPROM */
+		s->card_name = "RME Digi9636 (Rev G)";
+		break;
+	case 4: /* W52_G EPROM */
+		s->card_name = "RME Digi9652 (Rev G)";
+		break;
+	default:
+	case 3: /* original eprom */
+		if (s->hw_rev == 15) {
+			s->card_name = "RME Digi9652 (Rev 1.5)";
+		} else {
+			s->card_name = "RME Digi9652";
+		}
+		break;
+	}
+
+	printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev); 
+
+	if (s->hw_rev == 15)
+		rme96xx_initialize_spdif_receiver (s);
+
 	s->started = 0;
 	rme96xx_setlatency(s,7);
 
@@ -728,7 +985,7 @@
 
 	if (pci_enable_device(pcidev))
 		goto err_irq;
-	if (request_irq(s->irq, rme96xx_interrupt, SA_SHIRQ, "es1370", s)) {
+	if (request_irq(s->irq, rme96xx_interrupt, SA_SHIRQ, "rme96xx", s)) {
 		printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq);
 		goto err_irq;
 	}
@@ -825,6 +1082,7 @@
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
 	printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n");
+	devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
 	printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
         numcards = 0;
 	return pci_module_init(&rme96xx_driver);
@@ -848,13 +1106,11 @@
 ---------------------------------------------------------------------------*/
 
 #define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED)
+/* AFTM_U8 is not (yet?) supported ...  HP20020201 */
 
-
-static int rme96xx_ioctl(struct inode *in, struct file *file, 
-						unsigned int cmd, unsigned long arg)
+static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg)
 {
 
-
 	struct dmabuf * dma = (struct dmabuf *)file->private_data; 
 	rme96xx_info *s = dma->s;
 	unsigned long flags;
@@ -907,14 +1163,23 @@
 			case 96000: 
 				rme96xx_set_ctrl(s,RME96xx_freq);
 				break;
+			/* just report current rate as default
+			   e.g. use 0 to "select" current digital input rate
 			default:
 				rme96xx_unset_ctrl(s,RME96xx_freq);
 				val = 44100;
+			*/
 			}
 			if (val > 50000)
 				rme96xx_set_ctrl(s,RME96xx_DS);
 			else
 				rme96xx_unset_ctrl(s,RME96xx_DS);
+			/* set val to actual value  HP 20020201 */
+			/* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */
+			if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel))
+				val = rme96xx_get_sample_rate_ctrl(s);
+			else
+				val = rme96xx_get_sample_rate_status(s);
 			s->rate = val;
 			spin_unlock_irqrestore(&s->lock, flags);
 		}
@@ -1131,6 +1396,8 @@
 		return 0;
 
         case SOUND_PCM_READ_RATE:
+		/* HP20020201 */
+		s->rate = rme96xx_get_sample_rate_status(s);
 		return put_user(s->rate, (int *)arg);
 
         case SOUND_PCM_READ_CHANNELS:
@@ -1164,28 +1431,29 @@
 {
 	int minor = MINOR(in->i_rdev);
 	struct list_head *list;
-	int devnum = ((minor-3)/16) % devices; /* default = 0 */
+	int devnum;
 	rme96xx_info *s;
 	struct dmabuf* dma;
 	DECLARE_WAITQUEUE(wait, current); 
 
 	DBG(printk("device num %d open\n",devnum));
 
-/* ??? */
 	for (list = devs.next; ; list = list->next) {
 		if (list == &devs)
 			return -ENODEV;
 		s = list_entry(list, rme96xx_info, devs);
-		if (!((s->dspnum[devnum] ^ minor) & ~0xf)) 
+		for (devnum=0; devnum<devices; devnum++)
+			if (!((s->dspnum[devnum] ^ minor) & ~0xf)) 
+				break;
+		if (devnum<devices)
 			break;
 	}
        	VALIDATE_STATE(s);
-/* ??? */
 
 	dma = &s->dma[devnum];
 	f->private_data = dma;
 	/* wait for device to become free */
-	down(&s->dma[devnum].open_sem);
+	down(&dma->open_sem);
 	while (dma->open_mode & f->f_mode) {
 		if (f->f_flags & O_NONBLOCK) {
 			up(&dma->open_sem);
@@ -1204,11 +1472,11 @@
 
 	COMM                ("hardware open")
 
-	if (!s->dma[devnum].opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset);
+	if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset);
 
-	s->dma[devnum].open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
-	s->dma[devnum].opened = 1;
-	up(&s->dma[devnum].open_sem);
+	dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
+	dma->opened = 1;
+	up(&dma->open_sem);
 
 	DBG(printk("device num %d open finished\n",devnum));
 	return 0;
@@ -1217,7 +1485,7 @@
 static int rme96xx_release(struct inode *in, struct file *file)
 {
 	struct dmabuf * dma = (struct dmabuf*) file->private_data;
-	int hwp;
+	/* int hwp;  ... was unused   HP20020201 */
 	DBG(printk(__FUNCTION__"\n"));
 
 	COMM          ("draining")
@@ -1246,8 +1514,7 @@
 }
 
 
-static ssize_t rme96xx_write(struct file *file, const char *buffer, 
-									  size_t count, loff_t *ppos)
+static ssize_t rme96xx_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct dmabuf *dma = (struct dmabuf *)file->private_data;
 	ssize_t ret = 0;
@@ -1269,7 +1536,7 @@
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
 
-	if (! (dma->open_mode  & FMODE_WRITE))
+	if (! (dma->open_mode & FMODE_WRITE))
                 return -ENXIO;
 
 	if (!dma->s->started) rme96xx_startcard(dma->s,exact);
@@ -1281,7 +1548,6 @@
 		dma->readptr = hwp;
 		dma->writeptr = hwp;
 		dma->started = 1;
-		COMM          ("first write done")
 	}
 
   	while (count > 0) {
@@ -1316,11 +1582,11 @@
 	return ret;
 }
 
-static ssize_t rme96xx_read(struct file *file, char *buffer,size_t count, loff_t *ppos)
+static ssize_t rme96xx_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 { 
 	struct dmabuf *dma = (struct dmabuf *)file->private_data;
 	ssize_t ret = 0;
-	int cnt;
+	int cnt; /* number of bytes from "buffer" that will/can be used */
 	int hop = count/dma->inchannels;
 	int hwp;
 	int exact = (file->f_flags & O_NONBLOCK); 
@@ -1341,9 +1607,6 @@
 	if (! (dma->open_mode  & FMODE_READ))
                 return -ENXIO;
 
-	if (count > ((dma->s->fragsize*dma->inchannels)>>dma->formatshift))
-	    return -EFAULT;
-
 	if (!dma->s->started) rme96xx_startcard(dma->s,exact);
 	hwp = rme96xx_gethwptr(dma->s,0);
 
@@ -1359,15 +1622,12 @@
 		cnt = rme96xx_getispace(dma,hwp);		
 		cnt>>=dma->formatshift;
 		cnt*=dma->inchannels;
-
 		if (cnt > count)
 			cnt = count;
 
 		if (cnt != 0) {
-		        
 			if (rme96xx_copytouser(dma,buffer,cnt,hop))
 				return ret ? ret : -EFAULT;
-			
 			count -= cnt;
 			buffer += cnt;
 			ret += cnt;
@@ -1382,6 +1642,7 @@
 			if (signal_pending(current))
 				return ret ? ret : -ERESTARTSYS;
 		}			
+
 		hwp = rme96xx_gethwptr(dma->s,exact);
 
 	}; /* count > 0 */
@@ -1500,7 +1761,7 @@
 		if (list == &devs)
 			return -ENODEV;
 		s = list_entry(list, rme96xx_info, devs);
-		if (s->mixer== minor)
+		if (s->mixer == minor)
 			break;
 	}
        	VALIDATE_STATE(s);
@@ -1514,19 +1775,34 @@
 {
 	rme96xx_info *s = (rme96xx_info *)file->private_data;
 	u32 status;
+	int spdifrate;
 
 	status = readl(s->iobase + RME96xx_status_register);
+	/* hack to convert rev 1.5 SPDIF rate to "crystalrate" format   HP 20020201 */
+	rme96xx_spdif_sample_rate(s,&spdifrate);
+	status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F);
 
 	VALIDATE_STATE(s);
 	if (cmd == SOUND_MIXER_PRIVATE1) {
 		rme_mixer mixer;
 		copy_from_user(&mixer,(void*)arg,sizeof(mixer));
 		
-		if (file->f_mode & FMODE_WRITE) {
-		     s->dma[mixer.devnr].outoffset = mixer.o_offset;
-		     s->dma[mixer.devnr].inoffset = mixer.i_offset;
+		mixer.devnr &= RME96xx_MASK_DEVS;
+		if (mixer.devnr >= devices)
+			mixer.devnr = devices-1;
+		if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) {
+			/* modify only if device not open */
+			if (mixer.o_offset < 0)
+				mixer.o_offset = 0;
+			if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD)
+				mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1;
+			if (mixer.i_offset < 0)
+				mixer.i_offset = 0;
+			if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD)
+				mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1;
+			s->dma[mixer.devnr].outoffset = mixer.o_offset;
+			s->dma[mixer.devnr].inoffset = mixer.i_offset;
 		}
-
 		mixer.o_offset = s->dma[mixer.devnr].outoffset;
 		mixer.i_offset = s->dma[mixer.devnr].inoffset;
 
@@ -1536,14 +1812,15 @@
 		return put_user(status, (int *)arg);
 	}
 	if (cmd == SOUND_MIXER_PRIVATE3) {
-	     u32 control;
-	     copy_from_user(&control,(void*)arg,sizeof(control)); 
-	     if (file->f_mode & FMODE_WRITE) {
-		  s->control_register = control;
-		  writel(control,s->iobase + RME96xx_control_register);
-	     }
+		u32 control;
+		copy_from_user(&control,(void*)arg,sizeof(control)); 
+		if (file->f_mode & FMODE_WRITE) {
+			s->control_register &= ~RME96xx_mixer_allowed;
+			s->control_register |= control & RME96xx_mixer_allowed;
+			writel(control,s->iobase + RME96xx_control_register);
+		}
 
-	     return put_user(s->control_register, (int *)arg);
+		return put_user(s->control_register, (int *)arg);
 	}
 	return -1;
 }
diff -urN linux-2.4.19-pre4/drivers/sound/rme96xx.h linux-2.4.19-pre5/drivers/sound/rme96xx.h
--- linux-2.4.19-pre4/drivers/sound/rme96xx.h	Sun Aug 12 10:51:42 2001
+++ linux-2.4.19-pre5/drivers/sound/rme96xx.h	Fri Mar 29 14:49:50 2002
@@ -1,5 +1,12 @@
 /* (C) 2000 Guenter Geiger <geiger@debian.org>
    with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
+
+Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
+   HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
+   HP20020201 completed?
+
+A text/graphic control panel (rmectrl/xrmectrl) is available from
+   http://gige.xdv.org/pages/soft/pages/rme
 */
 
 
@@ -7,55 +14,65 @@
 #define AFMT_S32_BLOCKED 0x0000400
 #endif
 
+/* AFMT_S16_BLOCKED not yet supported */
 #ifndef AFMT_S16_BLOCKED 
 #define AFMT_S16_BLOCKED 0x0000800
 #endif
 
 
 typedef struct rme_status {
-     unsigned int irq:1;    /* high or low */
-     unsigned int lockmask:3;  /* ADAT1, ADAT2, ADAT3 */
-     unsigned int sr48:1;   /* current sample rate */
-     unsigned int wclock:1; /* wordclock used ? */
-     unsigned int bufpoint:10;
-
-     unsigned int syncmask:3;  /* ADAT1, ADAT2, ADAT3 */
-     unsigned int doublespeed:1;
-     unsigned int tc_busy:1;
-     unsigned int tc_out:1;
-     unsigned int crystalrate:3;
-     unsigned int spdif_error:1;
-     unsigned int bufid:1;
-     unsigned int tc_valid:1;     
+	unsigned int irq:1;
+	unsigned int lockmask:3;     /* ADAT input PLLs locked */
+	                             /*   100=ADAT1, 010=ADAT2, 001=ADAT3 */
+	unsigned int sr48:1;         /* sample rate: 0=44.1/88.2 1=48/96 kHz */
+	unsigned int wclock:1;       /* 1=wordclock used */
+	unsigned int bufpoint:10;
+	unsigned int syncmask:3;     /* ADAT input in sync with system clock */
+	                             /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
+	unsigned int doublespeed:1;  /* sample rate: 0=44.1/48 1=88.2/96 kHz */
+	unsigned int tc_busy:1;
+	unsigned int tc_out:1;
+	unsigned int crystalrate:3;  /* spdif input sample rate: */
+	                             /*   000=64kHz, 100=88.2kHz, 011=96kHz */
+	                             /*   111=32kHz, 110=44.1kHz, 101=48kHz */
+	unsigned int spdif_error:1;  /* 1=no spdif lock */
+	unsigned int bufid:1;
+	unsigned int tc_valid:1;     /* 1=timecode input detected */
+	unsigned int spdif_read:1;
 } rme_status_t;
 
 
+/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */
 typedef struct rme_control {
-     unsigned int start:1;
-     unsigned int latency:3;
-
-     unsigned int master:1;
-     unsigned int ie:1;
-     unsigned int sr48:1;
-     unsigned int spare:1;
-
-     unsigned int doublespeed:1;
-     unsigned int pro:1;
-     unsigned int emphasis:1;
-     unsigned int dolby:1;
-
-     unsigned int opt_out:1;
-     unsigned int wordclock:1;
-     unsigned int spdif_in:2;
-
-     unsigned int sync_ref:2;
+	unsigned int start:1;
+	unsigned int latency:3;      /* buffer size / latency [samples]: */
+	                             /*   0=64 ... 7=8192 */
+	unsigned int master:1;       /* W: clock mode: 1=master 0=slave/auto */
+	unsigned int ie:1;
+	unsigned int sr48:1;         /* samplerate 0=44.1/88.2, 1=48/96 kHz */
+	unsigned int spare:1;
+	unsigned int doublespeed:1;  /* double speed 0=44.1/48, 1=88.2/96 Khz */
+	unsigned int pro:1;          /* W: SPDIF-OUT 0=consumer, 1=professional */
+	unsigned int emphasis:1;     /* W: SPDIF-OUT emphasis 0=off, 1=on */
+	unsigned int dolby:1;        /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */
+	unsigned int opt_out:1;      /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */
+	unsigned int wordclock:1;    /* W: use Wordclock as sync (overwrites master) */
+        unsigned int spdif_in:2;     /* W: SPDIF-IN: */
+                                     /*    00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */
+	unsigned int sync_ref:2;     /* W: preferred sync-source in autosync */
+                                     /*    00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
+	unsigned int spdif_reset:1;
+	unsigned int spdif_select:1;
+	unsigned int spdif_clock:1;
+	unsigned int spdif_write:1;
+	unsigned int adat1_cd:1;     /* W: Rev 1.5+: if set, internal CD connector carries ADAT */
 } rme_ctrl_t;
 
 
 typedef struct _rme_mixer {
-     int i_offset;
-     int o_offset;
-     int devnr;
-     int spare[8];
+	int i_offset;
+	int o_offset;
+	int devnr;
+	int spare[8];
 } rme_mixer;
 
diff -urN linux-2.4.19-pre4/drivers/sound/trident.c linux-2.4.19-pre5/drivers/sound/trident.c
--- linux-2.4.19-pre4/drivers/sound/trident.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/sound/trident.c	Fri Mar 29 14:49:53 2002
@@ -3813,7 +3813,7 @@
 	pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff);
 	udelay(5000);
 
-	wCount = 200;
+	wCount = 2000;
 	while(wCount--) {
 		wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
 		if((wReg & 0x000f) == 0x000f)
diff -urN linux-2.4.19-pre4/drivers/sound/vwsnd.c linux-2.4.19-pre5/drivers/sound/vwsnd.c
--- linux-2.4.19-pre4/drivers/sound/vwsnd.c	Fri Nov  9 14:07:41 2001
+++ linux-2.4.19-pre5/drivers/sound/vwsnd.c	Fri Mar 29 14:49:54 2002
@@ -535,7 +535,7 @@
 {
 	unsigned long later = jiffies + 2;
 	while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY)
-		if (jiffies >= later)
+		if (time_after_eq(jiffies, later))
 			return -EBUSY;
 	return 0;
 }
@@ -1358,7 +1358,7 @@
 	later = jiffies + HZ / 2;	/* roughly half a second */
 	DBGDO(shut_up++);
 	while (ad1843_read_bits(lith, &ad1843_PDNO)) {
-		if (jiffies > later) {
+		if (time_after(jiffies, later)) {
 			printk(KERN_ERR
 			       "vwsnd audio: AD1843 won't power up\n");
 			return -EIO;
diff -urN linux-2.4.19-pre4/drivers/telephony/Config.in linux-2.4.19-pre5/drivers/telephony/Config.in
--- linux-2.4.19-pre4/drivers/telephony/Config.in	Fri Sep  7 09:28:37 2001
+++ linux-2.4.19-pre5/drivers/telephony/Config.in	Fri Mar 29 14:49:55 2002
@@ -6,5 +6,5 @@
 
 tristate 'Linux telephony support' CONFIG_PHONE
 dep_tristate 'QuickNet Internet LineJack/PhoneJack support' CONFIG_PHONE_IXJ $CONFIG_PHONE
-dep_tristate 'QuickNet Internet LineJack/PhoneJack PCMCIA support' CONFIG_PHONE_IXJ_PCMCIA $CONFIG_PHONE_IXJ
+dep_tristate 'QuickNet Internet LineJack/PhoneJack PCMCIA support' CONFIG_PHONE_IXJ_PCMCIA $CONFIG_PHONE_IXJ $CONFIG_PCMCIA
 endmenu
diff -urN linux-2.4.19-pre4/drivers/usb/devices.c linux-2.4.19-pre5/drivers/usb/devices.c
--- linux-2.4.19-pre4/drivers/usb/devices.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre5/drivers/usb/devices.c	Fri Mar 29 14:49:56 2002
@@ -105,8 +105,8 @@
   "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 static char *format_endpt =
-/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
-  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
+  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
 
 
 /*
@@ -166,24 +166,71 @@
 	return (clas_info[ix].class_name);
 }
 
-static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
-{
-	char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+static char *usb_dump_endpoint_descriptor (
+	int speed,
+	char *start,
+	char *end,
+	const struct usb_endpoint_descriptor *desc
+)
+{
+	char dir, unit, *type;
+	unsigned interval, in, bandwidth = 1;
 
 	if (start > end)
 		return start;
-	start += sprintf(start, format_endpt, desc->bEndpointAddress,
-			 (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL
-			 	? 'B' :			/* bidirectional */
-			 (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
-			 desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK],
-			 desc->wMaxPacketSize, desc->bInterval);
-	return start;
-}
+	in = (desc->bEndpointAddress & USB_DIR_IN);
+	dir = in ? 'I' : 'O';
+	if (speed == USB_SPEED_HIGH) {
+		switch (desc->wMaxPacketSize & (0x03 << 11)) {
+		case 1 << 11:	bandwidth = 2; break;
+		case 2 << 11:	bandwidth = 3; break;
+		}
+	}
 
-static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
-{
-	return usb_dump_endpoint_descriptor(start, end, endpoint);
+	/* this isn't checking for illegal values */
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		type = "Ctrl";
+		if (speed == USB_SPEED_HIGH) 	/* uframes per NAK */
+			interval = desc->bInterval;
+		else
+			interval = 0;
+		dir = 'B';			/* ctrl is bidirectional */
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		type = "Isoc";
+		interval = 1 << (desc->bInterval - 1);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		type = "Bulk";
+		if (speed == USB_SPEED_HIGH && !in)	/* uframes per NAK */
+			interval = desc->bInterval;
+		else
+			interval = 0;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		type = "Int.";
+		if (speed == USB_SPEED_HIGH) {
+			interval = 1 << (desc->bInterval - 1);
+		} else
+			interval = desc->bInterval;
+		break;
+	default:	/* "can't happen" */
+		return start;
+	}
+	interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000;
+	if (interval % 1000)
+		unit = 'u';
+	else {
+		unit = 'm';
+		interval /= 1000;
+	}
+
+	start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
+			 desc->bmAttributes, type,
+			 (desc->wMaxPacketSize & 0x07ff) * bandwidth,
+			 interval, unit);
+	return start;
 }
 
 static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
@@ -204,8 +251,13 @@
 	return start;
 }
 
-static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
-{
+static char *usb_dump_interface(
+	int speed,
+	char *start,
+	char *end,
+	const struct usb_interface *iface,
+	int setno
+) {
 	struct usb_interface_descriptor *desc = &iface->altsetting[setno];
 	int i;
 
@@ -213,7 +265,8 @@
 	for (i = 0; i < desc->bNumEndpoints; i++) {
 		if (start > end)
 			return start;
-		start = usb_dump_endpoint(start, end, desc->endpoint + i);
+		start = usb_dump_endpoint_descriptor(speed,
+				start, end, desc->endpoint + i);
 	}
 	return start;
 }
@@ -238,7 +291,13 @@
 	return start;
 }
 
-static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, int active)
+static char *usb_dump_config (
+	int speed,
+	char *start,
+	char *end,
+	const struct usb_config_descriptor *config,
+	int active
+)
 {
 	int i, j;
 	struct usb_interface *interface;
@@ -255,7 +314,8 @@
 		for (j = 0; j < interface->num_altsetting; j++) {
 			if (start > end)
 				return start;
-			start = usb_dump_interface(start, end, interface, j);
+			start = usb_dump_interface(speed,
+					start, end, interface, j);
 		}
 	}
 	return start;
@@ -336,8 +396,10 @@
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		if (start > end)
 			return start;
-		start = usb_dump_config(start, end, dev->config + i,
-					(dev->config + i) == dev->actconfig); /* active ? */
+		start = usb_dump_config(dev->speed,
+				start, end, dev->config + i,
+				/* active ? */
+				(dev->config + i) == dev->actconfig);
 	}
 	return start;
 }
@@ -429,12 +491,26 @@
 	 * count = device count at this level
 	 */
 	/* If this is the root hub, display the bandwidth information */
-	if (level == 0)
-		data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated,
-				FRAME_TIME_MAX_USECS_ALLOC,
-				(100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
-			         bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
-	
+ 	if (level == 0) {
+ 		int	max;
+ 
+ 		/* high speed reserves 80%, full/low reserves 90% */
+ 		if (usbdev->speed == USB_SPEED_HIGH)
+ 			max = 800;
+ 		else
+ 			max = FRAME_TIME_MAX_USECS_ALLOC;
+ 
+ 		/* report "average" periodic allocation over a microsecond.
+ 		 * the schedules are actually bursty, HCDs need to deal with
+ 		 * that and just compute/report this average.
+ 		 */
+ 		data_end += sprintf(data_end, format_bandwidth,
+ 				bus->bandwidth_allocated, max,
+ 				(100 * bus->bandwidth_allocated + max / 2)
+ 					/ max,
+ 			         bus->bandwidth_int_reqs,
+ 				 bus->bandwidth_isoc_reqs);
+ 	}
 	data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
 	
 	if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
diff -urN linux-2.4.19-pre4/drivers/usb/hid-core.c linux-2.4.19-pre5/drivers/usb/hid-core.c
--- linux-2.4.19-pre4/drivers/usb/hid-core.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre5/drivers/usb/hid-core.c	Fri Mar 29 14:49:56 2002
@@ -897,6 +897,9 @@
 	u8 data[len];
 	int read;
 
+	if (hid->quirks & HID_QUIRK_NOGET)
+		return;
+
 	if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) {
 		dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read);
 		return;
@@ -1076,16 +1079,25 @@
 #define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
 
+#define USB_VENDOR_ID_ATEN		0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
+#define USB_DEVICE_ID_ATEN_CS124U	0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
+	unsigned quirks;
 } hid_blacklist[] = {
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ 0, 0 }
 };
 
@@ -1094,13 +1106,17 @@
 	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
 	struct hid_descriptor *hdesc;
 	struct hid_device *hid;
-	unsigned rsize = 0;
+	unsigned quirks = 0, rsize = 0;
 	char *buf;
 	int n;
 
 	for (n = 0; hid_blacklist[n].idVendor; n++)
 		if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&
-			(hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;
+			(hid_blacklist[n].idProduct == dev->descriptor.idProduct))
+				quirks = hid_blacklist[n].quirks;
+
+	if (quirks & HID_QUIRK_IGNORE)
+		return NULL;
 
 	if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) && ((!interface->bNumEndpoints) ||
 		usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc))) {
@@ -1138,6 +1154,8 @@
 		}
 	}
 
+	hid->quirks = quirks;
+
 	for (n = 0; n < interface->bNumEndpoints; n++) {
 
 		struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];
diff -urN linux-2.4.19-pre4/drivers/usb/hid.h linux-2.4.19-pre5/drivers/usb/hid.h
--- linux-2.4.19-pre4/drivers/usb/hid.h	Tue Nov 13 17:45:27 2001
+++ linux-2.4.19-pre5/drivers/usb/hid.h	Fri Mar 29 14:49:56 2002
@@ -184,6 +184,8 @@
 
 #define HID_QUIRK_INVERT	0x01
 #define HID_QUIRK_NOTOUCH	0x02
+#define HID_QUIRK_IGNORE	0x04
+#define HID_QUIRK_NOGET		0x08
 
 /*
  * This is the global enviroment of the parser. This information is
diff -urN linux-2.4.19-pre4/drivers/usb/hpusbscsi.c linux-2.4.19-pre5/drivers/usb/hpusbscsi.c
--- linux-2.4.19-pre4/drivers/usb/hpusbscsi.c	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/hpusbscsi.c	Fri Mar 29 14:49:56 2002
@@ -120,6 +120,9 @@
 	if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl)))
 		goto err_out;
 
+	new->sense_command[0] = REQUEST_SENSE;
+	new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
+
 	/* adding to list for module unload */
 	list_add (&hpusbscsi_devices, &new->lh);
 
@@ -163,7 +166,6 @@
 	int result;
 
 	INIT_LIST_HEAD (&hpusbscsi_devices);
-	DEBUG ("Driver loaded\n");
 
 	if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) {
 		printk (KERN_ERR "hpusbscsi: driver registration failed\n");
@@ -371,6 +373,7 @@
 static void  control_interrupt_callback (struct urb *u)
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+	u8 scsi_state;
 
 DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
 	if(u->status < 0) {
@@ -378,10 +381,23 @@
                         handle_usb_error(hpusbscsi);
 		return;
 	}
-	hpusbscsi->srb->result &= SCSI_ERR_MASK;
-	hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte;
 
-	if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT)
+	scsi_state = hpusbscsi->scsi_state_byte;
+        if (hpusbscsi->state != HP_STATE_ERROR) {
+                hpusbscsi->srb->result &= SCSI_ERR_MASK;
+                hpusbscsi->srb->result |= scsi_state;
+        }
+
+	if (scsi_state == CHECK_CONDITION << 1) {
+		if (hpusbscsi->state == HP_STATE_WAIT) {
+			issue_request_sense(hpusbscsi);
+		} else {
+			/* we request sense after an eventual data transfer */
+			hpusbscsi->state = HP_STATE_ERROR;
+		}
+	}
+
+	if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1)
 		/* we do a callback to the scsi layer if and only if all data has been transfered */
 		hpusbscsi->scallback(hpusbscsi->srb);
 
@@ -396,6 +412,8 @@
 		hpusbscsi->state = HP_STATE_PREMATURE;
 	TRACE_STATE;
 		break;
+	case HP_STATE_ERROR:
+		break;
 	default:
 		printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
 	TRACE_STATE;
@@ -474,11 +492,16 @@
         DEBUG("Data transfer done\n");
 	TRACE_STATE;
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		if (u->status < 0)
+		if (u->status < 0) {
 			handle_usb_error(hpusbscsi);
-		else
-			hpusbscsi->state = HP_STATE_WAIT;
+		} else {
+			if (hpusbscsi->state != HP_STATE_ERROR) {
+				hpusbscsi->state = HP_STATE_WAIT;
+			} else {
+				issue_request_sense(hpusbscsi);
+			}
 		TRACE_STATE;
+		}
 	} else {
 		if (hpusbscsi->scallback != NULL)
 			hpusbscsi->scallback(hpusbscsi->srb);
@@ -541,8 +564,25 @@
 		handle_usb_error(hpusbscsi);
 		return;
 	}
-	if (hpusbscsi->state != HP_STATE_PREMATURE)
+	if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
 		hpusbscsi->state = HP_STATE_WORKING;
 }
 
+static void issue_request_sense (struct hpusbscsi *hpusbscsi)
+{
+	FILL_BULK_URB(
+		&hpusbscsi->dataurb,
+		hpusbscsi->dev,
+		usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
+		&hpusbscsi->sense_command,
+		SENSE_COMMAND_SIZE,
+		request_sense_callback,
+		hpusbscsi
+	);
+
+	hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
 
+	if (0 > usb_submit_urb(&hpusbscsi->dataurb)) {
+		handle_usb_error(hpusbscsi);
+	}
+}
diff -urN linux-2.4.19-pre4/drivers/usb/hpusbscsi.h linux-2.4.19-pre5/drivers/usb/hpusbscsi.h
--- linux-2.4.19-pre4/drivers/usb/hpusbscsi.h	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/hpusbscsi.h	Fri Mar 29 14:49:56 2002
@@ -4,9 +4,14 @@
 /* large parts based on or taken from code by John Fremlin and Matt Dharm */
 /* this file is licensed under the GPL */
 
+/* A big thanks to Jose for untiring testing */
+
 typedef void (*usb_urb_callback) (struct urb *);
 typedef void (*scsi_callback)(Scsi_Cmnd *);
 
+#define SENSE_COMMAND_SIZE 6
+#define HPUSBSCSI_SENSE_LENGTH 0x16
+
 struct hpusbscsi
 {
         struct list_head lh;
@@ -21,6 +26,7 @@
         int number;
        scsi_callback scallback;
        Scsi_Cmnd *srb;
+	u8 sense_command[SENSE_COMMAND_SIZE];
 
         int use_count;
         wait_queue_head_t pending;
@@ -57,6 +63,7 @@
 static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
 static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
 static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
+static void issue_request_sense (struct hpusbscsi *hpusbscsi);
 
 static Scsi_Host_Template hpusbscsi_scsi_host_template = {
 	name:           "hpusbscsi",
diff -urN linux-2.4.19-pre4/drivers/usb/hub.c linux-2.4.19-pre5/drivers/usb/hub.c
--- linux-2.4.19-pre4/drivers/usb/hub.c	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/hub.c	Fri Mar 29 14:49:56 2002
@@ -550,10 +550,6 @@
 		if (!(portstatus & USB_PORT_STAT_CONNECTION))
 			return 1;
 
-		/* Device went away? */
-		if (!(portstatus & USB_PORT_STAT_CONNECTION))
-			return 1;
-
 		/* bomb out completely if something weird happened */
 		if ((portchange & USB_PORT_STAT_C_CONNECTION))
 			return -1;
@@ -631,11 +627,11 @@
  * Not covered by the spec - but easy to deal with.
  *
  * This implementation uses 400ms minimum debounce timeout and checks
- * every 10ms for transient disconnects to restart the delay.
+ * every 100ms for transient disconnects to restart the delay.
  */
 
 #define HUB_DEBOUNCE_TIMEOUT	400
-#define HUB_DEBOUNCE_STEP	10
+#define HUB_DEBOUNCE_STEP	100
 
 /* return: -1 on error, 0 on success, 1 on disconnect.  */
 static int usb_hub_port_debounce(struct usb_device *hub, int port)
@@ -908,6 +904,7 @@
 	 */
 
 	daemonize();
+	reparent_to_init();
 
 	/* Setup a nice name */
 	strcpy(current->comm, "khubd");
diff -urN linux-2.4.19-pre4/drivers/usb/kaweth.c linux-2.4.19-pre5/drivers/usb/kaweth.c
--- linux-2.4.19-pre4/drivers/usb/kaweth.c	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/kaweth.c	Fri Mar 29 14:49:56 2002
@@ -123,6 +123,7 @@
 	{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ 
 	{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ 
 	{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
+	{ USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
 	{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ 
 	{ USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
 	{ USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
diff -urN linux-2.4.19-pre4/drivers/usb/pegasus.c linux-2.4.19-pre5/drivers/usb/pegasus.c
--- linux-2.4.19-pre4/drivers/usb/pegasus.c	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/pegasus.c	Fri Mar 29 14:49:56 2002
@@ -57,7 +57,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.25 (2002/03/06)"
+#define DRIVER_VERSION "v0.4.26 (2002/03/21)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -69,6 +69,7 @@
 static int loopback = 0;
 static int mii_mode = 1;
 static int multicast_filter_limit = 32;
+static DECLARE_MUTEX(gsem);
 
 static struct usb_eth_dev usb_dev_id[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags)	\
@@ -741,6 +742,7 @@
 	int	res;
 
 
+	down(&pegasus->sem);
 	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
@@ -759,12 +761,16 @@
 	pegasus->flags |= PEGASUS_RUNNING;
 	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
 		err("can't enable_net_traffic() - %d", res);
-		return -EIO;
+		res = -EIO;
+		goto exit;
 	}
 
 	set_carrier(net);
-
-	return 0;
+	res = 0;
+exit:
+	up(&pegasus->sem);
+	
+	return res;
 }
 
 
@@ -772,6 +778,7 @@
 {
 	pegasus_t	*pegasus = net->priv;
 
+	down(&pegasus->sem);
 	pegasus->flags &= ~PEGASUS_RUNNING;
 	netif_stop_queue( net );
 	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
@@ -783,7 +790,8 @@
 #ifdef	PEGASUS_USE_INTR
 	usb_unlink_urb( pegasus->intr_urb );
 #endif
-
+	up(&pegasus->sem);
+	
 	return 0;
 }
 
@@ -869,23 +877,33 @@
 {
 	__u16 *data = (__u16 *)&rq->ifr_data;
 	pegasus_t	*pegasus = net->priv;
+	int	res;
 
+	down(&pegasus->sem);
 	switch(cmd) {
 	case SIOCETHTOOL:
-		return pegasus_ethtool_ioctl(net, rq->ifr_data);
+		res = pegasus_ethtool_ioctl(net, rq->ifr_data);
+		break;
 	case SIOCDEVPRIVATE:
 		data[0] = pegasus->phy;
 	case SIOCDEVPRIVATE+1:
 		read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
-		return 0;
+		res = 0;
+		break;
 	case SIOCDEVPRIVATE+2:
-		if ( !capable(CAP_NET_ADMIN) )
+		if ( !capable(CAP_NET_ADMIN) ) {
+			up(&pegasus->sem);
 			return -EPERM;
+		}
 		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
-		return 0;
+		res = 0;
+		break;
 	default:
-		return -EOPNOTSUPP;
+		res = -EOPNOTSUPP;
 	}
+	up(&pegasus->sem);
+
+	return res;
 }
 
 
@@ -955,9 +973,10 @@
 		return NULL;
 	}
 
+	down(&gsem);
 	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
 		err("out of memory allocating device structure");
-		return NULL;
+		goto exit;
 	}
 
 	usb_inc_dev_use( dev );
@@ -968,20 +987,23 @@
 	pegasus->ctrl_urb = usb_alloc_urb(0);
 	if (!pegasus->ctrl_urb) {
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 	pegasus->rx_urb = usb_alloc_urb(0);
 	if (!pegasus->rx_urb) {
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 	pegasus->tx_urb = usb_alloc_urb(0);
 	if (!pegasus->tx_urb) {
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 	pegasus->intr_urb = usb_alloc_urb(0);
 	if (!pegasus->intr_urb) {
@@ -989,7 +1011,8 @@
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 
 	net = init_etherdev( NULL, 0 );
@@ -998,9 +1021,11 @@
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree( pegasus );
-		return	NULL;
+		pegasus = NULL;
+		goto exit;
 	}
-	
+
+	init_MUTEX(&pegasus->sem);
 	pegasus->usb = dev;
 	pegasus->net = net;
 	SET_MODULE_OWNER(net);
@@ -1028,7 +1053,7 @@
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
-		return NULL;
+		goto exit;
 	}
 
 	info( "%s: %s", net->name, usb_dev_id[dev_index].name );
@@ -1046,6 +1071,8 @@
 		pegasus->phy = 1;
 	}
 
+exit:
+	up(&gsem);
 	return pegasus;
 }
 
diff -urN linux-2.4.19-pre4/drivers/usb/pegasus.h linux-2.4.19-pre5/drivers/usb/pegasus.h
--- linux-2.4.19-pre4/drivers/usb/pegasus.h	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/pegasus.h	Fri Mar 29 14:49:56 2002
@@ -102,7 +102,7 @@
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
 	devrequest		dr;
 	wait_queue_head_t	ctrl_wait;
-	struct semaphore	ctrl_sem;
+	struct semaphore	sem;
 	unsigned char		ALIGN(rx_buff[PEGASUS_MAX_MTU]);
 	unsigned char		ALIGN(tx_buff[PEGASUS_MAX_MTU]);
 	unsigned char		ALIGN(intr_buff[8]);
diff -urN linux-2.4.19-pre4/drivers/usb/printer.c linux-2.4.19-pre5/drivers/usb/printer.c
--- linux-2.4.19-pre4/drivers/usb/printer.c	Tue Oct  9 15:15:02 2001
+++ linux-2.4.19-pre5/drivers/usb/printer.c	Fri Mar 29 14:49:57 2002
@@ -1,10 +1,12 @@
 /*
- * printer.c  Version 0.8
+ * printer.c  Version 0.11
  *
  * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
  * Copyright (c) 2000 Randy Dunlap	<randy.dunlap@intel.com>
  * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
+ # Copyright (c) 2001 Pete Zaitcev	<zaitcev@redhat.com>
+ # Copyright (c) 2001 David Paschal	<paschal@rcsis.com>
  *
  * USB Printer Device Class driver for USB printers and printer cables
  *
@@ -17,9 +19,11 @@
  *	v0.4 - fixes in unidirectional mode
  *	v0.5 - add DEVICE_ID string support
  *	v0.6 - never time out
- *	v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
+ *	v0.7 - fixed bulk-IN read and poll (David Paschal)
  *	v0.8 - add devfs support
  *	v0.9 - fix unplug-while-open paths
+ *	v0.10 - add proto_bias option (Pete Zaitcev)
+ *	v0.11 - add hpoj.sourceforge.net ioctls (David Paschal)
  */
 
 /*
@@ -54,16 +58,36 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.8"
-#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap"
+#define DRIVER_VERSION "v0.11"
+#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
 #define DRIVER_DESC "USB Printer Device Class driver"
 
 #define USBLP_BUF_SIZE		8192
 #define DEVICE_ID_SIZE		1024
 
-#define IOCNR_GET_DEVICE_ID	1
-#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)	/* get device_id string */
+/* ioctls: */
 #define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
+#define IOCNR_GET_DEVICE_ID		1
+#define IOCNR_GET_PROTOCOLS		2
+#define IOCNR_SET_PROTOCOL		3
+#define IOCNR_HP_SET_CHANNEL		4
+#define IOCNR_GET_BUS_ADDRESS		5
+#define IOCNR_GET_VID_PID		6
+/* Get device_id string: */
+#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
+/* The following ioctls were added for http://hpoj.sourceforge.net: */
+/* Get two-int array:
+ * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3),
+ * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */
+#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
+/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */
+#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
+/* Set channel number (HP Vendor-specific command): */
+#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
+/* Get two-int array: [0]=bus number, [1]=device address: */
+#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
+/* Get two-int array: [0]=vendor ID, [1]=product ID: */
+#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
 
 /*
  * A DEVICE_ID string may include the printer's serial number.
@@ -77,23 +101,37 @@
  * USB Printer Requests
  */
 
-#define USBLP_REQ_GET_ID	0x00
-#define USBLP_REQ_GET_STATUS	0x01
-#define USBLP_REQ_RESET		0x02
+#define USBLP_REQ_GET_ID			0x00
+#define USBLP_REQ_GET_STATUS			0x01
+#define USBLP_REQ_RESET				0x02
+#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00	/* HP Vendor-specific */
 
 #define USBLP_MINORS		16
 #define USBLP_MINOR_BASE	0
 
 #define USBLP_WRITE_TIMEOUT	(5*HZ)			/* 5 seconds */
 
+#define USBLP_FIRST_PROTOCOL	1
+#define USBLP_LAST_PROTOCOL	3
+#define USBLP_MAX_PROTOCOLS	(USBLP_LAST_PROTOCOL+1)
+
 struct usblp {
 	struct usb_device 	*dev;			/* USB device */
 	devfs_handle_t		devfs;			/* devfs device */
 	struct semaphore	sem;			/* locks this struct, especially "dev" */
+	char			*buf;		/* writeurb.transfer_buffer */
 	struct urb		readurb, writeurb;	/* The urbs */
 	wait_queue_head_t	wait;			/* Zzzzz ... */
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
+	/* Alternate-setting numbers and endpoints for each protocol
+	 * (7/1/{index=1,2,3}) that the device supports: */
+	struct {
+		int				alt_setting;
+		struct usb_endpoint_descriptor	*epwrite;
+		struct usb_endpoint_descriptor	*epread;
+	}			protocol[USBLP_MAX_PROTOCOLS];
+	int			current_protocol;
 	int			minor;			/* minor number of device */
 	unsigned int		quirks;			/* quirks flags */
 	unsigned char		used;			/* True if open */
@@ -102,6 +140,33 @@
 							/* first 2 bytes are (big-endian) length */
 };
 
+#ifdef DEBUG
+static void usblp_dump(struct usblp *usblp) {
+	int p;
+
+	dbg("usblp=0x%p", usblp);
+	dbg("dev=0x%p", usblp->dev);
+	dbg("devfs=0x%p", usblp->devfs);
+	dbg("buf=0x%p", usblp->buf);
+	dbg("readcount=%d", usblp->readcount);
+	dbg("ifnum=%d", usblp->ifnum);
+    for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
+	dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting);
+	dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite);
+	dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread);
+    }
+	dbg("current_protocol=%d", usblp->current_protocol);
+	dbg("minor=%d", usblp->minor);
+	dbg("quirks=%d", usblp->quirks);
+	dbg("used=%d", usblp->used);
+	dbg("bidir=%d", usblp->bidir);
+	dbg("device_id_string=\"%s\"",
+		usblp->device_id_string ?
+			usblp->device_id_string + 2 :
+			(unsigned char *)"(null)");
+}
+#endif
+
 extern devfs_handle_t usb_devfs_handle;			/* /dev/usb dir. */
 
 static struct usblp *usblp_table[USBLP_MINORS];
@@ -123,29 +188,52 @@
 	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
 	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
 	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
+	{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
+	{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */   
+	{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */   
+	{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
+	{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
+	{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
+	{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
+	{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
 	{ 0, 0 }
 };
 
+static int usblp_select_alts(struct usblp *usblp);
+static int usblp_set_protocol(struct usblp *usblp, int protocol);
+static int usblp_cache_device_id_string(struct usblp *usblp);
+
+
 /*
  * Functions for usblp control messages.
  */
 
-static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len)
+static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
 {
 	int retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-		request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5);
+		request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT);
 	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
 		request, !!dir, recip, value, len, retval);
 	return retval < 0 ? retval : 0;
 }
 
 #define usblp_read_status(usblp, status)\
-	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
+	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
 #define usblp_get_id(usblp, config, id, maxlen)\
-	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
+	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
 #define usblp_reset(usblp)\
-	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
+	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
+
+#define usblp_hp_channel_change_request(usblp, channel, buffer) \
+	usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1)
+
+/*
+ * See the description for usblp_select_alts() below for the usage
+ * explanation.  Look into your /proc/bus/usb/devices and dmesg in
+ * case of any trouble.
+ */
+static int proto_bias = -1;
 
 /*
  * URB callback.
@@ -257,13 +345,20 @@
 {
 	devfs_unregister (usblp->devfs);
 	usblp_table [usblp->minor] = NULL;
-	info ("usblp%d: removed", usblp->minor);
+	info("usblp%d: removed", usblp->minor);
 
 	kfree (usblp->writeurb.transfer_buffer);
 	kfree (usblp->device_id_string);
 	kfree (usblp);
 }
 
+static void usblp_unlink_urbs(struct usblp *usblp)
+{
+	usb_unlink_urb(&usblp->writeurb);
+	if (usblp->bidir)
+		usb_unlink_urb(&usblp->readurb);
+}
+
 static int usblp_release(struct inode *inode, struct file *file)
 {
 	struct usblp *usblp = file->private_data;
@@ -272,9 +367,7 @@
 	lock_kernel();
 	usblp->used = 0;
 	if (usblp->dev) {
-		if (usblp->bidir)
-			usb_unlink_urb(&usblp->readurb);
-		usb_unlink_urb(&usblp->writeurb);
+		usblp_unlink_urbs(usblp);
 		up(&usblp->sem);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
@@ -294,8 +387,9 @@
 static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct usblp *usblp = file->private_data;
-	int length, err;
-	unsigned char status;
+	int length, err, i;
+	unsigned char status, newChannel;
+	int twoints[2];
 	int retval = 0;
 
 	down (&usblp->sem);
@@ -314,32 +408,128 @@
 					goto done;
 				}
 
-				err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
+				length = usblp_cache_device_id_string(usblp);
+				if (length < 0) {
+					retval = length;
+					goto done;
+				}
+				if (length > _IOC_SIZE(cmd))
+					length = _IOC_SIZE(cmd); /* truncate */
+
+				if (copy_to_user((unsigned char *) arg,
+						usblp->device_id_string,
+						(unsigned long) length)) {
+					retval = -EFAULT;
+					goto done;
+				}
+
+				break;
+
+			case IOCNR_GET_PROTOCOLS:
+				if (_IOC_DIR(cmd) != _IOC_READ ||
+				    _IOC_SIZE(cmd) < sizeof(twoints)) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				twoints[0] = usblp->current_protocol;
+				twoints[1] = 0;
+				for (i = USBLP_FIRST_PROTOCOL;
+				     i <= USBLP_LAST_PROTOCOL; i++) {
+					if (usblp->protocol[i].alt_setting >= 0)
+						twoints[1] |= (1<<i);
+				}
+
+				if (copy_to_user((unsigned char *)arg,
+						(unsigned char *)twoints,
+						sizeof(twoints))) {
+					retval = -EFAULT;
+					goto done;
+				}
+
+				break;
+
+			case IOCNR_SET_PROTOCOL:
+				if (_IOC_DIR(cmd) != _IOC_WRITE) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+#ifdef DEBUG
+				if (arg == -10) {
+					usblp_dump(usblp);
+					break;
+				}
+#endif
+
+				usblp_unlink_urbs(usblp);
+				retval = usblp_set_protocol(usblp, arg);
+				if (retval < 0) {
+					usblp_set_protocol(usblp,
+						usblp->current_protocol);
+				}
+				break;
+
+			case IOCNR_HP_SET_CHANNEL:
+				if (_IOC_DIR(cmd) != _IOC_WRITE ||
+				    usblp->dev->descriptor.idVendor != 0x03F0 ||
+				    usblp->quirks & USBLP_QUIRK_BIDIR) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				err = usblp_hp_channel_change_request(usblp,
+					arg, &newChannel);
 				if (err < 0) {
-					dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
+					err("usblp%d: error = %d setting "
+						"HP channel",
 						usblp->minor, err);
-					usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
 					retval = -EIO;
 					goto done;
 				}
 
-				length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
-				if (length < DEVICE_ID_SIZE)
-					usblp->device_id_string[length] = '\0';
-				else
-					usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
+				dbg("usblp%d requested/got HP channel %ld/%d",
+					usblp->minor, arg, newChannel);
+				break;
 
-				dbg ("usblp%d Device ID string [%d/max %d]='%s'",
-					usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
+			case IOCNR_GET_BUS_ADDRESS:
+				if (_IOC_DIR(cmd) != _IOC_READ ||
+				    _IOC_SIZE(cmd) < sizeof(twoints)) {
+					retval = -EINVAL;
+					goto done;
+				}
 
-				if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
+				twoints[0] = usblp->dev->bus->busnum;
+				twoints[1] = usblp->dev->devnum;
+				if (copy_to_user((unsigned char *)arg,
+						(unsigned char *)twoints,
+						sizeof(twoints))) {
+					retval = -EFAULT;
+					goto done;
+				}
 
-				if (copy_to_user((unsigned char *) arg,
-						usblp->device_id_string, (unsigned long) length)) {
+				dbg("usblp%d is bus=%d, device=%d",
+					usblp->minor, twoints[0], twoints[1]);
+				break;
+
+			case IOCNR_GET_VID_PID:
+				if (_IOC_DIR(cmd) != _IOC_READ ||
+				    _IOC_SIZE(cmd) < sizeof(twoints)) {
+					retval = -EINVAL;
+					goto done;
+				}
+
+				twoints[0] = usblp->dev->descriptor.idVendor;
+				twoints[1] = usblp->dev->descriptor.idProduct;
+				if (copy_to_user((unsigned char *)arg,
+						(unsigned char *)twoints,
+						sizeof(twoints))) {
 					retval = -EFAULT;
 					goto done;
 				}
 
+				dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
+					usblp->minor, twoints[0], twoints[1]);
 				break;
 
 			default:
@@ -545,137 +735,255 @@
 static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
 			 const struct usb_device_id *id)
 {
-	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *epread, *epwrite;
-	struct usblp *usblp;
-	int minor, i, bidir = 0, quirks;
-	int alts = dev->actconfig->interface[ifnum].act_altsetting;
-	int length, err;
-	char *buf;
+	struct usblp *usblp = 0;
+	int protocol;
 	char name[6];
 
-	/* If a bidirectional interface exists, use it. */
-	for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
-
-		interface = &dev->actconfig->interface[ifnum].altsetting[i];
-
-		if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
-		    interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 ||
-		   (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
-			continue;
-
-		if (interface->bInterfaceProtocol > 1) {
-			bidir = 1;
-			alts = i;
-			break;
-		}
-	}
-
-	interface = &dev->actconfig->interface[ifnum].altsetting[alts];
-	if (usb_set_interface(dev, ifnum, alts))
-		err("can't set desired altsetting %d on interface %d", alts, ifnum);
-
-	epwrite = interface->endpoint + 0;
-	epread = bidir ? interface->endpoint + 1 : NULL;
-
-	if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
-		if (interface->bNumEndpoints == 1)
-			return NULL;
-		epwrite = interface->endpoint + 1;
-		epread = bidir ? interface->endpoint + 0 : NULL;
-	}
-
-	if ((epwrite->bEndpointAddress & 0x80) == 0x80)
-		return NULL;
-
-	if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
-		return NULL;
-
-	for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
-	if (usblp_table[minor]) {
-		err("no more free usblp devices");
-		return NULL;
-	}
-
+	/* Malloc and start initializing usblp structure so we can use it
+	 * directly. */
 	if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
-		err("out of memory");
-		return NULL;
+		err("out of memory for usblp");
+		goto abort;
 	}
 	memset(usblp, 0, sizeof(struct usblp));
-	init_MUTEX (&usblp->sem);
-
-	/* lookup quirks for this printer */
-	quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);
-
-	if (bidir && (quirks & USBLP_QUIRK_BIDIR)) {
-		bidir = 0;
-		epread = NULL;
-		info ("Disabling reads from problem bidirectional printer on usblp%d",
-			minor);
-	}
-
 	usblp->dev = dev;
-	usblp->ifnum = ifnum;
-	usblp->minor = minor;
-	usblp->bidir = bidir;
-	usblp->quirks = quirks;
-
+	init_MUTEX (&usblp->sem);
 	init_waitqueue_head(&usblp->wait);
+	usblp->ifnum = ifnum;
 
-	if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
-		err("out of memory");
-		kfree(usblp);
-		return NULL;
+	/* Look for a free usblp_table entry. */
+	while (usblp_table[usblp->minor]) {
+		usblp->minor++;
+		if (usblp->minor >= USBLP_MINORS) {
+			err("no more free usblp devices");
+			goto abort;
+		}
 	}
 
+	/* Malloc device ID string buffer to the largest expected length,
+	 * since we can re-query it on an ioctl and a dynamic string
+	 * could change in length. */
 	if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
-		err("out of memory");
-		kfree(usblp);
-		kfree(buf);
-		return NULL;
+		err("out of memory for device_id_string");
+		goto abort;
 	}
 
-	FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-		buf, 0, usblp_bulk, usblp);
+	/* Malloc write/read buffers in one chunk.  We somewhat wastefully
+	 * malloc both regardless of bidirectionality, because the
+	 * alternate setting can be changed later via an ioctl. */
+	if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
+		err("out of memory for buf");
+		goto abort;
+	}
+
+	/* Lookup quirks for this printer. */
+	usblp->quirks = usblp_quirks(
+		dev->descriptor.idVendor,
+		dev->descriptor.idProduct);
+
+	/* Analyze and pick initial alternate settings and endpoints. */
+	protocol = usblp_select_alts(usblp);
+	if (protocol < 0) {
+		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
+			dev->descriptor.idVendor,
+			dev->descriptor.idProduct);
+		goto abort;
+	}
+
+	/* Setup the selected alternate setting and endpoints. */
+	if (usblp_set_protocol(usblp, protocol) < 0)
+		goto abort;
 
-	if (bidir)
-		FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
-
-	/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
-	err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
-	if (err >= 0) {
-		length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
-		if (length < DEVICE_ID_SIZE)
-			usblp->device_id_string[length] = '\0';
-		else
-			usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
-		dbg ("usblp%d Device ID string [%d]=%s",
-			minor, length, &usblp->device_id_string[2]);
-	}
-	else {
-		err ("usblp%d: error = %d reading IEEE-1284 Device ID string",
-			minor, err);
-		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
-	}
+	/* Retrieve and store the device ID string. */
+	usblp_cache_device_id_string(usblp);
 
 #ifdef DEBUG
 	usblp_check_status(usblp, 0);
 #endif
 
-	sprintf(name, "lp%d", minor);
-
-	/* if we have devfs, create with perms=660 */
+	/* If we have devfs, create with perms=660. */
+	sprintf(name, "lp%d", usblp->minor);
 	usblp->devfs = devfs_register(usb_devfs_handle, name,
 				      DEVFS_FL_DEFAULT, USB_MAJOR,
-				      USBLP_MINOR_BASE + minor,
+				      USBLP_MINOR_BASE + usblp->minor,
 				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
 				      S_IWGRP, &usblp_fops, NULL);
 
-	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
-		minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
+	info("usblp%d: USB %sdirectional printer dev %d "
+		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
+		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum,
+		usblp->protocol[usblp->current_protocol].alt_setting,
+		usblp->current_protocol, usblp->dev->descriptor.idVendor,
+		usblp->dev->descriptor.idProduct);
+
+	return usblp_table[usblp->minor] = usblp;
+
+abort:
+	if (usblp) {
+		if (usblp->buf) kfree(usblp->buf);
+		if (usblp->device_id_string) kfree(usblp->device_id_string);
+		kfree(usblp);
+	}
+	return NULL;
+}
 
-	return usblp_table[minor] = usblp;
+/*
+ * We are a "new" style driver with usb_device_id table,
+ * but our requirements are too intricate for simple match to handle.
+ *
+ * The "proto_bias" option may be used to specify the preferred protocol
+ * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3).  If the device
+ * supports the preferred protocol, then we bind to it.
+ *
+ * The best interface for us is 7/1/2, because it is compatible
+ * with a stream of characters. If we find it, we bind to it.
+ *
+ * Note that the people from hpoj.sourceforge.net need to be able to
+ * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose.
+ *
+ * Failing 7/1/2, we look for 7/1/3, even though it's probably not
+ * stream-compatible, because this matches the behaviour of the old code.
+ *
+ * If nothing else, we bind to 7/1/1 - the unidirectional interface.
+ */
+static int usblp_select_alts(struct usblp *usblp)
+{
+	struct usb_interface *if_alt;
+	struct usb_interface_descriptor *ifd;
+	struct usb_endpoint_descriptor *epd, *epwrite, *epread;
+	int p, i, e;
+
+	if_alt = &usblp->dev->actconfig->interface[usblp->ifnum];
+
+	for (p = 0; p < USBLP_MAX_PROTOCOLS; p++)
+		usblp->protocol[p].alt_setting = -1;
+
+	/* Find out what we have. */
+	for (i = 0; i < if_alt->num_altsetting; i++) {
+		ifd = &if_alt->altsetting[i];
+
+		if (ifd->bInterfaceClass != 7 || ifd->bInterfaceSubClass != 1)
+			continue;
+
+		if (ifd->bInterfaceProtocol < USBLP_FIRST_PROTOCOL ||
+		    ifd->bInterfaceProtocol > USBLP_LAST_PROTOCOL)
+			continue;
+
+		/* Look for bulk OUT and IN endpoints. */
+		epwrite = epread = 0;
+		for (e = 0; e < ifd->bNumEndpoints; e++) {
+			epd = &ifd->endpoint[e];
+
+			if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
+			    USB_ENDPOINT_XFER_BULK)
+				continue;
+
+			if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
+				if (!epwrite) epwrite=epd;
+
+			} else {
+				if (!epread) epread=epd;
+			}
+		}
+
+		/* Ignore buggy hardware without the right endpoints. */
+		if (!epwrite || (ifd->bInterfaceProtocol > 1 && !epread))
+			continue;
+
+		/* Turn off reads for 7/1/1 (unidirectional) interfaces
+		 * and buggy bidirectional printers. */
+		if (ifd->bInterfaceProtocol == 1) {
+			epread = NULL;
+		} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
+			info("Disabling reads from problem bidirectional "
+				"printer on usblp%d", usblp->minor);
+			epread = NULL;
+		}
+
+		usblp->protocol[ifd->bInterfaceProtocol].alt_setting = i;
+		usblp->protocol[ifd->bInterfaceProtocol].epwrite = epwrite;
+		usblp->protocol[ifd->bInterfaceProtocol].epread = epread;
+	}
+
+	/* If our requested protocol is supported, then use it. */
+	if (proto_bias >= USBLP_FIRST_PROTOCOL &&
+	    proto_bias <= USBLP_LAST_PROTOCOL &&
+	    usblp->protocol[proto_bias].alt_setting != -1)
+		return proto_bias;
+
+	/* Ordering is important here. */
+	if (usblp->protocol[2].alt_setting != -1) return 2;
+	if (usblp->protocol[1].alt_setting != -1) return 1;
+	if (usblp->protocol[3].alt_setting != -1) return 3;
+
+	/* If nothing is available, then don't bind to this device. */
+	return -1;
+}
+
+static int usblp_set_protocol(struct usblp *usblp, int protocol)
+{
+	int r, alts;
+
+	if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
+		return -EINVAL;
+
+	alts = usblp->protocol[protocol].alt_setting;
+	if (alts < 0) return -EINVAL;
+	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
+	if (r < 0) {
+		err("can't set desired altsetting %d on interface %d",
+			alts, usblp->ifnum);
+		return r;
+	}
+
+	FILL_BULK_URB(&usblp->writeurb, usblp->dev,
+		usb_sndbulkpipe(usblp->dev,
+		 usblp->protocol[protocol].epwrite->bEndpointAddress),
+		usblp->buf, 0,
+		usblp_bulk, usblp);
+
+	usblp->bidir = (usblp->protocol[protocol].epread != 0);
+	if (usblp->bidir)
+		FILL_BULK_URB(&usblp->readurb, usblp->dev,
+			usb_rcvbulkpipe(usblp->dev,
+			 usblp->protocol[protocol].epread->bEndpointAddress),
+			usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE,
+			usblp_bulk, usblp);
+
+	usblp->current_protocol = protocol;
+	dbg("usblp%d set protocol %d", usblp->minor, protocol);
+	return 0;
+}
+
+/* Retrieves and caches device ID string.
+ * Returns length, including length bytes but not null terminator.
+ * On error, returns a negative errno value. */
+static int usblp_cache_device_id_string(struct usblp *usblp)
+{
+	int err, length;
+
+	err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
+	if (err < 0) {
+		dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
+			usblp->minor, err);
+		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
+		return -EIO;
+	}
+
+	/* First two bytes are length in big-endian.
+	 * They count themselves, and we copy them into
+	 * the user's buffer. */
+	length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1];
+	if (length < 2)
+		length = 2;
+	else if (length >= DEVICE_ID_SIZE)
+		length = DEVICE_ID_SIZE - 1;
+	usblp->device_id_string[length] = '\0';
+
+	dbg("usblp%d Device ID string [len=%d]=\"%s\"",
+		usblp->minor, length, &usblp->device_id_string[2]);
+
+	return length;
 }
 
 static void usblp_disconnect(struct usb_device *dev, void *ptr)
@@ -691,9 +999,7 @@
 	lock_kernel();
 	usblp->dev = NULL;
 
-	usb_unlink_urb(&usblp->writeurb);
-	if (usblp->bidir)
-		usb_unlink_urb(&usblp->readurb);
+	usblp_unlink_urbs(usblp);
 
 	if (!usblp->used)
 		usblp_cleanup (usblp);
@@ -727,7 +1033,7 @@
 {
 	if (usb_register(&usblp_driver))
 		return -1;
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_VERSION ": " DRIVER_DESC);
 	return 0;
 }
 
@@ -741,5 +1047,6 @@
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_PARM(proto_bias, "i");
+MODULE_PARM_DESC(proto_bias, "Favourite protocol number");
 MODULE_LICENSE("GPL");
-
diff -urN linux-2.4.19-pre4/drivers/usb/pwc-ctrl.c linux-2.4.19-pre5/drivers/usb/pwc-ctrl.c
--- linux-2.4.19-pre4/drivers/usb/pwc-ctrl.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/usb/pwc-ctrl.c	Fri Mar 29 14:49:57 2002
@@ -1,7 +1,7 @@
 /* Driver for Philips webcam
    Functions that send various control messages to the webcam, including
    video modes.
-   (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)
+   (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -78,10 +78,12 @@
 #define READ_SHUTTER_FORMATTER			0x0600
 #define READ_RED_GAIN_FORMATTER			0x0700
 #define READ_BLUE_GAIN_FORMATTER		0x0800
+#define SENSOR_TYPE_FORMATTER1			0x0C00
 #define READ_RAW_Y_MEAN_FORMATTER		0x3100
 #define SET_POWER_SAVE_MODE_FORMATTER		0x3200
 #define MIRROR_IMAGE_FORMATTER			0x3300
 #define LED_FORMATTER				0x3400
+#define SENSOR_TYPE_FORMATTER2			0x3700
 
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER		0x0100
@@ -162,6 +164,21 @@
 /****************************************************************************/
 
 
+#define SendControlMsg(request, value, buflen) \
+	usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
+		request, \
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+		value, \
+		pdev->vcinterface, \
+		&buf, buflen, HZ / 2)
+
+#define RecvControlMsg(request, value, buflen) \
+	usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
+		request, \
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+		value, \
+		pdev->vcinterface, \
+		&buf, buflen, HZ / 2)
 
 
 #if PWC_DEBUG
@@ -241,7 +258,7 @@
 	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
 	if (ret < 0)
 		return ret;
-	if (pEntry->compressed)
+	if (pEntry->compressed && pdev->decompressor != NULL)
 		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 		
 	/* Set various parameters */
@@ -911,7 +928,7 @@
 	int ret;
 	
 	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
- 	        GET_STATUS_CTL, 
+ 	        GET_CHROM_CTL, 
 		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 	        PRESET_MANUAL_RED_GAIN_FORMATTER,
 		pdev->vcinterface,
@@ -950,7 +967,7 @@
 	int ret;
 	
 	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
-   	        GET_STATUS_CTL,
+   	        GET_CHROM_CTL,
 		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 		PRESET_MANUAL_BLUE_GAIN_FORMATTER,
 		pdev->vcinterface,
@@ -962,6 +979,7 @@
 	return (buf << 8);
 }
 
+
 /* The following two functions are different, since they only read the
    internal red/blue gains, which may be different from the manual 
    gains set or read above.
@@ -997,11 +1015,74 @@
 		&buf, 1, HZ / 2);
 
 	if (ret < 0)
-	    return ret;
+		return ret;
 	
 	return (buf << 8);
 }
 
+
+static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+{
+	unsigned char buf;
+	
+	/* useful range is 0x01..0x20 */
+	buf = speed / 0x7f0;
+	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+		SET_CHROM_CTL,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		AWB_CONTROL_SPEED_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_wb_speed(struct pwc_device *pdev)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+		GET_CHROM_CTL,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		AWB_CONTROL_SPEED_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)
+		return ret;
+	return (buf * 0x7f0);
+}
+
+
+static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+{
+	unsigned char buf;
+	
+	/* useful range is 0x01..0x3F */
+	buf = (delay >> 10);
+	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+		SET_CHROM_CTL,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		AWB_CONTROL_DELAY_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_wb_delay(struct pwc_device *pdev)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+		GET_CHROM_CTL,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		AWB_CONTROL_DELAY_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)
+		return ret;
+	return (buf << 10);
+}
+
+
 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 {
 	unsigned char buf[2];
@@ -1055,53 +1136,242 @@
 	return 0;
 }
 
+static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+{
+	unsigned char buf;
+	int ret;
+	
+	if (contour < 0)
+		buf = 0xff; /* auto contour on */
+	else
+		buf = 0x0; /* auto contour off */
+	ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+		SET_LUM_CTL,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		AUTO_CONTOUR_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)
+		return ret;
+	
+	if (contour < 0)
+		return 0;
+	if (contour > 0xffff)
+		contour = 0xffff;
+	
+	buf = (contour >> 10); /* contour preset is [0..3f] */
+	ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+		SET_LUM_CTL,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		PRESET_CONTOUR_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)	
+		return ret;	
+	return 0;
+}
+
+static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+{
+	unsigned char buf;
+	int ret;
+	
+	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+		GET_LUM_CTL,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		AUTO_CONTOUR_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)
+		return ret;
+
+	if (buf == 0) {
+		/* auto mode off, query current preset value */
+		ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+			GET_LUM_CTL,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			PRESET_CONTOUR_FORMATTER,
+			pdev->vcinterface,
+			&buf, 1, HZ / 2);
+		if (ret < 0)	
+			return ret;
+		*contour =  (buf << 10);
+	}
+	else
+		*contour = -1;
+	return 0;
+}
+
+
+static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+{
+	unsigned char buf;
+	
+	if (backlight)
+		buf = 0xff;
+	else
+		buf = 0x0;
+	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+		SET_LUM_CTL,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		BACK_LIGHT_COMPENSATION_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_backlight(struct pwc_device *pdev)
+{
+	int ret;
+	unsigned char buf;
+	
+	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+		GET_LUM_CTL,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		BACK_LIGHT_COMPENSATION_FORMATTER,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)
+		return ret;
+	return buf;
+}
+
+
+static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+{
+	unsigned char buf;
+	
+	if (flicker)
+		buf = 0xff;
+	else
+		buf = 0x0;
+	return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+}
+
+static inline int pwc_get_flicker(struct pwc_device *pdev)
+{
+	int ret;
+	unsigned char buf;
+	
+	ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	return buf;
+}
+
+
+static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+{
+	unsigned char buf;
+
+	if (noise < 0)
+		noise = 0;
+	if (noise > 3)
+		noise = 3;
+	buf = noise;
+	return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
+{
+	int ret;
+	unsigned char buf;
+	
+	ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+Debug("pwc_get_dynamic_noise = %d\n", buf);
+	return buf;
+}
+
+
+int pwc_get_cmos_sensor(struct pwc_device *pdev)
+{
+	unsigned char buf;
+	int ret = -1, request;
+	
+	if (pdev->type < 675)
+		request = SENSOR_TYPE_FORMATTER1;
+	else if (pdev->type < 730)
+		return -1; /* The Vesta series doesn't have this call */
+	else
+		request = SENSOR_TYPE_FORMATTER2;
+	
+	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+		GET_STATUS_CTL,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		request,
+		pdev->vcinterface,
+		&buf, 1, HZ / 2);
+	if (ret < 0)
+		return ret;
+	if (pdev->type < 675)
+		return buf | 0x100;
+	else
+		return buf;
+}
+
+
  /* End of Add-Ons                                    */
  /* ************************************************* */
 
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
+	int ret = 0;
+
 	switch(cmd) {
 	case VIDIOCPWCRUSER:
 	{
 		if (pwc_restore_user(pdev))
-			return -EINVAL;
+			ret = -EINVAL;
 		break;
 	}
 	
 	case VIDIOCPWCSUSER:
 	{
 		if (pwc_save_user(pdev))
-			return -EINVAL;
+			ret = -EINVAL;
 		break;
 	}
 		
 	case VIDIOCPWCFACTORY:
 	{
 		if (pwc_restore_factory(pdev))
-			return -EINVAL;
+			ret = -EINVAL;
 		break;
 	}
 	
 	case VIDIOCPWCSCQUAL:
 	{	
-		int qual, ret;
+		int qual;
 
 		if (copy_from_user(&qual, arg, sizeof(int)))
-			return -EFAULT;
-			
-		if (qual < 0 || qual > 3)
-			return -EINVAL;
-		ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot);
-		if (ret < 0)
-			return ret;
-		pdev->vcompression = qual;
+			ret = -EFAULT;
+		else {
+			if (qual < 0 || qual > 3)
+				ret = -EINVAL;
+			else
+				ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot);
+			if (ret >= 0)
+				pdev->vcompression = qual;
+		}
 		break;
 	}
 	
 	case VIDIOCPWCGCQUAL:
 	{
 		if (copy_to_user(arg, &pdev->vcompression, sizeof(int)))
-			return -EFAULT;
+			ret = -EFAULT;
+		break;
+	}
+
+	case VIDIOCPWCPROBE:
+	{
+		struct pwc_probe probe;
+		
+		strcpy(probe.name, pdev->vdev->name);
+		probe.type = pdev->type;
+		if (copy_to_user(arg, &probe, sizeof(probe)))
+			ret = -EFAULT;
 		break;
 	}
 
@@ -1110,10 +1380,10 @@
 		int agc;
 		
 		if (copy_from_user(&agc, arg, sizeof(agc)))
-			return -EFAULT;	
+			ret = -EFAULT;	
 		else {
 			if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc))
-				return -EINVAL;
+				ret = -EINVAL;
 		}
 		break;
 	}
@@ -1123,42 +1393,36 @@
 		int agc;
 		
 		if (pwc_get_agc(pdev, &agc))
-			return -EINVAL;
-		if (copy_to_user(arg, &agc, sizeof(agc)))
-			return -EFAULT;
+			ret = -EINVAL;
+		else
+			if (copy_to_user(arg, &agc, sizeof(agc)))
+				ret = -EFAULT;
 		break;
 	}
 	
 	case VIDIOCPWCSSHUTTER:
 	{
-		int shutter_speed, ret;
+		int shutter_speed;
 
 		if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed)))
-			return -EFAULT;
-		else {
+			ret = -EFAULT;
+		else
 			ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, shutter_speed);
-			if (ret < 0)
-				return ret;
-		}
 		break;
 	}
 	
-
- /* ************************************************* */
- /* Begin of Add-Ons for color compensation           */
-
         case VIDIOCPWCSAWB:
 	{
 		struct pwc_whitebalance wb;
-		int ret;
 		
 		if (copy_from_user(&wb, arg, sizeof(wb)))
-			return -EFAULT;
-	
-		ret = pwc_set_awb(pdev, wb.mode);
-		if (ret >= 0 && wb.mode == PWC_WB_MANUAL) {
-			pwc_set_red_gain(pdev, wb.manual_red);
-			pwc_set_blue_gain(pdev, wb.manual_blue);
+			ret = -EFAULT;
+		else {
+			ret = pwc_set_awb(pdev, wb.mode);
+			if (ret >= 0 && wb.mode == PWC_WB_MANUAL) {
+				pwc_set_red_gain(pdev, wb.manual_red);
+				pwc_set_blue_gain(pdev, wb.manual_blue);
+			}
 		}
 		break;
 	}
@@ -1170,55 +1434,176 @@
 		memset(&wb, 0, sizeof(wb));
 		wb.mode = pwc_get_awb(pdev);
 		if (wb.mode < 0)
-			return -EINVAL;
-		wb.manual_red = pwc_get_red_gain(pdev);
-		wb.manual_blue = pwc_get_blue_gain(pdev);
-		if (wb.mode == PWC_WB_AUTO) {
-			wb.read_red = pwc_read_red_gain(pdev);
-			wb.read_blue = pwc_read_blue_gain(pdev);
+			ret = -EINVAL;
+		else {
+			if (wb.mode == PWC_WB_MANUAL) {
+				wb.manual_red = pwc_get_red_gain(pdev);
+				wb.manual_blue = pwc_get_blue_gain(pdev);
+			}
+			if (wb.mode == PWC_WB_AUTO) {
+				wb.read_red = pwc_read_red_gain(pdev);
+				wb.read_blue = pwc_read_blue_gain(pdev);
+			}
+			if (copy_to_user(arg, &wb, sizeof(wb)))
+				ret= -EFAULT;
 		}
-		if (copy_to_user(arg, &wb, sizeof(wb)))
-			return -EFAULT;
+		break;
+	}
+	
+	case VIDIOCPWCSAWBSPEED:
+	{
+		struct pwc_wb_speed wbs;
+		
+		if (copy_from_user(&wbs, arg, sizeof(wbs)))
+			ret = -EFAULT;
+		else {
+			if (wbs.control_speed > 0) {
+				ret = pwc_set_wb_speed(pdev, wbs.control_speed);
+			}
+			if (wbs.control_delay > 0) {
+				ret = pwc_set_wb_delay(pdev, wbs.control_delay);
+			}
+		}
+		break;
+	}
+	
+	case VIDIOCPWCGAWBSPEED:
+	{
+		struct pwc_wb_speed wbs;
+		
+		ret = pwc_get_wb_speed(pdev);
+		if (ret < 0)
+			break;
+		wbs.control_speed = ret;
+		ret = pwc_get_wb_delay(pdev);
+		if (ret < 0)
+			break;
+		wbs.control_delay = ret;
+		if (copy_to_user(arg, &wbs, sizeof(wbs)))
+			ret = -EFAULT;
 		break;
 	}
 
         case VIDIOCPWCSLED:
 	{
-		int ret;
 		struct pwc_leds leds;
 
 		if (copy_from_user(&leds, arg, sizeof(leds)))
-			return -EFAULT;
-
-		ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
-		if (ret<0)
-		    return ret;
-	    break;
+			ret = -EFAULT;
+		else
+			ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
+	    	break;
 	}
 
 
-
 	case VIDIOCPWCGLED:
 	{
-		int led;
 		struct pwc_leds leds;
 		
-		led = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); 
-		if (led < 0)
-			return -EINVAL;
+		ret = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); 
+		if (ret < 0)
+			break;
 		if (copy_to_user(arg, &leds, sizeof(leds)))
-			return -EFAULT;
+			ret = -EFAULT;
 		break;
 	}
 
- /* End of Add-Ons                                    */
- /* ************************************************* */
+	case VIDIOCPWCSCONTOUR:
+	{
+		int contour;
+		
+		if (copy_from_user(&contour, arg, sizeof(contour)))
+			ret = -EFAULT;
+		else
+			ret = pwc_set_contour(pdev, contour);
+		break;
+	}
+			
+	case VIDIOCPWCGCONTOUR:
+	{
+		int contour;
+		
+		ret = pwc_get_contour(pdev, &contour);
+		if (ret < 0)
+			break;
+			
+		if (copy_to_user(arg, &contour, sizeof(contour)))
+			ret = -EFAULT;
+		break;
+	}
+	
+	case VIDIOCPWCSBACKLIGHT:
+	{
+		int backlight;
+		
+		if (copy_from_user(&backlight, arg, sizeof(backlight)))
+			ret = -EFAULT;
+		else
+			ret = pwc_set_backlight(pdev, backlight);
+		break;
+	}
+
+	case VIDIOCPWCGBACKLIGHT:
+	{
+		ret = pwc_get_backlight(pdev);
+		if (ret < 0)
+			break;
+		if (copy_to_user(arg, &ret, sizeof(ret)))
+			ret = -EFAULT;
+		break;
+	}
+	
+	case VIDIOCPWCSFLICKER:
+	{
+		int flicker;
+		
+		if (copy_from_user(&flicker, arg, sizeof(flicker)))
+			ret = -EFAULT;
+		else
+			ret = pwc_set_flicker(pdev, flicker);
+		break;
+	}
+
+	case VIDIOCPWCGFLICKER:
+	{
+		ret = pwc_get_flicker(pdev);
+		if (ret < 0)
+			break;
+		if (copy_to_user(arg, &ret, sizeof(ret)))
+			ret = -EFAULT;
+		break;
+	}
+	
+	case VIDIOCPWCSDYNNOISE:
+	{
+		int dynnoise;
+		
+		if (copy_from_user(&dynnoise, arg, sizeof(dynnoise)))
+			ret = -EFAULT;
+		else
+			ret = pwc_set_dynamic_noise(pdev, dynnoise);
+		break;
+	}
+	
+	case VIDIOCPWCGDYNNOISE:
+	{
+		ret = pwc_get_dynamic_noise(pdev);
+		if (ret < 0)
+			break;
+		if (copy_to_user(arg, &ret, sizeof(ret)))
+			ret = -EFAULT;
+		break;
+	}
+	
 
 	default:
-		return -ENOIOCTLCMD;
+		ret = -ENOIOCTLCMD;
 		break;
 	}
-	return 0;
+	
+	if (ret > 0)
+		return 0;
+	return ret;
 }
 
 
diff -urN linux-2.4.19-pre4/drivers/usb/pwc-if.c linux-2.4.19-pre5/drivers/usb/pwc-if.c
--- linux-2.4.19-pre4/drivers/usb/pwc-if.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/usb/pwc-if.c	Fri Mar 29 14:49:57 2002
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    USB and Video4Linux interface part.
-   (C) 1999-2001 Nemosoft Unv.
+   (C) 1999-2002 Nemosoft Unv.
 
    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
@@ -66,7 +66,7 @@
 
 /* hotplug device table support */
 static __devinitdata struct usb_device_id pwc_device_table [] = {
-	{ USB_DEVICE(0x0471, 0x0302) },
+	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
 	{ USB_DEVICE(0x0471, 0x0303) },
 	{ USB_DEVICE(0x0471, 0x0304) },
 	{ USB_DEVICE(0x0471, 0x0307) },
@@ -75,12 +75,14 @@
 	{ USB_DEVICE(0x0471, 0x0310) },
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
-	{ USB_DEVICE(0x069A, 0x0001) },
-	{ USB_DEVICE(0x046D, 0x08b0) },
-	{ USB_DEVICE(0x055D, 0x9000) },
+	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
+	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */
+	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
 	{ USB_DEVICE(0x055D, 0x9001) },
-	{ USB_DEVICE(0x041E, 0x400C) },
-	{ USB_DEVICE(0x04CC, 0x8116) },
+	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative */
+	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
+	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
+	{ USB_DEVICE(0x0d81, 0x1900) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, pwc_device_table);
@@ -105,7 +107,7 @@
 static int default_mbufs = 2;	/* Default number of mmap() buffers */
        int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
-static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */
+static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
        int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
 static struct {
 	int type;
@@ -163,7 +165,7 @@
    succeeded. The pwc_device struct links back to both structures.
 
    When a device is unplugged while in use it will be removed from the 
-   list of known USB devices; I also de-register as a V4L device, but 
+   list of known USB devices; I also de-register it as a V4L device, but 
    unfortunately I can't free the memory since the struct is still in use
    by the file descriptor. This free-ing is then deferend until the first
    opportunity. Crude, but it works.
@@ -351,6 +353,8 @@
 	for (; i < MAX_IMAGES; i++)
 		pdev->image_ptr[i] = NULL;
 
+	kbuf = NULL;
+	  
 	Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
 	return 0;
 }
@@ -405,6 +409,7 @@
 		rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
 	}
 	pdev->image_data = NULL;
+	
 	Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
 }
 
@@ -606,12 +611,10 @@
 	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
 }
 
-/* 2001-10-14: The YUV420 is still there, but you can only set it from within 
-   a program (YUV420P being the default) */
+/* 2001-10-14: YUV420P is the only palette remaining. */
 static int pwc_set_palette(struct pwc_device *pdev, int pal)
 {
-	if (   pal == VIDEO_PALETTE_YUV420
-            || pal == VIDEO_PALETTE_YUV420P
+	if (   pal == VIDEO_PALETTE_YUV420P
 #if PWC_DEBUG
             || pal == VIDEO_PALETTE_RAW
 #endif
@@ -629,7 +632,7 @@
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
  */
-static void pwc_isoc_handler(purb_t urb)
+static void pwc_isoc_handler(struct urb *urb)
 {
 	struct pwc_device *pdev;
 	int i, fst, flen;
@@ -791,7 +794,7 @@
 static int pwc_isoc_init(struct pwc_device *pdev)
 {
 	struct usb_device *udev;
-	purb_t urb;
+	struct urb *urb;
 	int i, j, ret;
 
 	struct usb_interface_descriptor *idesc;
@@ -905,7 +908,6 @@
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
 {
 	int ret;
-
 	/* Stop isoc stuff */
 	pwc_isoc_cleanup(pdev);
 	/* Reset parameters */
@@ -968,6 +970,29 @@
 		if (usb_set_interface(pdev->udev, 0, 0))
 			Info("Failed to set alternate interface to 0.\n");
 		pdev->usb_init = 1;
+		
+		if (pwc_trace & TRACE_OPEN) {
+			/* Query CMOS sensor type */
+			const char *sensor_type = NULL;
+
+			i = pwc_get_cmos_sensor(pdev);
+			switch(i) {
+			case -1: /* Unknown, show nothing */; break;
+			case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
+			case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
+			case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
+			case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
+			case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
+			case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
+			case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
+			case 0x40:  sensor_type = "UPA 1021 sensor"; break;
+			case 0x100: sensor_type = "VGA sensor"; break;
+			case 0x101: sensor_type = "PAL MR sensor"; break;
+			default:   sensor_type = "unknown type of sensor"; break;
+			}
+			if (sensor_type != NULL)
+				Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+		}
 	}
 
 	/* Turn on camera */
@@ -1590,6 +1615,7 @@
 	pdev = vdev->priv;
 
 	/* FIXME - audit mmap during a read */		
+	/* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
@@ -1621,7 +1647,7 @@
 	int vendor_id, product_id, type_id;
 	int i, hint;
 	int video_nr = -1; /* default: use next available device */
-	char serial_number[30];
+	char serial_number[30], *name;
 
 	free_mem_leak();
 	
@@ -1642,38 +1668,47 @@
 		switch (product_id) {
 		case 0x0302:
 			Info("Philips PCA645VC USB webcam detected.\n");
+			name = "Philips 645 webcam";
 			type_id = 645;
 			break;
 		case 0x0303:
 			Info("Philips PCA646VC USB webcam detected.\n");
+			name = "Philips 646 webcam";
 			type_id = 646;
 			break;
 		case 0x0304:
 			Info("Askey VC010 type 2 USB webcam detected.\n");
+			name = "Askey VC010 webcam";
 			type_id = 646;
 			break;
 		case 0x0307:
 			Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+			name = "Philips 675 webcam";
 			type_id = 675;
 			break;
 		case 0x0308:
 			Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+			name = "Philips 680 webcam";
 			type_id = 680;
 			break;
 		case 0x030C:
 			Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+			name = "Philips 690 webcam";
 			type_id = 690;
 			break;
 		case 0x0310:
 			Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n");
+			name = "Philips 730 webcam";
 			type_id = 730;
 			break;
 		case 0x0311:
 			Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n");
+			name = "Philips 740 webcam";
 			type_id = 740;
 			break;
 		case 0x0312:
 			Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+			name = "Philips 750 webcam";
 			type_id = 750;
 			break;
 		default:
@@ -1685,6 +1720,7 @@
 		switch(product_id) {
 		case 0x0001:
 			Info("Askey VC010 type 1 USB webcam detected.\n");
+			name = "Askey VC010 webcam";
 			type_id = 645;
 			break;
 		default:
@@ -1695,7 +1731,8 @@
 	else if (vendor_id == 0x046d) {
 		switch(product_id) {
 		case 0x08b0:
-			Info("Logitech QuickCam 3000 Pro detected.\n");
+			Info("Logitech QuickCam 3000 Pro USB webcam detected.\n");
+			name = "Logitech QuickCam 3000 Pro";
 			type_id = 730;
         		break;
         	default:
@@ -1711,10 +1748,12 @@
 		switch(product_id) {
 		case 0x9000:
 			Info("Samsung MPC-C10 USB webcam detected.\n");
+			name = "Samsung MPC-C10";
 			type_id = 675;
 			break;
 		case 0x9001:
 			Info("Samsung MPC-C30 USB webcam detected.\n");
+			name = "Samsung MPC-C30";
 			type_id = 675;
 			break;
 		default:
@@ -1726,6 +1765,7 @@
 		switch(product_id) {
 		case 0x400c:
 			Info("Creative Labs Webcam 5 detected.\n");
+			name = "Creative Labs Webcam 5";
 			type_id = 730;
 			break;
 		default:
@@ -1736,7 +1776,8 @@
 	else if (vendor_id == 0x04cc) { 
 		switch(product_id) {
 		case 0x8116:
-			Info("SOTEC CMS-001 USB webcam detected.\n");
+			Info("Sotec Afina Eye USB webcam detected.\n");
+			name = "Sotec Afina Eye";
 			type_id = 730;
 			break;  
 		default:
@@ -1744,7 +1785,25 @@
 			break;
 		}
 	}
-	else return NULL; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */
+	else if (vendor_id == 0x0d81) {
+		switch(product_id) {
+		case 0x1900:
+			Info("Visionite VCS-UC300 USB webcam detected.\n");
+			name = "Visionite VCS-UC300";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x1910:
+			Info("Visionite VCS-UM100 USB webcam detected.\n");
+			name = "Visionite VCS-UM100";
+			type_id = 730; /* CMOS sensor */
+			break;
+		default:
+			return NULL;
+			break;
+		}
+	}
+	else 
+		return NULL; /* Not any of the know types; but the list keeps growing. */
 
 	memset(serial_number, 0, 30);
 	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
@@ -1778,7 +1837,7 @@
 		return NULL;
 	}
 	memcpy(vdev, &pwc_template, sizeof(pwc_template));
-	sprintf(vdev->name, "Philips %d webcam", pdev->type);
+	strcpy(vdev->name, name);
 	SET_MODULE_OWNER(vdev);
 	pdev->vdev = vdev;
 	vdev->priv = pdev;
@@ -1786,7 +1845,6 @@
 	pdev->release = udev->descriptor.bcdDevice;
 	Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
 
-
 	/* Now search device_hint[] table for a match, so we can hint a node number. */
 	for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
 		if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
@@ -1951,11 +2009,12 @@
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
 	Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
-	Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n");
+	Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30,\n");
+	Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
 	if (fps) {
-		if (fps < 5 || fps > 30) {
-			Err("Framerate out of bounds (5-30).\n");
+		if (fps < 4 || fps > 30) {
+			Err("Framerate out of bounds (4-30).\n");
 			return -EINVAL;
 		}
 		default_fps = fps;
@@ -2007,9 +2066,9 @@
 	if (power_save)
 		Info("Enabling power save on open/close.\n");
 	if (leds[0] >= 0)
-		led_on = leds[0] / 100;
+		led_on = leds[0];
 	if (leds[1] >= 0)
-		led_off = leds[1] / 100;
+		led_off = leds[1];
 
 	/* Big device node whoopla. Basicly, it allows you to assign a 
 	   device node (/dev/videoX) to a camera, based on its type 
diff -urN linux-2.4.19-pre4/drivers/usb/pwc-ioctl.h linux-2.4.19-pre5/drivers/usb/pwc-ioctl.h
--- linux-2.4.19-pre4/drivers/usb/pwc-ioctl.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/usb/pwc-ioctl.h	Fri Mar 29 14:49:57 2002
@@ -1,7 +1,7 @@
 #ifndef PWC_IOCTL_H
 #define PWC_IOCTL_H
 
-/* (C) 2001 Nemosoft Unv.    webcam@smcc.demon.nl
+/* (C) 2001-2002 Nemosoft Unv.    webcam@smcc.demon.nl
    
    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
@@ -18,7 +18,9 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/*
+/*         This is pwc-ioctl.h belonging to PWC 8.6                        */
+
+/* 
    Changes
    2001/08/03  Alvarado   Added ioctl constants to access methods for 
                           changing white balance and red/blue gains
@@ -52,6 +54,14 @@
 #define PWC_FPS_SNAPSHOT	0x00400000
 
 
+
+struct pwc_probe
+{
+	char name[32];
+	int type;
+};
+
+
 /* pwc_whitebalance.mode values */
 #define PWC_WB_INDOOR		0
 #define PWC_WB_OUTDOOR		1
@@ -63,9 +73,9 @@
    Set mode to one of the PWC_WB_* values above.
    *red and *blue are the respective gains of these colour components inside 
    the camera; range 0..65535
-   When mode == PWC_WB_MANUAL, manual_red and manual_blue are set or read; 
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
    otherwise undefined.
-   read_red and read_blue are read-only.
+   'read_red' and 'read_blue' are read-only.
 */   
    
 struct pwc_whitebalance
@@ -75,6 +85,17 @@
 	int read_red, read_blue;	/* R/O */
 };
 
+/* 
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and 
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+	int control_speed;
+	int control_delay;
+
+};
 
 /* Used with VIDIOCPWC[SG]LED */
 struct pwc_leds
@@ -104,6 +125,19 @@
  /* Get preferred compression quality */
 #define VIDIOCPWCGCQUAL		_IOR('v', 195, int)
 
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding 
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */    
+#define VIDIOCPWCPROBE		_IOR('v', 199, struct pwc_probe)
+
  /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
 #define VIDIOCPWCSAGC		_IOW('v', 200, int)
  /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
@@ -115,9 +149,28 @@
 #define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
 #define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
 
- /* Turn LED on/off ; int range 0..65535 */
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED	_IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED	_IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
 #define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
- /* Get state of LED; int range 0..65535 */
 #define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
 
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR	_IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR	_IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT	_IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT	_IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER	_IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER	_IOR('v', 208, int)  
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
+
 #endif
diff -urN linux-2.4.19-pre4/drivers/usb/pwc-misc.c linux-2.4.19-pre5/drivers/usb/pwc-misc.c
--- linux-2.4.19-pre4/drivers/usb/pwc-misc.c	Sat Sep 15 22:21:43 2001
+++ linux-2.4.19-pre5/drivers/usb/pwc-misc.c	Fri Mar 29 14:49:57 2002
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    Various miscellaneous functions and tables.
-   (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)
+   (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
diff -urN linux-2.4.19-pre4/drivers/usb/pwc-uncompress.c linux-2.4.19-pre5/drivers/usb/pwc-uncompress.c
--- linux-2.4.19-pre4/drivers/usb/pwc-uncompress.c	Wed Jun 20 17:42:09 2001
+++ linux-2.4.19-pre5/drivers/usb/pwc-uncompress.c	Fri Mar 29 14:49:57 2002
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    Decompression frontend.
-   (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)
+   (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
diff -urN linux-2.4.19-pre4/drivers/usb/pwc-uncompress.h linux-2.4.19-pre5/drivers/usb/pwc-uncompress.h
--- linux-2.4.19-pre4/drivers/usb/pwc-uncompress.h	Wed Jun 20 17:42:09 2001
+++ linux-2.4.19-pre5/drivers/usb/pwc-uncompress.h	Fri Mar 29 14:49:57 2002
@@ -1,4 +1,4 @@
-/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)
+/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -20,8 +20,8 @@
    significant change should be reflected by increasing the 
    pwc_decompressor_version major number.
  */
-#ifndef PWC_DEC_H
-#define PWC_DEC_H
+#ifndef PWC_UNCOMPRESS_H
+#define PWC_UNCOMPRESS_H
 
 #include <linux/config.h>
 #include <linux/list.h>
diff -urN linux-2.4.19-pre4/drivers/usb/pwc.h linux-2.4.19-pre5/drivers/usb/pwc.h
--- linux-2.4.19-pre4/drivers/usb/pwc.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/usb/pwc.h	Fri Mar 29 14:49:57 2002
@@ -1,4 +1,4 @@
-/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)
+/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	5
-#define PWC_VERSION 	"8.5"
+#define PWC_MINOR	6
+#define PWC_VERSION 	"8.6"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
@@ -96,7 +96,7 @@
 	void *data;
 	int  length;
 	int  read;
-	purb_t urb;
+	struct urb *urb;
 };
 
 /* intermediate buffers with raw data from the USB cam */
@@ -247,6 +247,7 @@
 extern int pwc_set_saturation(struct pwc_device *pdev, int value);
 extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
 extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value);
+extern int pwc_get_cmos_sensor(struct pwc_device *pdev);
 
 /* Power down or up the camera; not supported by all models */
 extern int pwc_camera_power(struct pwc_device *pdev, int power);
diff -urN linux-2.4.19-pre4/drivers/usb/serial/digi_acceleport.c linux-2.4.19-pre5/drivers/usb/serial/digi_acceleport.c
--- linux-2.4.19-pre4/drivers/usb/serial/digi_acceleport.c	Wed Oct 10 23:42:47 2001
+++ linux-2.4.19-pre5/drivers/usb/serial/digi_acceleport.c	Fri Mar 29 14:49:57 2002
@@ -734,7 +734,7 @@
 	while( count > 0 && ret == 0 ) {
 
 		while( (port->write_urb->status == -EINPROGRESS
-		|| priv->dp_write_urb_in_use) && jiffies < timeout ) {
+		|| priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) {
 			cond_wait_interruptible_timeout_irqrestore(
 				&port->write_wait, DIGI_RETRY_TIMEOUT,
 				&priv->dp_port_lock, flags );
@@ -899,7 +899,7 @@
 
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
 
-	while( jiffies < timeout && !priv->dp_transmit_idle ) {
+	while( time_before(jiffies, timeout) && !priv->dp_transmit_idle ) {
 		cond_wait_interruptible_timeout_irqrestore(
 			&priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,
 			&priv->dp_port_lock, flags );
diff -urN linux-2.4.19-pre4/drivers/usb/serial/ipaq.c linux-2.4.19-pre5/drivers/usb/serial/ipaq.c
--- linux-2.4.19-pre4/drivers/usb/serial/ipaq.c	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/serial/ipaq.c	Fri Mar 29 14:49:58 2002
@@ -9,6 +9,10 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (19/3/2002) ganesh
+ * 	Don't submit urbs while holding spinlocks. Thanks to Greg for pointing
+ * 	this out.
+ *
  * (8/3/2002) ganesh
  * 	The ipaq sometimes emits a '\0' before the CLIENT string. At this
  * 	point of time, the ppp ldisc is not yet attached to the tty, so
@@ -65,7 +69,7 @@
 		       int count);
 static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
 			   int count);
-static int ipaq_write_flush(struct usb_serial_port *port);
+static void ipaq_write_gather(struct usb_serial_port *port);
 static void ipaq_read_bulk_callback (struct urb *urb);
 static void ipaq_write_bulk_callback(struct urb *urb);
 static int ipaq_write_room(struct usb_serial_port *port);
@@ -382,17 +386,23 @@
 	priv->queue_len += count;
 	if (priv->active == 0) {
 		priv->active = 1;
-		result = ipaq_write_flush(port);
+		ipaq_write_gather(port);
+		spin_unlock_irqrestore(&write_list_lock, flags);
+		result = usb_submit_urb(port->write_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		}
+	} else {
+		spin_unlock_irqrestore(&write_list_lock, flags);
 	}
-	spin_unlock_irqrestore(&write_list_lock, flags);
 	return result;
 }
 
-static int ipaq_write_flush(struct usb_serial_port *port)
+static void ipaq_write_gather(struct usb_serial_port *port)
 {
 	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
 	struct usb_serial	*serial = port->serial;
-	int			count, room, result;
+	int			count, room;
 	struct ipaq_packet	*pkt;
 	struct urb		*urb = port->write_urb;
 	struct list_head	*tmp;
@@ -400,7 +410,7 @@
 	if (urb->status == -EINPROGRESS) {
 		/* Should never happen */
 		err(__FUNCTION__ " - flushing while urb is active !");
-		return -EAGAIN;
+		return;
 	}
 	room = URBDATA_SIZE;
 	for (tmp = priv->queue.next; tmp != &priv->queue;) {
@@ -427,11 +437,7 @@
 		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
 		      port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
 		      port);
-	result = usb_submit_urb(urb);
-	if (result) {
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
-	}
-	return result;
+	return;
 }
 
 static void ipaq_write_bulk_callback(struct urb *urb)
@@ -439,6 +445,7 @@
 	struct usb_serial_port	*port = (struct usb_serial_port *)urb->context;
 	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
 	unsigned long		flags;
+	int			result;
 
 	if (port_paranoia_check (port, __FUNCTION__)) {
 		return;
@@ -452,11 +459,16 @@
 
 	spin_lock_irqsave(&write_list_lock, flags);
 	if (!list_empty(&priv->queue)) {
-		ipaq_write_flush(port);
+		ipaq_write_gather(port);
+		spin_unlock_irqrestore(&write_list_lock, flags);
+		result = usb_submit_urb(port->write_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		}
 	} else {
 		priv->active = 0;
+		spin_unlock_irqrestore(&write_list_lock, flags);
 	}
-	spin_unlock_irqrestore(&write_list_lock, flags);
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 	
diff -urN linux-2.4.19-pre4/drivers/usb/serial/visor.c linux-2.4.19-pre5/drivers/usb/serial/visor.c
--- linux-2.4.19-pre4/drivers/usb/serial/visor.c	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/serial/visor.c	Fri Mar 29 14:49:58 2002
@@ -12,6 +12,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (03/21/2002) gkh
+ *	Added support for the Palm m130 device, thanks to Udo Eisenbarth
+ *	<udo.eisenbarth@web.de> for the information.
+ *
  * (02/21/2002) SilaS
  *	Added support for the Palm m515 devices.
  *
@@ -168,6 +172,7 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -188,6 +193,7 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
diff -urN linux-2.4.19-pre4/drivers/usb/serial/visor.h linux-2.4.19-pre5/drivers/usb/serial/visor.h
--- linux-2.4.19-pre4/drivers/usb/serial/visor.h	Fri Mar 29 14:49:12 2002
+++ linux-2.4.19-pre5/drivers/usb/serial/visor.h	Fri Mar 29 14:49:58 2002
@@ -25,6 +25,7 @@
 #define PALM_M505_ID			0x0002
 #define PALM_M515_ID			0x0003
 #define PALM_M125_ID			0x0040
+#define PALM_M130_ID			0x0050
 
 #define SONY_VENDOR_ID			0x054C
 #define SONY_CLIE_3_5_ID		0x0038
diff -urN linux-2.4.19-pre4/drivers/usb/uhci.c linux-2.4.19-pre5/drivers/usb/uhci.c
--- linux-2.4.19-pre4/drivers/usb/uhci.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/drivers/usb/uhci.c	Fri Mar 29 14:49:58 2002
@@ -618,7 +618,7 @@
 {
 	struct urb_priv *urbp;
 
-	urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
 	if (!urbp) {
 		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
 		return NULL;
@@ -1585,7 +1585,9 @@
 	spin_unlock(&urb->lock);
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
-	uhci_call_completion(urb);
+	/* Only call completion if it was successful */
+	if (!ret)
+		uhci_call_completion(urb);
 
 	return ret;
 }
@@ -1651,6 +1653,7 @@
 		/* Interrupts are an exception */
 		if (urb->interval) {
 			uhci_add_complete(urb);
+			spin_unlock_irqrestore(&urb->lock, flags);
 			return;		/* <-- note return */
 		}
 
diff -urN linux-2.4.19-pre4/drivers/usb/usb-ohci.c linux-2.4.19-pre5/drivers/usb/usb-ohci.c
--- linux-2.4.19-pre4/drivers/usb/usb-ohci.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/usb/usb-ohci.c	Fri Mar 29 14:49:58 2002
@@ -11,6 +11,9 @@
  * 
  * 
  * History:
+ *
+ * 2002/01/20 async unlink fixes:  return -EINPROGRESS (per spec) and
+ *	make interrupt unlink-in-completion work (db)
  * 
  * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
  * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
@@ -486,9 +489,8 @@
 
 			/* implicitly requeued */
   			urb->actual_length = 0;
-  			urb->status = USB_ST_URB_PENDING;
-  			if (urb_priv->state != URB_DEL)
-  				td_submit_urb (urb);
+			urb->status = -EINPROGRESS;
+			td_submit_urb (urb);
   			break;
   			
 		case PIPE_ISOCHRONOUS:
@@ -790,6 +792,7 @@
 				/* usb_dec_dev_use done in dl_del_list() */
 				urb->status = -EINPROGRESS;
 				spin_unlock_irqrestore (&usb_ed_lock, flags);
+				return -EINPROGRESS;
 			}
 		} else {
 			urb_rm_priv (urb);
diff -urN linux-2.4.19-pre4/drivers/usb/usb.c linux-2.4.19-pre5/drivers/usb/usb.c
--- linux-2.4.19-pre4/drivers/usb/usb.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre5/drivers/usb/usb.c	Fri Mar 29 14:49:58 2002
@@ -1955,7 +1955,7 @@
 	/* 9.4.10 says devices don't need this, if the interface
 	   only has one alternate setting */
 	if (iface->num_altsetting == 1) {
-		warn("ignoring set_interface for dev %d, iface %d, alt %d",
+		dbg("ignoring set_interface for dev %d, iface %d, alt %d",
 			dev->devnum, interface, alternate);
 		return 0;
 	}
diff -urN linux-2.4.19-pre4/drivers/video/Config.in linux-2.4.19-pre5/drivers/video/Config.in
--- linux-2.4.19-pre4/drivers/video/Config.in	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/drivers/video/Config.in	Fri Mar 29 14:49:58 2002
@@ -146,6 +146,7 @@
 	    bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
 	    bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
 	 fi
+	 tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
 	 tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
 	 tristate '  Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT
@@ -273,7 +274,7 @@
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -294,7 +295,7 @@
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
@@ -311,7 +312,8 @@
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+	   "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -327,7 +329,8 @@
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -336,7 +339,7 @@
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
            "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB24 y
       else
 	 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
@@ -344,7 +347,7 @@
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
-	      "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	    define_tristate CONFIG_FBCON_CFB24 m
 	 fi
       fi
diff -urN linux-2.4.19-pre4/drivers/video/Makefile linux-2.4.19-pre5/drivers/video/Makefile
--- linux-2.4.19-pre4/drivers/video/Makefile	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/drivers/video/Makefile	Fri Mar 29 14:49:58 2002
@@ -50,6 +50,7 @@
 obj-$(CONFIG_FB_ATARI)            += atafb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_RADEON)		  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
diff -urN linux-2.4.19-pre4/fs/buffer.c linux-2.4.19-pre5/fs/buffer.c
--- linux-2.4.19-pre4/fs/buffer.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/fs/buffer.c	Fri Mar 29 14:50:07 2002
@@ -47,6 +47,7 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/completion.h>
+#include <linux/compiler.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -102,27 +103,35 @@
 	struct {
 		int nfract;	/* Percentage of buffer cache dirty to 
 				   activate bdflush */
-		int dummy1;	/* old "ndirty" */
+		int ndirty;	/* Maximum number of dirty blocks to write out per
+				   wake-cycle */
 		int dummy2;	/* old "nrefill" */
 		int dummy3;	/* unused */
 		int interval;	/* jiffies delay between kupdate flushes */
 		int age_buffer;	/* Time for normal buffer to age before we flush it */
 		int nfract_sync;/* Percentage of buffer cache dirty to 
 				   activate bdflush synchronously */
-		int dummy4;	/* unused */
+		int nfract_stop_bdflush; /* Percetange of buffer cache dirty to stop bdflush */
 		int dummy5;	/* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}};
+} bdf_prm = {{30, 500, 0, 0, 5*HZ, 30*HZ, 60, 20, 0}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
-int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0};
+int bdflush_min[N_PARAM] = {  0,  1,    0,   0,  0,   1*HZ,   0, 0, 0};
+int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 10000*HZ, 100, 100, 0};
 
 void unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Wait_IO, &bh->b_state);
-	clear_bit(BH_launder, &bh->b_state);
+	clear_bit(BH_Launder, &bh->b_state);
+	/*
+	 * When a locked buffer is visible to the I/O layer BH_Launder
+	 * is set. This means before unlocking we must clear BH_Launder,
+	 * mb() on alpha and then clear BH_Lock, so no reader can see
+	 * BH_Launder set on an unlocked buffer and then risk to deadlock.
+	 */
+	smp_mb__after_clear_bit();
 	clear_bit(BH_Lock, &bh->b_state);
 	smp_mb__after_clear_bit();
 	if (waitqueue_active(&bh->b_wait))
@@ -130,13 +139,9 @@
 }
 
 /*
- * Rewrote the wait-routines to use the "new" wait-queue functionality,
- * and getting rid of the cli-sti pairs. The wait-queue routines still
- * need cli-sti, but now it's just a couple of 386 instructions or so.
- *
  * Note that the real wait_on_buffer() is an inline function that checks
- * if 'b_wait' is set before calling this, so that the queues aren't set
- * up unnecessarily.
+ * that the buffer is locked before calling this, so that unnecessary disk
+ * unplugging does not occur.
  */
 void __wait_on_buffer(struct buffer_head * bh)
 {
@@ -232,10 +237,9 @@
  */
 static void write_unlocked_buffers(kdev_t dev)
 {
-	do {
+	do
 		spin_lock(&lru_list_lock);
-	} while (write_some_buffers(dev));
-	run_task_queue(&tq_disk);
+	while (write_some_buffers(dev));
 }
 
 /*
@@ -273,12 +277,6 @@
 	return 0;
 }
 
-static inline void wait_for_some_buffers(kdev_t dev)
-{
-	spin_lock(&lru_list_lock);
-	wait_for_buffers(dev, BUF_LOCKED, 1);
-}
-
 static int wait_for_locked_buffers(kdev_t dev, int index, int refile)
 {
 	do {
@@ -1046,7 +1044,6 @@
 	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
 
 	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
-	dirty += size_buffers_type[BUF_LOCKED] >> PAGE_SHIFT;
 	tot = nr_free_buffer_pages();
 
 	dirty *= 100;
@@ -1063,6 +1060,21 @@
 	return -1;
 }
 
+static int bdflush_stop(void)
+{
+	unsigned long dirty, tot, dirty_limit;
+
+	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+	tot = nr_free_buffer_pages();
+
+	dirty *= 100;
+	dirty_limit = tot * bdf_prm.b_un.nfract_stop_bdflush;
+
+	if (dirty > dirty_limit)
+		return 0;
+	return 1;
+}
+
 /*
  * if a new dirty buffer is created we need to balance bdflush.
  *
@@ -1077,19 +1089,16 @@
 	if (state < 0)
 		return;
 
-	/* If we're getting into imbalance, start write-out */
-	spin_lock(&lru_list_lock);
-	write_some_buffers(NODEV);
+	wakeup_bdflush();
 
 	/*
 	 * And if we're _really_ out of balance, wait for
-	 * some of the dirty/locked buffers ourselves and
-	 * start bdflush.
+	 * some of the dirty/locked buffers ourselves.
 	 * This will throttle heavy writers.
 	 */
 	if (state > 0) {
-		wait_for_some_buffers(NODEV);
-		wakeup_bdflush();
+		spin_lock(&lru_list_lock);
+		write_some_buffers(NODEV);
 	}
 }
 
@@ -2592,23 +2601,58 @@
 	return 1;
 }
 
+/*
+ * The first time the VM inspects a page which has locked buffers, it
+ * will just mark it as needing waiting upon on the scan of the page LRU.
+ * BH_Wait_IO is used for this.
+ *
+ * The second time the VM visits the page, if it still has locked
+ * buffers, it is time to start writing them out.  (BH_Wait_IO was set).
+ *
+ * The third time the VM visits the page, if the I/O hasn't completed
+ * then it's time to wait upon writeout.  BH_Lock and BH_Launder are
+ * used for this.
+ *
+ * There is also the case of buffers which were locked by someone else
+ * - write(2) callers, bdflush, etc.  There can be a huge number of these
+ * and we don't want to just skip them all and fail the page allocation. 
+ * We want to be able to wait on these buffers as well.
+ *
+ * The BH_Launder bit is set in submit_bh() to indicate that I/O is
+ * underway against the buffer, doesn't matter who started it - we know
+ * that the buffer will eventually come unlocked, and so it's safe to
+ * wait on it.
+ *
+ * The caller holds the page lock and the caller will free this page
+ * into current->local_page, so by waiting on the page's buffers the
+ * caller is guaranteed to obtain this page.
+ *
+ * sync_page_buffers() will sort-of return true if all the buffers
+ * against this page are freeable, so try_to_free_buffers() should
+ * try to free the page's buffers a second time.  This is a bit
+ * broken for blocksize < PAGE_CACHE_SIZE, but not very importantly.
+ */
 static int sync_page_buffers(struct buffer_head *head)
 {
 	struct buffer_head * bh = head;
-	int tryagain = 0;
+	int tryagain = 1;
 
 	do {
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
 			continue;
 
 		/* Don't start IO first time around.. */
-		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state))
+		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state)) {
+			tryagain = 0;
 			continue;
+		}
 
 		/* Second time through we start actively writing out.. */
 		if (test_and_set_bit(BH_Lock, &bh->b_state)) {
-			if (!test_bit(BH_launder, &bh->b_state))
+			if (unlikely(!buffer_launder(bh))) {
+				tryagain = 0;
 				continue;
+			}
 			wait_on_buffer(bh);
 			tryagain = 1;
 			continue;
@@ -2621,7 +2665,6 @@
 
 		__mark_buffer_clean(bh);
 		get_bh(bh);
-		set_bit(BH_launder, &bh->b_state);
 		bh->b_end_io = end_buffer_io_sync;
 		submit_bh(WRITE, bh);
 		tryagain = 0;
@@ -2946,14 +2989,29 @@
 
 	complete((struct completion *)startup);
 
+	/*
+	 * FIXME: The ndirty logic here is wrong.  It's supposed to
+	 * send bdflush back to sleep after writing ndirty buffers.
+	 * In fact, the test is wrong so bdflush will in fact
+	 * sleep when bdflush_stop() returns true.
+	 *
+	 * FIXME: If it proves useful to implement ndirty properly,
+	 * then perhaps the value of ndirty should be scaled by the
+	 * amount of memory in the machine.
+	 */
 	for (;;) {
+		int ndirty = bdf_prm.b_un.ndirty;
+
 		CHECK_EMERGENCY_SYNC
 
-		spin_lock(&lru_list_lock);
-		if (!write_some_buffers(NODEV) || balance_dirty_state() < 0) {
-			wait_for_some_buffers(NODEV);
-			interruptible_sleep_on(&bdflush_wait);
+		while (ndirty > 0) {
+			spin_lock(&lru_list_lock);
+			if (!write_some_buffers(NODEV))
+				break;
+			ndirty -= NRSYNC;
 		}
+		if (ndirty > 0 || bdflush_stop())
+			interruptible_sleep_on(&bdflush_wait);
 	}
 }
 
@@ -2982,8 +3040,6 @@
 	complete((struct completion *)startup);
 
 	for (;;) {
-		wait_for_some_buffers(NODEV);
-
 		/* update interval */
 		interval = bdf_prm.b_un.interval;
 		if (interval) {
@@ -3011,6 +3067,7 @@
 		printk(KERN_DEBUG "kupdate() activated...\n");
 #endif
 		sync_old_buffers();
+		run_task_queue(&tq_disk);
 	}
 }
 
diff -urN linux-2.4.19-pre4/fs/coda/coda_linux.c linux-2.4.19-pre5/fs/coda/coda_linux.c
--- linux-2.4.19-pre4/fs/coda/coda_linux.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre5/fs/coda/coda_linux.c	Fri Mar 29 14:50:07 2002
@@ -34,21 +34,7 @@
 char * coda_f2s(ViceFid *f)
 {
 	static char s[60];
-	if ( f ) {
-		sprintf(s, "(%-#lx,%-#lx,%-#lx)", 
-			 f->Volume, f->Vnode, f->Unique);
-	}
-	return s;
-}
-
-/* print another fid */
-char * coda_f2s2(ViceFid *f)
-{
-	static char s[60];
-	if ( f ) {
-		sprintf(s, "(%-#lx,%-#lx,%-#lx)", 
-			 f->Volume, f->Vnode, f->Unique);
-	}
+	sprintf(s, "(%-#lx.%-#lx.%-#lx)", f->Volume, f->Vnode, f->Unique);
 	return s;
 }
 
@@ -172,8 +158,6 @@
 	        inode->i_mtime = attr->va_mtime.tv_sec;
         if (attr->va_ctime.tv_sec != -1)
 	        inode->i_ctime = attr->va_ctime.tv_sec;
-	if (!inode->i_ctime)
-		inode->i_ctime = inode->i_mtime;
 }
 
 
diff -urN linux-2.4.19-pre4/fs/coda/dir.c linux-2.4.19-pre5/fs/coda/dir.c
--- linux-2.4.19-pre4/fs/coda/dir.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre5/fs/coda/dir.c	Fri Mar 29 14:50:07 2002
@@ -50,11 +50,8 @@
 static int coda_dentry_delete(struct dentry *);
 
 /* support routines */
-static void coda_prepare_fakefile(struct file *coda_file, 
-				  struct dentry *open_dentry,
-				  struct file *open_file);
-static int coda_venus_readdir(struct file *filp, void *dirent, 
-			      filldir_t filldir);
+static int coda_venus_readdir(struct file *filp, filldir_t filldir,
+			      void *dirent, struct dentry *dir);
 int coda_fsync(struct file *, struct dentry *dentry, int datasync);
 
 int coda_hasmknod;
@@ -209,7 +206,7 @@
         int error=0;
 	const char *name=de->d_name.name;
 	int length=de->d_name.len;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	struct ViceFid newfid;
 	struct coda_vattr attrs;
 
@@ -247,7 +244,7 @@
         int error=0;
 	const char *name=de->d_name.name;
 	int length=de->d_name.len;
-	struct inode *result = NULL;
+	struct inode *inode;
 	struct ViceFid newfid;
 	struct coda_vattr attrs;
 
@@ -272,23 +269,22 @@
 		return error;
 	}
 
-	error = coda_cnode_make(&result, &newfid, dir->i_sb);
-	if ( error ) {
+	inode = coda_iget(dir->i_sb, &newfid, &attrs);
+	if ( IS_ERR(inode) ) {
 		d_drop(de);
-		result = NULL;
-		return error;
+		return PTR_ERR(inode);
 	}
 
 	/* invalidate the directory cnode's attributes */
 	coda_dir_changed(dir, 0);
-	d_instantiate(de, result);
+	d_instantiate(de, inode);
         return 0;
 }			     
 
 static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
 {
 	struct inode *inode;
-	struct coda_vattr attr;
+	struct coda_vattr attrs;
 	const char *name = de->d_name.name;
 	int len = de->d_name.len;
 	int error;
@@ -302,9 +298,9 @@
 	CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", 
 	       name, len, coda_i2s(dir), mode);
 
-	attr.va_mode = mode;
+	attrs.va_mode = mode;
 	error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
-			       name, len, &newfid, &attr);
+			       name, len, &newfid, &attrs);
         
         if ( error ) {
 	        CDEBUG(D_INODE, "mkdir error: %s result %d\n", 
@@ -316,10 +312,10 @@
 	CDEBUG(D_INODE, "mkdir: new dir has fid %s.\n", 
 	       coda_f2s(&newfid)); 
 
-	error = coda_cnode_make(&inode, &newfid, dir->i_sb);
-	if ( error ) {
+	inode = coda_iget(dir->i_sb, &newfid, &attrs);
+	if ( IS_ERR(inode) ) {
 		d_drop(de);
-		return error;
+		return PTR_ERR(inode);
 	}
 	
 	/* invalidate the directory cnode's attributes */
@@ -490,156 +486,120 @@
 
 
 /* file operations for directories */
-int coda_readdir(struct file *file, void *dirent,  filldir_t filldir)
+int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
 {
         int result = 0;
-	struct dentry *cdentry;
-	struct inode *cinode, *inode = file->f_dentry->d_inode;
-	struct file *cfile, fakefile;
-	struct coda_inode_info *cii = ITOC(inode);
+	struct dentry *coda_dentry = coda_file->f_dentry;
+	struct inode *coda_inode = coda_dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(coda_inode);
+	struct file *host_file = cii->c_container;
 
-	coda_vfs_stat.readdir++;
+	if (!host_file) BUG();
 
-        cfile = cii->c_container;
-        if (!cfile) BUG();
+	coda_vfs_stat.readdir++;
 
-	cinode = cii->c_container->f_dentry->d_inode;
-	if ( S_ISREG(cinode->i_mode) ) {
-		/* Venus: we must read Venus dirents from the file */
-		cdentry = cii->c_container->f_dentry;
-		coda_prepare_fakefile(file, cdentry, &fakefile);
-
-		result = coda_venus_readdir(&fakefile, dirent, filldir);
-
-		file->f_pos = fakefile.f_pos;
-		file->f_version = fakefile.f_version;
-        } else {
-		/* potemkin case: we are handed a directory inode */
-		result = vfs_readdir(file, filldir, dirent);
-        }
+	/* Access to both host and coda f_pos fields is serialized on the
+	 * coda_file->f_dentry->d_inode->i_sem which has already been taken by
+	 * vfs_readdir. Userspace shouldn't 'play' with the container file as
+	 * long as the file is held open. */
+	host_file->f_pos = coda_file->f_pos;
+
+	if ( !host_file->f_op->readdir )
+		result = coda_venus_readdir(host_file, filldir, dirent,
+					    coda_dentry);
+	else
+		result = vfs_readdir(host_file, filldir, dirent);
 
-	UPDATE_ATIME(inode);
+	coda_file->f_pos = host_file->f_pos;
 	return result;
 }
 
 /* support routines */
-
-/* instantiate a fake file to pass to coda_venus_readdir */
-static void coda_prepare_fakefile(struct file *coda_file, 
-				  struct dentry *cont_dentry,
-				  struct file *fake_file)
-{
-	fake_file->f_dentry = cont_dentry;
-	fake_file->f_pos = coda_file->f_pos;
-	fake_file->f_version = coda_file->f_version;
-	fake_file->f_op = cont_dentry->d_inode->i_fop;
-	fake_file->f_flags = coda_file->f_flags;
-	return ;
-}
-
-/* 
- * this structure is manipulated by filldir in vfs layer.
- * the count holds the remaining amount of space in the getdents buffer,
- * beyond the current_dir pointer.
- *
- * What structure is this comment referring to?? -JH
- */
-
-/* should be big enough to hold any single directory entry */
-#define DIR_BUFSIZE 2048
-
-static int coda_venus_readdir(struct file *filp, void *getdent, 
-			      filldir_t filldir)
+static int coda_venus_readdir(struct file *filp, filldir_t filldir,
+			      void *dirent, struct dentry *dir)
 {
-        int bufsize;
-	int offset = filp->f_pos; /* offset in the directory file */
-	int count = 0;
-	int pos = 0;      /* offset in the block we read */
-	int result = 0; /* either an error or # of entries returned */
-	int errfill;
-        char *buff = NULL;
-        struct venus_dirent *vdirent;
-        int string_offset = (int) (&((struct venus_dirent *)(0))->d_name);
-	int i;
-
-        CODA_ALLOC(buff, char *, DIR_BUFSIZE);
-        if ( !buff ) { 
-                printk("coda_venus_readdir: out of memory.\n");
-                return -ENOMEM;
-        }
+	int result = 0; /* # of entries returned */
+	struct venus_dirent *vdir;
+	unsigned long vdir_size =
+	    (unsigned long)(&((struct venus_dirent *)0)->d_name);
+	struct qstr name;
+	ino_t ino;
+	int ret, i;
+
+	vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
+	if (!vdir) return -ENOMEM;
+
+	i = filp->f_pos;
+	switch(i) {
+	case 0:
+		ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
+		if (ret < 0) break;
+		result++;
+		filp->f_pos++;
+		/* fallthrough */
+	case 1:
+		ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
+		if (ret < 0) break;
+		result++;
+		filp->f_pos++;
+		/* fallthrough */
+	default:
+	while (1) {
+		/* read entries from the directory file */
+		ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
+				  sizeof(*vdir));
+		if (ret < 0) {
+			printk("coda_venus_readdir: read dir failed %d\n", ret);
+			break;
+		}
+		if (ret == 0) break; /* end of directory file reached */
 
-        /* we use this routine to read the file into our buffer */
-        bufsize = kernel_read(filp, filp->f_pos, buff, DIR_BUFSIZE);
-        if ( bufsize < 0) {
-                printk("coda_venus_readdir: cannot read directory %d.\n",
-		       bufsize);
-                result = bufsize;
-                goto exit;
-        }
-        if ( bufsize == 0) {
-                result = 0;
-                goto exit;
-        }
-	
-        /* Parse and write into user space. Filldir tells us when done! */
-        CDEBUG(D_FILE, "buffsize: %d offset %d, count %d.\n", 
-	       bufsize, offset, count);
-
-	i = 0;
-	result = 0; 
-        while ( pos + string_offset < bufsize && i < 1024) {
-                vdirent = (struct venus_dirent *) (buff + pos);
-
-                /* test if the name is fully in the buffer */
-                if ( pos + string_offset + (int) vdirent->d_namlen >= bufsize ){
-			if ( result == 0 )
-				printk("CODA: Invalid directory cfino: %ld\n", 
-				       filp->f_dentry->d_inode->i_ino);
-                        break;
-                }
-                /* now we are certain that we can read the entry from buff */
+		/* catch truncated reads */
+		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
+			printk("coda_venus_readdir: short read: %ld\n",
+			       filp->f_dentry->d_inode->i_ino);
+			ret = -EBADF;
+			break;
+		}
 
-                /* if we don't have a null entry, copy it */
-                if ( vdirent->d_fileno && vdirent->d_reclen ) {
-                        int namlen  = vdirent->d_namlen;
-                        off_t offs  = filp->f_pos; 
-                        ino_t ino   = vdirent->d_fileno;
-                        char *name  = vdirent->d_name;
-
-			errfill = filldir(getdent,  name, namlen, 
-					  offs, ino, DT_UNKNOWN); 
-CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos,  string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill);
-			/* errfill means no space for filling in this round */
-			if ( errfill < 0 ) {
-				result = 0;
-				break;
-			}
-                        /* adjust count */
-                        result++;
-                }
-                /* next one */
-                filp->f_pos += vdirent->d_reclen;
-		if ( filp->f_pos > filp->f_dentry->d_inode->i_size )
-			break; 
-		if ( !vdirent->d_reclen ) {
-			printk("CODA: Invalid directory, cfino: %ld\n", 
+		/* validate whether the directory entry makes sense */
+		if (vdir->d_reclen < vdir_size + vdir->d_namlen ||
+		    vdir->d_namlen > CODA_MAXNAMLEN) {
+			printk("coda_venus_readdir: Invalid dir: %ld\n",
 			       filp->f_dentry->d_inode->i_ino);
-			result = -EINVAL;
+			ret = -EBADF;
 			break;
 		}
-                pos += (unsigned int) vdirent->d_reclen;
-		i++;
-	} 
 
-	if ( i >= 1024 ) {
-		printk("Repeating too much in readdir %ld\n", 
-		       filp->f_dentry->d_inode->i_ino);
-		result = -EINVAL;
-	}
+		name.len = vdir->d_namlen;
+		name.name = vdir->d_name;
 
-exit:
-        CODA_FREE(buff, DIR_BUFSIZE);
-        return result;
+		/* Make sure we skip '.' and '..', we already got those */
+		if (name.name[0] == '.' && (name.len == 1 ||
+		    (vdir->d_name[1] == '.' && name.len == 2)))
+			vdir->d_fileno = name.len = 0;
+
+		/* skip null entries */
+		if (vdir->d_fileno && name.len) {
+			/* try to look for this entry in the dcache, that way
+			 * userspace doesn't have to worry about breaking old
+			 * getcwd implementation by having mismatched inode
+			 * numbers for internal volume mountpoints. */
+			ino = find_inode_number(dir, &name);
+			if (!ino) ino = vdir->d_fileno;
+
+			ret = filldir(dirent, name.name, name.len, filp->f_pos,
+				      ino, DT_UNKNOWN);
+			if (ret < 0) break;
+			result++;
+		}
+		/* we'll always have progress because d_reclen is unsigned and
+		 * we've already established it is non-zero. */
+		filp->f_pos += vdir->d_reclen;
+	}
+	} 
+	kfree(vdir);
+	return result ? result : ret;
 }
 
 /* called when a cache lookup succeeds */
@@ -754,8 +714,7 @@
 		if (inode->i_ino != old_ino)
 			goto return_bad_inode;
 		
-		if ( cii->c_flags ) 
-			coda_flag_inode_children(inode, C_FLUSH);
+		coda_flag_inode_children(inode, C_FLUSH);
 		
 		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
 	}
diff -urN linux-2.4.19-pre4/fs/coda/file.c linux-2.4.19-pre5/fs/coda/file.c
--- linux-2.4.19-pre4/fs/coda/file.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre5/fs/coda/file.c	Fri Mar 29 14:50:07 2002
@@ -76,6 +76,7 @@
 
 	cfile->f_flags = flags;
 	inode->i_size = cinode->i_size;
+	inode->i_blocks = (inode->i_size + 511) >> 9;
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	up(&inode->i_sem);
 
diff -urN linux-2.4.19-pre4/fs/ext2/inode.c linux-2.4.19-pre5/fs/ext2/inode.c
--- linux-2.4.19-pre4/fs/ext2/inode.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre5/fs/ext2/inode.c	Fri Mar 29 14:50:07 2002
@@ -407,10 +407,10 @@
 		mark_buffer_uptodate(bh, 1);
 		unlock_buffer(bh);
 		mark_buffer_dirty_inode(bh, inode);
-		if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
-			ll_rw_block (WRITE, 1, &bh);
-			wait_on_buffer (bh);
-		}
+		/* We used to sync bh here if IS_SYNC(inode).
+		 * But we now rely upon generic_osync_inode()
+		 * and b_inode_buffers
+		 */
 		parent = nr;
 	}
 	if (n == num)
@@ -469,18 +469,10 @@
 	inode->i_ctime = CURRENT_TIME;
 
 	/* had we spliced it onto indirect block? */
-	if (where->bh) {
+	if (where->bh)
 		mark_buffer_dirty_inode(where->bh, inode);
-		if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
-			ll_rw_block (WRITE, 1, &where->bh);
-			wait_on_buffer(where->bh);
-		}
-	}
 
-	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
-		ext2_sync_inode (inode);
-	else
-		mark_inode_dirty(inode);
+	mark_inode_dirty(inode);
 	return 0;
 
 changed:
@@ -837,10 +829,6 @@
 				   (u32*)partial->bh->b_data + addr_per_block,
 				   (chain+n-1) - partial);
 		mark_buffer_dirty_inode(partial->bh, inode);
-		if (IS_SYNC(inode)) {
-			ll_rw_block (WRITE, 1, &partial->bh);
-			wait_on_buffer (partial->bh);
-		}
 		brelse (partial->bh);
 		partial--;
 	}
@@ -872,10 +860,12 @@
 			;
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	if (IS_SYNC(inode))
+	if (IS_SYNC(inode)) {
+		fsync_inode_buffers(inode);
 		ext2_sync_inode (inode);
-	else
+	} else {
 		mark_inode_dirty(inode);
+	}
 }
 
 void ext2_read_inode (struct inode * inode)
diff -urN linux-2.4.19-pre4/fs/ext3/inode.c linux-2.4.19-pre5/fs/ext3/inode.c
--- linux-2.4.19-pre4/fs/ext3/inode.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre5/fs/ext3/inode.c	Fri Mar 29 14:50:07 2002
@@ -581,8 +581,6 @@
 			
 			parent = nr;
 		}
-		if (IS_SYNC(inode))
-			handle->h_sync = 1;
 	}
 	if (n == num)
 		return 0;
diff -urN linux-2.4.19-pre4/fs/jffs2/build.c linux-2.4.19-pre5/fs/jffs2/build.c
--- linux-2.4.19-pre4/fs/jffs2/build.c	Fri Sep 14 14:04:07 2001
+++ linux-2.4.19-pre5/fs/jffs2/build.c	Fri Mar 29 14:50:07 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: build.c,v 1.16 2001/03/15 15:38:23 dwmw2 Exp $
+ * $Id: build.c,v 1.16.2.2 2002/03/12 15:36:43 dwmw2 Exp $
  *
  */
 
@@ -59,7 +59,11 @@
 
 	/* First, scan the medium and build all the inode caches with
 	   lists of physical nodes */
+
+	c->flags |= JFFS2_SB_FLAG_MOUNTING;
 	ret = jffs2_scan_medium(c);
+	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
+
 	if (ret)
 		return ret;
 
@@ -201,6 +205,10 @@
 
 		if (child_ic->nlink++ && fd->type == DT_DIR) {
 			printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
+			if (fd->ino == 1 && ic->ino == 1) {
+				printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
+				printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
+			}
 			/* What do we do about it? */
 		}
 		D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
diff -urN linux-2.4.19-pre4/fs/jffs2/readinode.c linux-2.4.19-pre5/fs/jffs2/readinode.c
--- linux-2.4.19-pre4/fs/jffs2/readinode.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/fs/jffs2/readinode.c	Fri Mar 29 14:50:07 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: readinode.c,v 1.58.2.2 2002/02/23 14:25:37 dwmw2 Exp $
+ * $Id: readinode.c,v 1.58.2.5 2002/03/05 22:40:03 dwmw2 Exp $
  *
  */
 
@@ -252,6 +252,7 @@
 	struct jffs2_sb_info *c;
 	struct jffs2_raw_inode latest_node;
 	__u32 latest_mctime, mctime_ver;
+	__u32 mdata_ver = 0;
 	int ret;
 	ssize_t retlen;
 
@@ -299,8 +300,6 @@
 	f->dents = fd_list;
 
 	while (tn_list) {
-		static __u32 mdata_ver = 0;
-
 		tn = tn_list;
 
 		fn = tn->fn;
@@ -472,6 +471,8 @@
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	down(&f->sem);
+
 	frags = f->fraglist;
 	fds = f->dents;
 	if (f->metadata) {
@@ -499,10 +500,7 @@
 		fds = fd->next;
 		jffs2_free_full_dirent(fd);
 	}
-	//	if (!f->inocache->nlink) {
-		//		D1(printk(KERN_DEBUG "jffs2_clear_inode() deleting inode #%lu\n", inode->i_ino));
-		//		jffs2_del_ino_cache(JFFS2_SB_INFO(inode->i_sb), f->inocache);
-		//		jffs2_free_inode_cache(f->inocache);
-	//	}
+
+	up(&f->sem);
 };
 
diff -urN linux-2.4.19-pre4/fs/jffs2/super.c linux-2.4.19-pre5/fs/jffs2/super.c
--- linux-2.4.19-pre4/fs/jffs2/super.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/fs/jffs2/super.c	Fri Mar 29 14:50:07 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: super.c,v 1.48.2.1 2002/02/23 14:13:34 dwmw2 Exp $
+ * $Id: super.c,v 1.48.2.2 2002/03/12 15:36:43 dwmw2 Exp $
  *
  */
 
@@ -245,15 +245,11 @@
 	INIT_LIST_HEAD(&c->bad_used_list);
 	c->highest_ino = 1;
 
-	c->flags |= JFFS2_SB_FLAG_MOUNTING;
-
 	if (jffs2_build_filesystem(c)) {
 		D1(printk(KERN_DEBUG "build_fs failed\n"));
 		goto out_nodes;
 	}
 
-	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
-
 	sb->s_op = &jffs2_super_operations;
 
 	D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
diff -urN linux-2.4.19-pre4/fs/open.c linux-2.4.19-pre5/fs/open.c
--- linux-2.4.19-pre4/fs/open.c	Fri Oct 12 13:48:42 2001
+++ linux-2.4.19-pre5/fs/open.c	Fri Mar 29 14:50:07 2002
@@ -71,6 +71,30 @@
 	return error;
 }
 
+/*
+ * Install a file pointer in the fd array.  
+ *
+ * The VFS is full of places where we drop the files lock between
+ * setting the open_fds bitmap and installing the file in the file
+ * array.  At any such point, we are vulnerable to a dup2() race
+ * installing a file in the array before us.  We need to detect this and
+ * fput() the struct file we are about to overwrite in this case.
+ *
+ * It should never happen - if we allow dup2() do it, _really_ bad things
+ * will follow.
+ */
+
+void fd_install(unsigned int fd, struct file * file)
+{
+	struct files_struct *files = current->files;
+	
+	write_lock(&files->file_lock);
+	if (files->fd[fd])
+		BUG();
+	files->fd[fd] = file;
+	write_unlock(&files->file_lock);
+}
+
 int do_truncate(struct dentry *dentry, loff_t length)
 {
 	struct inode *inode = dentry->d_inode;
diff -urN linux-2.4.19-pre4/fs/proc/root.c linux-2.4.19-pre5/fs/proc/root.c
--- linux-2.4.19-pre4/fs/proc/root.c	Sat Oct 20 19:14:42 2001
+++ linux-2.4.19-pre5/fs/proc/root.c	Fri Mar 29 14:50:07 2002
@@ -58,6 +58,12 @@
 #ifdef CONFIG_PROC_DEVICETREE
 	proc_device_tree_init();
 #endif
+#ifdef CONFIG_PPC_ISERIES
+	iSeries_proc_create();
+#endif
+#ifdef CONFIG_PPC64
+	proc_ppc64_init(); 
+#endif
 #ifdef CONFIG_PPC_RTAS
 	proc_rtas_init();
 #endif
diff -urN linux-2.4.19-pre4/fs/super.c linux-2.4.19-pre5/fs/super.c
--- linux-2.4.19-pre4/fs/super.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/fs/super.c	Fri Mar 29 14:50:07 2002
@@ -762,7 +762,7 @@
 
 	/* Forget any remaining inodes */
 	if (invalidate_inodes(sb)) {
-		printk("VFS: Busy inodes after unmount. "
+		printk(KERN_ERR "VFS: Busy inodes after unmount. "
 			"Self-destruct in 5 seconds.  Have a nice day...\n");
 	}
 
diff -urN linux-2.4.19-pre4/include/asm-alpha/core_tsunami.h linux-2.4.19-pre5/include/asm-alpha/core_tsunami.h
--- linux-2.4.19-pre4/include/asm-alpha/core_tsunami.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.19-pre5/include/asm-alpha/core_tsunami.h	Fri Mar 29 14:50:07 2002
@@ -288,7 +288,7 @@
 #ifdef __KERNEL__
 
 #ifndef __EXTERN_INLINE
-#define __EXTERN_INLINE extern inline
+#define __EXTERN_INLINE static inline
 #define __IO_EXTERN_INLINE
 #endif
 
diff -urN linux-2.4.19-pre4/include/asm-alpha/core_wildfire.h linux-2.4.19-pre5/include/asm-alpha/core_wildfire.h
--- linux-2.4.19-pre4/include/asm-alpha/core_wildfire.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.19-pre5/include/asm-alpha/core_wildfire.h	Fri Mar 29 14:50:07 2002
@@ -269,7 +269,7 @@
 #ifdef __KERNEL__
 
 #ifndef __EXTERN_INLINE
-#define __EXTERN_INLINE extern inline
+#define __EXTERN_INLINE static inline
 #define __IO_EXTERN_INLINE
 #endif
 
diff -urN linux-2.4.19-pre4/include/asm-alpha/pgtable.h linux-2.4.19-pre5/include/asm-alpha/pgtable.h
--- linux-2.4.19-pre4/include/asm-alpha/pgtable.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/asm-alpha/pgtable.h	Fri Mar 29 14:50:07 2002
@@ -194,8 +194,8 @@
 #define PAGE_TO_PA(page)	((page - mem_map) << PAGE_SHIFT)
 #else
 #define PAGE_TO_PA(page) \
-		((((page)-(page)->zone->zone_mem_map) << PAGE_SHIFT) \
-		+ (page)->zone->zone_start_paddr)
+		((((page)-page_zone(page)->zone_mem_map) << PAGE_SHIFT) \
+		+ page_zone(page)->zone_start_paddr)
 #endif
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -213,8 +213,8 @@
 	pte_t pte;								\
 	unsigned long pfn;							\
 										\
-	pfn = ((unsigned long)((page)-(page)->zone->zone_mem_map)) << 32;	\
-	pfn += (page)->zone->zone_start_paddr << (32-PAGE_SHIFT);		\
+	pfn = ((unsigned long)((page)-page_zone(page)->zone_mem_map)) << 32;	\
+	pfn += page_zone(page)->zone_start_paddr << (32-PAGE_SHIFT);		\
 	pte_val(pte) = pfn | pgprot_val(pgprot);				\
 										\
 	pte;									\
diff -urN linux-2.4.19-pre4/include/asm-alpha/unistd.h linux-2.4.19-pre5/include/asm-alpha/unistd.h
--- linux-2.4.19-pre4/include/asm-alpha/unistd.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/asm-alpha/unistd.h	Fri Mar 29 14:50:07 2002
@@ -530,8 +530,8 @@
 	return sys_close(fd);
 }
 
-extern off_t sys_lseek(int, off_t, int);
-static inline off_t lseek(int fd, off_t off, int whense)
+extern off_t sys_lseek(unsigned int, off_t, unsigned int);
+static inline off_t lseek(unsigned int fd, off_t off, unsigned int whense)
 {
 	return sys_lseek(fd, off, whense);
 }
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-anakin/ide.h linux-2.4.19-pre5/include/asm-arm/arch-anakin/ide.h
--- linux-2.4.19-pre4/include/asm-arm/arch-anakin/ide.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-anakin/ide.h	Fri Mar 29 14:50:07 2002
@@ -7,7 +7,6 @@
  *              (jonm@bluemug.com).
  */
  
-#include <linux/config.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
 
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-anakin/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-anakin/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-anakin/uncompress.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-anakin/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -14,6 +14,7 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H
 
+#include <linux/config.h>
 #include <asm/io.h>
 #include <asm/arch/serial_reg.h>
 
@@ -24,7 +25,9 @@
 static inline void
 putc(int c)
 {
-	while (!(__raw_readl(IO_START + UART0 + 0x10) & TXEMPTY));
+	while (!(__raw_readl(IO_START + UART0 + 0x10) & TXEMPTY))
+		barrier();
+
 	__raw_writel(c, IO_START + UART0 + 0x14);
 	__raw_writel(__raw_readl(IO_START + UART0 + 0x18)
 			| SENDREQUEST, IO_START + UART0 + 0x18);
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-cl7500/keyboard.h linux-2.4.19-pre5/include/asm-arm/arch-cl7500/keyboard.h
--- linux-2.4.19-pre4/include/asm-arm/arch-cl7500/keyboard.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-cl7500/keyboard.h	Fri Mar 29 14:50:07 2002
@@ -6,6 +6,7 @@
  *
  * Copyright (C) 1998-2001 Russell King
  */
+#include <asm/irq.h>
 #define NR_SCANCODES 128
 
 extern int ps2kbd_init_hw(void);
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-cl7500/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-cl7500/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-cl7500/uncompress.h	Thu Apr 12 12:20:31 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-cl7500/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -9,7 +9,8 @@
 
 static __inline__ void putc(char c)
 {
-	while (!(*((volatile unsigned int *)(SERBASE + 0x14)) & 0x20));
+	while (!(*((volatile unsigned int *)(SERBASE + 0x14)) & 0x20))
+		barrier();
 	*((volatile unsigned int *)(SERBASE)) = c;
 }
 
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/autcpu12.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/autcpu12.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/autcpu12.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/autcpu12.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,78 @@
+/*
+ * AUTCPU12 specific defines
+ *
+ * (c) 2001 Thomas Gleixner, autronix automation <gleixner@autronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_AUTCPU12_H
+#define __ASM_ARCH_AUTCPU12_H
+
+/*
+ * The CS8900A ethernet chip has its I/O registers wired to chip select 2
+ * (nCS2). This is the mapping for it.
+ */
+#define AUTCPU12_PHYS_CS8900A		CS2_PHYS_BASE		/* physical */
+#define AUTCPU12_VIRT_CS8900A		(0xfe000000)		/* virtual */
+
+/*
+ * The flash bank is wired to chip select 0
+ */
+#define AUTCPU12_PHYS_FLASH		CS0_PHYS_BASE		/* physical */
+
+/* offset for device specific information structure */
+#define AUTCPU12_LCDINFO_OFFS		(0x00010000)	
+/*
+* Videomemory is the internal SRAM (CS 6)	
+*/
+#define AUTCPU12_PHYS_VIDEO		CS6_PHYS_BASE
+#define AUTCPU12_VIRT_VIDEO		(0xfd000000)
+
+/*
+* All special IO's are tied to CS1
+*/
+#define AUTCPU12_PHYS_CHAR_LCD         	CS1_PHYS_BASE +0x00000000  /* physical */
+
+#define AUTCPU12_PHYS_NVRAM            	CS1_PHYS_BASE +0x02000000  /* physical */
+
+#define AUTCPU12_PHYS_CSAUX1           	CS1_PHYS_BASE +0x04000000  /* physical */
+
+#define AUTCPU12_PHYS_SMC              	CS1_PHYS_BASE +0x06000000  /* physical */
+
+#define AUTCPU12_PHYS_CAN              	CS1_PHYS_BASE +0x08000000  /* physical */
+
+#define AUTCPU12_PHYS_TOUCH            	CS1_PHYS_BASE +0x0A000000  /* physical */
+
+#define AUTCPU12_PHYS_IO               	CS1_PHYS_BASE +0x0C000000  /* physical */
+
+#define AUTCPU12_PHYS_LPT              	CS1_PHYS_BASE +0x0E000000  /* physical */
+
+/* 
+* defines for smartmedia card access 
+*/
+#define AUTCPU12_SMC_RDY		(1<<2)
+#define AUTCPU12_SMC_ALE		(1<<3)
+#define AUTCPU12_SMC_CLE  		(1<<4)
+#define AUTCPU12_SMC_PORT_OFFSET	PBDR
+#define AUTCPU12_SMC_SELECT_OFFSET 	0x10
+/*
+* defines for lcd contrast 
+*/
+#define AUTCPU12_DPOT_PORT_OFFSET	PEDR
+#define	AUTCPU12_DPOT_CS		(1<<0)
+#define AUTCPU12_DPOT_CLK    		(1<<1)
+#define	AUTCPU12_DPOT_UD		(1<<2)
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/dma.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/dma.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/dma.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/dma.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/dma.h
+ *
+ *  Copyright (C) 1997,1998 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+#define MAX_DMA_ADDRESS		0xffffffff
+
+#define MAX_DMA_CHANNELS	0
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/hardware.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/hardware.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/hardware.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,179 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/hardware.h
+ *
+ *  This file contains the hardware definitions of the Prospector P720T.
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <linux/config.h>
+
+#define CLPS7111_VIRT_BASE	0xff000000
+#define CLPS7111_BASE		CLPS7111_VIRT_BASE
+
+/*
+ * The physical addresses that the external chip select signals map to is
+ * dependent on the setting of the nMEDCHG signal on EP7211 and EP7212
+ * processors.  CONFIG_EP72XX_BOOT_ROM is only available if these
+ * processors are in use.
+ */
+#ifndef CONFIG_EP72XX_ROM_BOOT
+#define CS0_PHYS_BASE		(0x00000000)
+#define CS1_PHYS_BASE		(0x10000000)
+#define CS2_PHYS_BASE		(0x20000000)
+#define CS3_PHYS_BASE		(0x30000000)
+#define CS4_PHYS_BASE		(0x40000000)
+#define CS5_PHYS_BASE		(0x50000000)
+#define CS6_PHYS_BASE		(0x60000000)
+#define CS7_PHYS_BASE		(0x70000000)
+#else
+#define CS0_PHYS_BASE		(0x70000000)
+#define CS1_PHYS_BASE		(0x60000000)
+#define CS2_PHYS_BASE		(0x50000000)
+#define CS3_PHYS_BASE		(0x40000000)
+#define CS4_PHYS_BASE		(0x30000000)
+#define CS5_PHYS_BASE		(0x20000000)
+#define CS6_PHYS_BASE		(0x10000000)
+#define CS7_PHYS_BASE		(0x00000000)
+#endif
+
+#if defined (CONFIG_ARCH_EP7211)
+
+#define EP7211_VIRT_BASE	CLPS7111_VIRT_BASE
+#define EP7211_BASE		CLPS7111_VIRT_BASE
+#include <asm/hardware/ep7211.h>
+
+#elif defined (CONFIG_ARCH_EP7212)
+
+#define EP7212_VIRT_BASE	CLPS7111_VIRT_BASE
+#define EP7212_BASE		CLPS7111_VIRT_BASE
+#include <asm/hardware/ep7212.h>
+
+
+#endif
+
+#define SYSPLD_VIRT_BASE	0xfe000000
+#define SYSPLD_BASE		SYSPLD_VIRT_BASE
+
+#ifndef __ASSEMBLER__
+
+#define PCIO_BASE		IO_BASE
+
+#endif
+
+
+#if  defined (CONFIG_ARCH_AUTCPU12)
+
+#define  CS89712_VIRT_BASE	CLPS7111_VIRT_BASE
+#define  CS89712_BASE		CLPS7111_VIRT_BASE
+
+#include <asm/hardware/clps7111.h>
+#include <asm/hardware/ep7212.h>
+#include <asm/hardware/cs89712.h>
+
+#endif
+
+
+#if defined (CONFIG_ARCH_CDB89712)
+
+#include <asm/hardware/clps7111.h>
+#include <asm/hardware/ep7212.h>
+#include <asm/hardware/cs89712.h>
+
+/* dynamic ioremap() areas */
+#define FLASH_START      0x00000000
+#define FLASH_SIZE       0x800000
+#define FLASH_WIDTH      4
+
+#define SRAM_START       0x60000000
+#define SRAM_SIZE        0xc000
+#define SRAM_WIDTH       4
+
+#define BOOTROM_START    0x70000000
+#define BOOTROM_SIZE     0x80
+#define BOOTROM_WIDTH    4
+
+
+/* static cdb89712_map_io() areas */
+#define REGISTER_START   0x80000000
+#define REGISTER_SIZE    0x4000
+#define REGISTER_BASE    0xff000000
+
+#define ETHER_START      0x20000000
+#define ETHER_SIZE       0x1000
+#define ETHER_BASE       0xfe000000
+
+#endif
+
+
+#if defined (CONFIG_ARCH_EDB7211)
+
+/*
+ * The extra 8 lines of the keyboard matrix are wired to chip select 3 (nCS3) 
+ * and repeat across it. This is the mapping for it.
+ *
+ * In jumpered boot mode, nCS3 is mapped to 0x4000000, not 0x3000000. This 
+ * was cause for much consternation and headscratching. This should probably
+ * be made a compile/run time kernel option.
+ */
+#define EP7211_PHYS_EXTKBD		CS3_PHYS_BASE	/* physical */
+
+#define EP7211_VIRT_EXTKBD		(0xfd000000)	/* virtual */
+
+
+/*
+ * The CS8900A ethernet chip has its I/O registers wired to chip select 2 
+ * (nCS2). This is the mapping for it.
+ *
+ * In jumpered boot mode, nCS2 is mapped to 0x5000000, not 0x2000000. This 
+ * was cause for much consternation and headscratching. This should probably
+ * be made a compile/run time kernel option.
+ */
+#define EP7211_PHYS_CS8900A		CS2_PHYS_BASE	/* physical */
+
+#define EP7211_VIRT_CS8900A		(0xfc000000)	/* virtual */
+
+
+/*
+ * The two flash banks are wired to chip selects 0 and 1. This is the mapping
+ * for them.
+ *
+ * nCS0 and nCS1 are at 0x70000000 and 0x60000000, respectively, when running
+ * in jumpered boot mode.
+ */
+#define EP7211_PHYS_FLASH1		CS0_PHYS_BASE	/* physical */
+#define EP7211_PHYS_FLASH2		CS1_PHYS_BASE	/* physical */
+
+#define EP7211_VIRT_FLASH1		(0xfa000000)	/* virtual */
+#define EP7211_VIRT_FLASH2		(0xfb000000)	/* virtual */
+
+#endif /* CONFIG_ARCH_EDB7211 */
+
+
+/*
+ * Relevant bits in port D, which controls power to the various parts of
+ * the LCD on the EDB7211.
+ */
+#define EDB_PD1_LCD_DC_DC_EN	(1<<1)
+#define EDB_PD2_LCDEN		(1<<2)
+#define EDB_PD3_LCDBL		(1<<3)
+
+
+#endif
+
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/io.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/io.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/io.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/io.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,50 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/io.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)			((a))
+#define __mem_pci(a)		((unsigned long)(a))
+#define __mem_isa(a)		((unsigned long)(a))
+
+/*
+ * Generic virtual read/write
+ */
+#define __arch_getw(a)		(*(volatile unsigned short *)(a))
+#define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
+
+/*
+ * ioremap support - validate a PCI memory address, and convert it
+ * to a physical address for the page tables.
+ */
+#define iomem_valid_addr(iomem,size)	(1)
+#define iomem_to_phys(iomem)		(iomem)
+
+/*
+ * We don't support ins[lb]/outs[lb].  Make them fault.
+ */
+#define __raw_readsb(p,d,l)	do { *(int *)0 = 0; } while (0)
+#define __raw_readsl(p,d,l)	do { *(int *)0 = 0; } while (0)
+#define __raw_writesb(p,d,l)	do { *(int *)0 = 0; } while (0)
+#define __raw_writesl(p,d,l)	do { *(int *)0 = 0; } while (0)
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/irq.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/irq.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/irq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/irq.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,20 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/irq.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#define fixup_irq(i)	(i)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/irqs.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/irqs.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/irqs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/irqs.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,53 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/irqs.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Interrupts from INTSR1
+ */
+#define IRQ_CSINT			4
+#define IRQ_EINT1			5
+#define IRQ_EINT2			6
+#define IRQ_EINT3			7
+#define IRQ_TC1OI			8
+#define IRQ_TC2OI			9
+#define IRQ_RTCMI			10
+#define IRQ_TINT			11
+#define IRQ_UTXINT1			12
+#define IRQ_URXINT1			13
+#define IRQ_UMSINT			14
+#define IRQ_SSEOTI			15
+
+#define INT1_IRQS			(0x0000fff0)
+#define INT1_ACK_IRQS			(0x00004f10)
+
+/*
+ * Interrupts from INTSR2
+ */
+#define IRQ_KBDINT			(16+0)	/* bit 0 */
+#define IRQ_SS2RX			(16+1)	/* bit 1 */
+#define IRQ_SS2TX			(16+2)	/* bit 2 */
+#define IRQ_UTXINT2			(16+12)	/* bit 12 */
+#define IRQ_URXINT2			(16+13)	/* bit 13 */
+
+#define INT2_IRQS			(0x30070000)
+#define INT2_ACK_IRQS			(0x00010000)
+
+#define NR_IRQS                         30
+
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/keyboard.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/keyboard.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/keyboard.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/arch-clps711x/keyboard.h
+ *
+ * Copyright (C) 1998-2001 Russell King
+ */
+#include <asm/mach-types.h>
+
+#define NR_SCANCODES 128
+
+#define kbd_disable_irq()	do { } while (0)
+#define kbd_enable_irq()	do { } while (0)
+
+/*
+ * EDB7211 keyboard driver
+ */
+extern void edb7211_kbd_init_hw(void);
+extern void clps711x_kbd_init_hw(void);
+
+static inline void kbd_init_hw(void)
+{
+	if (machine_is_edb7211())
+		edb7211_kbd_init_hw();
+
+	if (machine_is_autcpu12())
+		clps711x_kbd_init_hw();
+}
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/memory.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/memory.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/memory.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/memory.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,206 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/mmu.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+#include <linux/config.h>
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+#define PHYS_OFFSET	(0xc0000000UL)
+
+/*
+ * On integrator, the dram is contiguous
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET)
+
+/*
+ * 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.
+ */
+
+#if defined(CONFIG_ARCH_CDB89712)
+
+#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)
+
+#elif defined (CONFIG_ARCH_AUTCPU12)
+
+#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)
+
+#else
+
+#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
+
+
+/*
+ * Like the SA1100, the EDB7211 has a large gap between physical RAM
+ * banks.  In 2.2, the Psion (CL-PS7110) port added custom support for
+ * discontiguous physical memory.  In 2.4, we can use the standard
+ * Linux NUMA support.
+ *
+ * This is not necessary for EP7211 implementations with only one used
+ * memory bank.  For those systems, simply undefine CONFIG_DISCONTIGMEM.
+ */
+
+#ifdef CONFIG_ARCH_EDB7211
+
+#ifdef CONFIG_DISCONTIGMEM
+/*
+ * Because of the wide memory address space between physical RAM banks on the 
+ * SA1100, it's much more convenient to use Linux's NUMA support to implement
+ * our memory map representation.  Assuming all memory nodes have equal access 
+ * characteristics, we then have generic discontigous memory support.
+ *
+ * Of course, all this isn't mandatory for SA1100 implementations with only
+ * one used memory bank.  For those, simply undefine CONFIG_DISCONTIGMEM.
+ *
+ * The nodes are matched with the physical memory bank addresses which are 
+ * incidentally the same as virtual addresses.
+ * 
+ * 	node 0:  0xc0000000 - 0xc7ffffff
+ * 	node 1:  0xc8000000 - 0xcfffffff
+ * 	node 2:  0xd0000000 - 0xd7ffffff
+ * 	node 3:  0xd8000000 - 0xdfffffff
+ */
+
+#define NR_NODES	4
+
+/*
+ * Given a kernel address, find the home node of the underlying memory.
+ */
+#define KVADDR_TO_NID(addr) \
+		(((unsigned long)(addr) - PAGE_OFFSET) >> NODE_MAX_MEM_SHIFT)
+
+/*
+ * Given a physical address, convert it to a node id.
+ */
+#define PHYS_TO_NID(addr) KVADDR_TO_NID(__phys_to_virt(addr))
+
+/*
+ * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
+ * and returns the mem_map of that node.
+ */
+#define ADDR_TO_MAPBASE(kaddr) \
+			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
+
+/*
+ * Given a kaddr, LOCAL_MAR_NR finds the owning node of the memory
+ * and returns the index corresponding to the appropriate page in the
+ * node's mem_map.
+ */
+#define LOCAL_MAP_NR(kaddr) \
+	(((unsigned long)(kaddr)-LOCAL_BASE_ADDR((kaddr))) >> PAGE_SHIFT)
+
+/*
+ * Given a kaddr, virt_to_page returns a pointer to the corresponding 
+ * mem_map entry.
+ */
+#define virt_to_page(kaddr) \
+	(ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr))
+
+/*
+ * VALID_PAGE returns a non-zero value if given page pointer is valid.
+ * This assumes all node's mem_maps are stored within the node they refer to.
+ */
+#define VALID_PAGE(page) \
+({ unsigned int node = KVADDR_TO_NID(page); \
+   ( (node < NR_NODES) && \
+     ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size) ); \
+})
+
+/*
+ * The PS7211 allows up to 256MB max per DRAM bank, but the EDB7211
+ * uses only one of the two banks (bank #1).  However, even within
+ * bank #1, memory is discontiguous.
+ *
+ * The EDB7211 has two 8MB DRAM areas with 8MB of empty space between
+ * them, so we use 24 for the node max shift to get 16MB node sizes.
+ */
+#define NODE_MAX_MEM_SHIFT	24
+#define NODE_MAX_MEM_SIZE	(1<<NODE_MAX_MEM_SHIFT)
+
+/*
+ * Given a mem_map_t, LOCAL_MAP_BASE finds the owning node for the
+ * physical page and returns the kaddr for the mem_map of that node.
+ */
+#define LOCAL_MAP_BASE(page) \
+			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(page)))
+
+/*
+ * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory
+ * and returns the kaddr corresponding to first physical page in the
+ * node's mem_map.
+ */
+#define LOCAL_BASE_ADDR(kaddr)	((unsigned long)(kaddr) & ~(NODE_MAX_MEM_SIZE-1))
+
+/* 
+ * With discontigmem, the conceptual mem_map array starts from PAGE_OFFSET.
+ * Given a kaddr, MAP_NR returns the appropriate global mem_map index so 
+ * it matches the corresponding node's local mem_map.
+ */
+#define MAP_NR(kaddr)	(LOCAL_MAP_NR((kaddr)) + \
+		(((unsigned long)ADDR_TO_MAPBASE((kaddr)) - PAGE_OFFSET) / \
+		sizeof(mem_map_t)))
+
+#else
+
+#define PHYS_TO_NID(addr)	(0)
+
+#endif /* CONFIG_DISCONTIGMEM */
+
+#endif	/* CONFIG_ARCH_EDB7211 */
+
+#ifndef PHYS_TO_NID
+#define PHYS_TO_NID(addr)	(0)
+#endif
+
+#endif
+
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/param.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/param.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/param.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/param.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,21 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/param.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define HZ 100
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/syspld.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/syspld.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/syspld.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/syspld.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,121 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/syspld.h
+ *
+ *  System Control PLD register definitions.
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_SYSPLD_H
+#define __ASM_ARCH_SYSPLD_H
+
+#define SYSPLD_PHYS_BASE	(0x10000000)
+
+#ifndef __ASSEMBLY__
+#include <asm/types.h>
+
+#define SYSPLD_REG(type,off)	(*(volatile type *)(SYSPLD_BASE + off))
+#else
+#define SYSPLD_REG(type,off)	(off)
+#endif
+
+#define PLD_INT		SYSPLD_REG(u32, 0x000000)
+#define PLD_INT_PENIRQ		(1 << 5)
+#define PLD_INT_UCB_IRQ		(1 << 1)
+#define PLD_INT_KBD_ATN		(1 << 0)	/* EINT1 */
+
+#define PLD_PWR		SYSPLD_REG(u32, 0x000004)
+#define PLD_PWR_EXT		(1 << 5)
+#define PLD_PWR_MODE		(1 << 4)	/* 1 = PWM, 0 = PFM */
+#define PLD_S4_ON		(1 << 3)	/* LCD bias voltage enable */
+#define PLD_S3_ON		(1 << 2)	/* LCD backlight enable */
+#define PLD_S2_ON		(1 << 1)	/* LCD 3V3 supply enable */
+#define PLD_S1_ON		(1 << 0)	/* LCD 3V supply enable */
+
+#define PLD_KBD		SYSPLD_REG(u32, 0x000008)
+#define PLD_KBD_WAKE		(1 << 1)
+#define PLD_KBD_EN		(1 << 0)
+
+#define PLD_SPI		SYSPLD_REG(u32, 0x00000c)
+#define PLD_SPI_EN		(1 << 0)
+
+#define PLD_IO		SYSPLD_REG(u32, 0x000010)
+#define PLD_IO_BOOTSEL		(1 << 6)	/* boot sel switch */
+#define PLD_IO_USER		(1 << 5)	/* user defined switch */
+#define PLD_IO_LED3		(1 << 4)
+#define PLD_IO_LED2		(1 << 3)
+#define PLD_IO_LED1		(1 << 2)
+#define PLD_IO_LED0		(1 << 1)
+#define PLD_IO_LEDEN		(1 << 0)
+
+#define PLD_IRDA	SYSPLD_REG(u32, 0x000014)
+#define PLD_IRDA_EN		(1 << 0)
+
+#define PLD_COM2	SYSPLD_REG(u32, 0x000018)
+#define PLD_COM2_EN		(1 << 0)
+
+#define PLD_COM1	SYSPLD_REG(u32, 0x00001c)
+#define PLD_COM1_EN		(1 << 0)
+
+#define PLD_AUD		SYSPLD_REG(u32, 0x000020)
+#define PLD_AUD_DIV1		(1 << 6)
+#define PLD_AUD_DIV0		(1 << 5)
+#define PLD_AUD_CLK_SEL1	(1 << 4)
+#define PLD_AUD_CLK_SEL0	(1 << 3)
+#define PLD_AUD_MIC_PWR		(1 << 2)
+#define PLD_AUD_MIC_GAIN	(1 << 1)
+#define PLD_AUD_CODEC_EN	(1 << 0)
+
+#define PLD_CF		SYSPLD_REG(u32, 0x000024)
+#define PLD_CF2_SLEEP		(1 << 5)
+#define PLD_CF1_SLEEP		(1 << 4)
+#define PLD_CF2_nPDREQ		(1 << 3)
+#define PLD_CF1_nPDREQ		(1 << 2)
+#define PLD_CF2_nIRQ		(1 << 1)
+#define PLD_CF1_nIRQ		(1 << 0)
+
+#define PLD_SDC		SYSPLD_REG(u32, 0x000028)
+#define PLD_SDC_INT_EN		(1 << 2)
+#define PLD_SDC_WP		(1 << 1)
+#define PLD_SDC_CD		(1 << 0)
+
+#define PLD_FPGA	SYSPLD_REG(u32, 0x00002c)
+
+#define PLD_CODEC	SYSPLD_REG(u32, 0x400000)
+#define PLD_CODEC_IRQ3		(1 << 4)
+#define PLD_CODEC_IRQ2		(1 << 3)
+#define PLD_CODEC_IRQ1		(1 << 2)
+#define PLD_CODEC_EN		(1 << 0)
+
+#define PLD_BRITE	SYSPLD_REG(u32, 0x400004)
+#define PLD_BRITE_UP		(1 << 1)
+#define PLD_BRITE_DN		(1 << 0)
+
+#define PLD_LCDEN	SYSPLD_REG(u32, 0x400008)
+#define PLD_LCDEN_EN		(1 << 0)
+
+#define PLD_ID		SYSPLD_REG(u32, 0x40000c)
+
+#define PLD_TCH		SYSPLD_REG(u32, 0x400010)
+#define PLD_TCH_PENIRQ		(1 << 1)
+#define PLD_TCH_EN		(1 << 0)
+
+#define PLD_GPIO	SYSPLD_REG(u32, 0x400014)
+#define PLD_GPIO2		(1 << 2)
+#define PLD_GPIO1		(1 << 1)
+#define PLD_GPIO0		(1 << 0)
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/system.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/system.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/system.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/system.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,40 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/system.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/clps7111.h>
+
+static void arch_idle(void)
+{
+	clps_writel(1, HALT);
+	__asm__ __volatile__(
+	"mov	r0, r0
+	mov	r0, r0");
+}
+
+static inline void arch_reset(char mode)
+{
+	cpu_reset(0);
+}
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/time.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/time.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/time.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/time.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,43 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/time.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <asm/leds.h>
+#include <asm/hardware/clps7111.h>
+
+extern void clps711x_setup_timer(void);
+
+/*
+ * IRQ handler for the timer
+ */
+static void p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	do_leds();
+	do_timer(regs);
+	do_profile(regs);
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static inline void setup_timer(void)
+{
+	clps711x_setup_timer();
+	timer_irq.handler = p720t_timer_interrupt;
+	setup_arm_irq(IRQ_TC2OI, &timer_irq);
+}
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/timex.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/timex.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/timex.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/timex.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,23 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/timex.h
+ *
+ *  Prospector 720T architecture timex specifications
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define CLOCK_TICK_RATE 512000
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/uncompress.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,67 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/uncompress.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/config.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/clps7111.h>
+
+#undef CLPS7111_BASE
+#define CLPS7111_BASE CLPS7111_PHYS_BASE
+
+#define barrier()		__asm__ __volatile__("": : :"memory")
+#define __raw_readl(p)		(*(unsigned long *)(p))
+#define __raw_writel(v,p)	(*(unsigned long *)(p) = (v))
+
+#ifdef CONFIG_DEBUG_CLPS711X_UART2
+#define SYSFLGx	SYSFLG2
+#define UARTDRx	UARTDR2
+#else
+#define SYSFLGx	SYSFLG1
+#define UARTDRx	UARTDR1
+#endif
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+	char c;
+
+	while ((c = *s++) != '\0') {
+		while (clps_readl(SYSFLGx) & SYSFLG_UTXFF)
+			barrier();
+		clps_writel(c, UARTDRx);
+
+		if (c == '\n') {
+			while (clps_readl(SYSFLGx) & SYSFLG_UTXFF)
+				barrier();
+			clps_writel('\r', UARTDRx);
+		}
+	}
+	while (clps_readl(SYSFLGx) & SYSFLG_UBUSY)
+		barrier();
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-clps711x/vmalloc.h linux-2.4.19-pre5/include/asm-arm/arch-clps711x/vmalloc.h
--- linux-2.4.19-pre4/include/asm-arm/arch-clps711x/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-clps711x/vmalloc.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,32 @@
+/*
+ *  linux/include/asm-arm/arch-clps711x/vmalloc.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-ebsa110/io.h linux-2.4.19-pre5/include/asm-arm/arch-ebsa110/io.h
--- linux-2.4.19-pre4/include/asm-arm/arch-ebsa110/io.h	Thu Apr 12 12:20:31 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-ebsa110/io.h	Fri Mar 29 14:50:07 2002
@@ -21,34 +21,48 @@
 #define __arch_getw(a)		(*(volatile unsigned short *)(a))
 #define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
 
-u8  __inb(int port);
-u16 __inw(int port);
-u32 __inl(int port);
+u8 __inb8(unsigned int port);
+void __outb8(u8  val, unsigned int port);
 
-#define inb(p)			__inb(p)
-#define inw(p)			__inw(p)
-#define inl(p)			__inl(p)
+u8 __inb16(unsigned int port);
+void __outb16(u8  val, unsigned int port);
 
-void __outb(u8  val, int port);
-void __outw(u16 val, int port);
-void __outl(u32 val, int port);
+u16 __inw(unsigned int port);
+void __outw(u16 val, unsigned int port);
 
-#define outb(v,p)		__outb(v,p)
-#define outw(v,p)		__outw(v,p)
-#define outl(v,p)		__outl(v,p)
+u32 __inl(unsigned int port);
+void __outl(u32 val, unsigned int port);
 
 u8  __readb(void *addr);
 u16 __readw(void *addr);
 u32 __readl(void *addr);
 
-#define readb(b)		__readb(b)
-#define readw(b)		__readw(b)
-#define readl(b)		__readl(b)
-
 void __writeb(u8  val, void *addr);
 void __writew(u16 val, void *addr);
 void __writel(u32 val, void *addr);
 
+/*
+ * Argh, someone forgot the IOCS16 line.  We therefore have to handle
+ * the byte stearing by selecting the correct byte IO functions here.
+ */
+#ifdef ISA_SIXTEEN_BIT_PERIPHERAL
+#define inb(p)			__inb16(p)
+#define outb(v,p)		__outb16(v,p)
+#else
+#define inb(p)			__inb8(p)
+#define outb(v,p)		__outb8(v,p)
+#endif
+
+#define inw(p)			__inw(p)
+#define outw(v,p)		__outw(v,p)
+
+#define inl(p)			__inl(p)
+#define outl(v,p)		__outl(v,p)
+
+#define readb(b)		__readb(b)
+#define readw(b)		__readw(b)
+#define readl(b)		__readl(b)
+
 #define writeb(v,b)		__writeb(v,b)
 #define writew(v,b)		__writew(v,b)
 #define writel(v,b)		__writel(v,b)
@@ -56,4 +70,12 @@
 #define __arch_ioremap(off,sz,c)	((void *)(off))
 #define __arch_iounmap(virt)		do { } while (0)
 
+extern void insb(unsigned int port, void *buf, int sz);
+extern void insw(unsigned int port, void *buf, int sz);
+extern void insl(unsigned int port, void *buf, int sz);
+
+extern void outsb(unsigned int port, const void *buf, int sz);
+extern void outsw(unsigned int port, const void *buf, int sz);
+extern void outsl(unsigned int port, const void *buf, int sz);
+
 #endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-ebsa110/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-ebsa110/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-ebsa110/uncompress.h	Thu Apr 12 12:20:31 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-ebsa110/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -13,6 +13,8 @@
  */
 static void puts(const char *s)
 {
+	unsigned long tmp1, tmp2;
+
 	__asm__ __volatile__("
 	ldrb	%0, [%2], #1
 	teq	%0, #0
@@ -32,7 +34,9 @@
 	and	%1, %1, #0x60
 	teq	%1, #0x60
 	bne	3b
-	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+	"
+	 : "=&r" (tmp1), "=&r" (tmp2)
+	 : "0" (0), "1" (0), "r" (s), "r" (0xf0000be0) : "cc");
 }
 
 /*
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-ebsa285/keyboard.h linux-2.4.19-pre5/include/asm-arm/arch-ebsa285/keyboard.h
--- linux-2.4.19-pre4/include/asm-arm/arch-ebsa285/keyboard.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-ebsa285/keyboard.h	Fri Mar 29 14:50:07 2002
@@ -6,6 +6,7 @@
  * Copyright (C) 1998-2001 Russell King
  * (C) 1998 Phil Blundell
  */
+#include <linux/config.h>
 #include <linux/ioport.h>
 #include <asm/irq.h>
 #include <asm/system.h>
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-ebsa285/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-ebsa285/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-ebsa285/uncompress.h	Mon Sep 18 15:15:23 2000
+++ linux-2.4.19-pre5/include/asm-arm/arch-ebsa285/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -18,10 +18,12 @@
 static __inline__ void putc(char c)
 {
 	if (machine_is_netwinder()) {
-		while ((SER0_BASE[5] & 0x60) != 0x60);
+		while ((SER0_BASE[5] & 0x60) != 0x60)
+			barrier();
 		SER0_BASE[0] = c;
 	} else {
-		while (DC21285_BASE[6] & 8);
+		while (DC21285_BASE[6] & 8)
+			barrier();
 		DC21285_BASE[0] = c;
 	}
 }
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/ether00.h linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/ether00.h
--- linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/ether00.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/ether00.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,482 @@
+#ifndef __ETHER00_H
+#define __ETHER00_H
+
+
+
+/*
+ * Register definitions for the Ethernet MAC
+ */
+
+/*
+ * Copyright (c) Altera Corporation 2000.
+ * All rights reserved.
+ */
+
+/*
+*	Structures for the DMA controller
+*/
+typedef struct fda_desc
+	{
+	struct fda_desc *	FDNext;
+	long				FDSystem;
+	long				FDStat;
+	short				FDLength;
+	short				FDCtl;
+	}FDA_DESC;
+
+typedef struct buf_desc
+	{
+	char *	BuffData;
+	short	BuffLength;
+	char	BDStat;
+	char	BDCtl;
+	}BUF_DESC;
+
+/*
+*	Control masks for the DMA controller
+*/
+#define FDCTL_BDCOUNT_MSK						(0x1F)
+#define FDCTL_BDCOUNT_OFST						(0)
+#define FDCTL_FRMOPT_MSK						(0x7C00)
+#define FDCTL_FRMOPT_OFST						(10)
+#define	FDCTL_COWNSFD_MSK						(0x8000)
+#define	FDCTL_COWNSFD_OFST						(15)
+
+#define BDCTL_RXBDSEQN_MSK						(0x7F)
+#define BDCTL_RXBDSEQN_OFST						(0)
+#define	BDCTL_COWNSBD_MSK						(0x80)
+#define	BDCTL_COWNSBD_OFST						(7)
+
+#define FDNEXT_EOL_MSK							(0x1)
+#define FDNEXT_EOL_OFST							(0)
+#define FDNEXT_EOL_POINTER_MSK					(0xFFFFFFF0)
+#define FDNEXT_EOL_POINTER_OFST					(4)
+
+#define ETHER_ARC_SIZE         (21)
+
+/*
+*	Regsiter definitions and masks
+*/
+#define ETHER_DMA_CTL(base)							(ETHER00_TYPE (base + 0x100))
+#define ETHER_DMA_CTL_DMBURST_OFST				(2)
+#define ETHER_DMA_CTL_DMBURST_MSK				(0x1FC)
+#define ETHER_DMA_CTL_POWRMGMNT_OFST			(11)
+#define ETHER_DMA_CTL_POWRMGMNT_MSK				(0x1000)
+#define ETHER_DMA_CTL_TXBIGE_OFST				(14)
+#define ETHER_DMA_CTL_TXBIGE_MSK				(0x4000)
+#define ETHER_DMA_CTL_RXBIGE_OFST				(15)
+#define ETHER_DMA_CTL_RXBIGE_MSK				(0x8000)
+#define ETHER_DMA_CTL_TXWAKEUP_OFST				(16)
+#define ETHER_DMA_CTL_TXWAKEUP_MSK				(0x10000)
+#define ETHER_DMA_CTL_SWINTREQ_OFST				(17)
+#define ETHER_DMA_CTL_SWINTREQ_MSK				(0x20000)
+#define ETHER_DMA_CTL_INTMASK_OFST				(18)
+#define ETHER_DMA_CTL_INTMASK_MSK				(0x40000)
+#define ETHER_DMA_CTL_M66ENSTAT_OFST			(19)
+#define ETHER_DMA_CTL_M66ENSTAT_MSK				(0x80000)
+#define ETHER_DMA_CTL_RMTXINIT_OFST				(20)
+#define ETHER_DMA_CTL_RMTXINIT_MSK				(0x100000)
+#define ETHER_DMA_CTL_RMRXINIT_OFST				(21)
+#define ETHER_DMA_CTL_RMRXINIT_MSK				(0x200000)
+#define ETHER_DMA_CTL_RXALIGN_OFST				(22)
+#define ETHER_DMA_CTL_RXALIGN_MSK				(0xC00000)
+#define ETHER_DMA_CTL_RMSWRQ_OFST				(24)
+#define ETHER_DMA_CTL_RMSWRQ_MSK				(0x1000000)
+#define ETHER_DMA_CTL_RMEMBANK_OFST				(25)
+#define ETHER_DMA_CTL_RMEMBANK_MSK				(0x2000000)
+
+#define ETHER_TXFRMPTR(base)							(ETHER00_TYPE (base + 0x104))
+
+#define ETHER_TXTHRSH(base)							(ETHER00_TYPE (base + 0x308))
+
+#define ETHER_TXPOLLCTR(base)							(ETHER00_TYPE (base + 0x30c))
+
+#define	ETHER_BLFRMPTR(base)							(ETHER00_TYPE (base + 0x110))
+#define ETHER_BLFFRMPTR_EOL_OFST				(0)
+#define ETHER_BLFFRMPTR_EOL_MSK					(0x1)
+#define ETHER_BLFFRMPTR_ADDRESS_OFST			(4)
+#define ETHER_BLFFRMPTR_ADDRESS_MSK				(0xFFFFFFF0)
+
+#define ETHER_RXFRAGSIZE(base)						(ETHER00_TYPE (base + 0x114))
+#define	ETHER_RXFRAGSIZE_MINFRAG_OFST			(2)
+#define	ETHER_RXFRAGSIZE_MINFRAG_MSK			(0xFFC)
+#define	ETHER_RXFRAGSIZE_ENPACK_OFST			(15)
+#define	ETHER_RXFRAGSIZE_ENPACK_MSK				(0x8000)
+
+#define ETHER_INT_EN(base)							(ETHER00_TYPE (base + 0x118))
+#define ETHER_INT_EN_FDAEXEN_OFST				(0)
+#define ETHER_INT_EN_FDAEXEN_MSK				(0x1)
+#define ETHER_INT_EN_BLEXEN_OFST				(1)
+#define ETHER_INT_EN_BLEXN_MSK					(0x2)
+#define ETHER_INT_EN_STARGABTEN_OFST			(2)
+#define ETHER_INT_EN_STARGABTEN_MSK				(0x4)
+#define ETHER_INT_EN_RTARGABTEN_OFST			(3)
+#define ETHER_INT_EN_RTARGABTEN_MSK				(0x8)
+#define ETHER_INT_EN_RMASABTEN_OFST				(4)
+#define ETHER_INT_EN_RMASABTEN_MSK				(0x10)
+#define ETHER_INT_EN_SSYSERREN_OFST				(5)
+#define ETHER_INT_EN_SSYSERREN_MSK				(0x20)
+#define ETHER_INT_EN_DPARERREN_OFST				(6)
+#define ETHER_INT_EN_DPARERREN_MSK				(0x40)
+#define ETHER_INT_EN_EARNOTEN_OFST				(7)
+#define ETHER_INT_EN_EARNOTEN_MSK				(0x80)
+#define ETHER_INT_EN_DPARDEN_OFST				(8)
+#define ETHER_INT_EN_DPARDEN_MSK				(0x100)
+#define ETHER_INT_EN_DMPARERREN_OFST			(9)
+#define ETHER_INT_EN_DMPARERREN_MSK				(0x200)
+#define ETHER_INT_EN_TXCTLCMPEN_OFST			(10)
+#define ETHER_INT_EN_TXCTLCMPEN_MSK				(0x400)
+#define ETHER_INT_EN_NRABTEN_OFST				(11)
+#define ETHER_INT_EN_NRABTEN_MSK				(0x800)
+
+#define	ETHER_FDA_BAS(base)							(ETHER00_TYPE (base + 0x11C))
+#define ETHER_FDA_BAS_ADDRESS_OFST				(4)
+#define ETHER_FDA_BAS_ADDRESS_MSK				(0xFFFFFFF0)
+
+#define ETHER_FDA_LIM(base)							(ETHER00_TYPE (base + 0x120))
+#define ETHER_FDA_LIM_COUNT_OFST				(4)
+#define ETHER_FDA_LIM_COUNT_MSK					(0xFFF0)
+
+#define ETHER_INT_SRC(base)							(ETHER00_TYPE (base + 0x124))
+#define ETHER_INT_SRC_INTMACTX_OFST				(0)
+#define ETHER_INT_SRC_INTMACTX_MSK				(0x1)
+#define ETHER_INT_SRC_INTMACRX_OFST				(1)
+#define ETHER_INT_SRC_INTMACRX_MSK				(0x2)
+#define ETHER_INT_SRC_INTSBUS_OFST				(2)
+#define ETHER_INT_SRC_INTSBUS_MSK				(0x4)
+#define ETHER_INT_SRC_INTFDAEX_OFST				(3)
+#define ETHER_INT_SRC_INTFDAEX_MSK				(0x8)
+#define ETHER_INT_SRC_INTBLEX_OFST				(4)
+#define ETHER_INT_SRC_INTBLEX_MSK				(0x10)
+#define ETHER_INT_SRC_SWINT_OFST				(5)
+#define ETHER_INT_SRC_SWINT_MSK					(0x20)
+#define ETHER_INT_SRC_INTEARNOT_OFST			(6)
+#define ETHER_INT_SRC_INTEARNOT_MSK				(0x40)
+#define ETHER_INT_SRC_DMPARERR_OFST				(7)
+#define ETHER_INT_SRC_DMPARERR_MSK				(0x80)
+#define ETHER_INT_SRC_INTEXBD_OFST				(8)
+#define ETHER_INT_SRC_INTEXBD_MSK				(0x100)
+#define ETHER_INT_SRC_INTTXCTLCMP_OFST			(9)
+#define ETHER_INT_SRC_INTTXCTLCMP_MSK			(0x200)
+#define ETHER_INT_SRC_INTNRABT_OFST				(10)
+#define ETHER_INT_SRC_INTNRABT_MSK				(0x400)
+#define ETHER_INT_SRC_FDAEX_OFST				(11)
+#define ETHER_INT_SRC_FDAEX_MSK					(0x800)
+#define ETHER_INT_SRC_BLEX_OFST					(12)
+#define ETHER_INT_SRC_BLEX_MSK					(0x1000)
+#define ETHER_INT_SRC_DMPARERRSTAT_OFST			(13)
+#define ETHER_INT_SRC_DMPARERRSTAT_MSK			(0x2000)
+#define ETHER_INT_SRC_NRABT_OFST				(14)
+#define ETHER_INT_SRC_NRABT_MSK					(0x4000)
+#define ETHER_INT_SRC_INTLINK_OFST				(15)
+#define ETHER_INT_SRC_INTLINK_MSK				(0x8000)
+#define ETHER_INT_SRC_INTEXDEFER_OFST			(16)
+#define ETHER_INT_SRC_INTEXDEFER_MSK			(0x10000)
+#define ETHER_INT_SRC_INTRMON_OFST				(17)
+#define ETHER_INT_SRC_INTRMON_MSK				(0x20000)
+#define ETHER_INT_SRC_IRQ_MSK					(0x83FF)
+
+#define ETHER_PAUSECNT(base)							(ETHER00_TYPE (base + 0x40))
+#define ETHER_PAUSECNT_COUNT_OFST				(0)
+#define ETHER_PAUSECNT_COUNT_MSK				(0xFFFF)
+
+#define ETHER_REMPAUCNT(base)							(ETHER00_TYPE (base + 0x44))
+#define ETHER_REMPAUCNT_COUNT_OFST				(0)
+#define ETHER_REMPAUCNT_COUNT_MSK				(0xFFFF)
+
+#define ETHER_TXCONFRMSTAT(base)						(ETHER00_TYPE (base + 0x348))
+#define ETHER_TXCONFRMSTAT_TS_STAT_VALUE_OFST	(0)
+#define ETHER_TXCONFRMSTAT_TS_STAT_VALUE_MSK	(0x3FFFFF)
+
+#define ETHER_MAC_CTL(base)							(ETHER00_TYPE (base + 0))
+#define ETHER_MAC_CTL_HALTREQ_OFST				(0)
+#define ETHER_MAC_CTL_HALTREQ_MSK				(0x1)
+#define ETHER_MAC_CTL_HALTIMM_OFST				(1)
+#define ETHER_MAC_CTL_HALTIMM_MSK				(0x2)
+#define ETHER_MAC_CTL_RESET_OFST				(2)
+#define ETHER_MAC_CTL_RESET_MSK					(0x4)
+#define ETHER_MAC_CTL_FULLDUP_OFST				(3)
+#define ETHER_MAC_CTL_FULLDUP_MSK				(0x8)
+#define ETHER_MAC_CTL_MACLOOP_OFST				(4)
+#define ETHER_MAC_CTL_MACLOOP_MSK				(0x10)
+#define ETHER_MAC_CTL_CONN_OFST					(5)
+#define ETHER_MAC_CTL_CONN_MSK					(0x60)
+#define ETHER_MAC_CTL_LOOP10_OFST				(7)
+#define ETHER_MAC_CTL_LOOP10_MSK				(0x80)
+#define ETHER_MAC_CTL_LNKCHG_OFST				(8)
+#define ETHER_MAC_CTL_LNKCHG_MSK				(0x100)
+#define ETHER_MAC_CTL_MISSROLL_OFST				(10)
+#define ETHER_MAC_CTL_MISSROLL_MSK				(0x400)
+#define ETHER_MAC_CTL_ENMISSROLL_OFST			(13)
+#define ETHER_MAC_CTL_ENMISSROLL_MSK			(0x2000)
+#define ETHER_MAC_CTL_LINK10_OFST				(15)
+#define ETHER_MAC_CTL_LINK10_MSK				(0x8000)
+
+#define ETHER_ARC_CTL(base)							(ETHER00_TYPE (base + 0x4))
+#define	ETHER_ARC_CTL_STATIONACC_OFST			(0)
+#define	ETHER_ARC_CTL_STATIONACC_MSK			(0x1)
+#define	ETHER_ARC_CTL_GROUPACC_OFST				(1)
+#define	ETHER_ARC_CTL_GROUPACC_MSK				(0x2)
+#define	ETHER_ARC_CTL_BROADACC_OFST				(2)
+#define	ETHER_ARC_CTL_BROADACC_MSK				(0x4)
+#define	ETHER_ARC_CTL_NEGARC_OFST				(3)
+#define	ETHER_ARC_CTL_NEGARC_MSK				(0x8)
+#define	ETHER_ARC_CTL_COMPEN_OFST				(4)
+#define	ETHER_ARC_CTL_COMPEN_MSK				(0x10)
+
+#define ETHER_TX_CTL(base)							(ETHER00_TYPE (base + 0x8))
+#define ETHER_TX_CTL_TXEN_OFST					(0)
+#define ETHER_TX_CTL_TXEN_MSK					(0x1)
+#define ETHER_TX_CTL_TXHALT_OFST				(1)
+#define ETHER_TX_CTL_TXHALT_MSK					(0x2)
+#define ETHER_TX_CTL_NOPAD_OFST					(2)
+#define ETHER_TX_CTL_NOPAD_MSK					(0x4)
+#define ETHER_TX_CTL_NOCRC_OFST					(3)
+#define ETHER_TX_CTL_NOCRC_MSK					(0x8)
+#define ETHER_TX_CTL_FBACK_OFST					(4)
+#define ETHER_TX_CTL_FBACK_MSK					(0x10)
+#define ETHER_TX_CTL_NOEXDEF_OFST				(5)
+#define ETHER_TX_CTL_NOEXDEF_MSK				(0x20)
+#define ETHER_TX_CTL_SDPAUSE_OFST				(6)
+#define ETHER_TX_CTL_SDPAUSE_MSK				(0x40)
+#define ETHER_TX_CTL_MII10_OFST					(7)
+#define ETHER_TX_CTL_MII10_MSK					(0x80)
+#define ETHER_TX_CTL_ENUNDER_OFST				(8)
+#define ETHER_TX_CTL_ENUNDER_MSK				(0x100)
+#define ETHER_TX_CTL_ENEXDEFER_OFST				(9)
+#define ETHER_TX_CTL_ENEXDEFER_MSK				(0x200)
+#define ETHER_TX_CTL_ENLCARR_OFST				(10)
+#define ETHER_TX_CTL_ENLCARR_MSK				(0x400)
+#define ETHER_TX_CTL_ENEXCOLL_OFST				(11)
+#define ETHER_TX_CTL_ENEXCOLL_MSK				(0x800)
+#define ETHER_TX_CTL_ENLATECOLL_OFST				(12)
+#define ETHER_TX_CTL_ENLATECOLL_MSK				(0x1000)
+#define ETHER_TX_CTL_ENTXPAR_OFST				(13)
+#define ETHER_TX_CTL_ENTXPAR_MSK				(0x2000)
+#define ETHER_TX_CTL_ENCOMP_OFST				(14)
+#define ETHER_TX_CTL_ENCOMP_MSK					(0x4000)
+
+#define ETHER_TX_STAT(base)							(ETHER00_TYPE (base + 0xc))
+#define ETHER_TX_STAT_TXCOLL_OFST				(0)
+#define ETHER_TX_STAT_TXCOLL_MSK				(0xF)
+#define ETHER_TX_STAT_EXCOLL_OFST				(4)
+#define ETHER_TX_STAT_EXCOLL_MSK				(0x10)
+#define ETHER_TX_STAT_TXDEFER_OFST				(5)
+#define ETHER_TX_STAT_TXDEFER_MSK				(0x20)
+#define ETHER_TX_STAT_PAUSED_OFST				(6)
+#define ETHER_TX_STAT_PAUSED_MSK				(0x40)
+#define ETHER_TX_STAT_INTTX_OFST				(7)
+#define ETHER_TX_STAT_INTTX_MSK					(0x80)
+#define ETHER_TX_STAT_UNDER_OFST				(8)
+#define ETHER_TX_STAT_UNDER_MSK					(0x100)
+#define ETHER_TX_STAT_EXDEFER_OFST				(9)
+#define ETHER_TX_STAT_EXDEFER_MSK				(0x200)
+#define ETHER_TX_STAT_LCARR_OFST				(10)
+#define ETHER_TX_STAT_LCARR_MSK					(0x400)
+#define ETHER_TX_STAT_TX10STAT_OFST				(11)
+#define ETHER_TX_STAT_TX10STAT_MSK				(0x800)
+#define ETHER_TX_STAT_LATECOLL_OFST				(12)
+#define ETHER_TX_STAT_LATECOLL_MSK				(0x1000)
+#define ETHER_TX_STAT_TXPAR_OFST				(13)
+#define ETHER_TX_STAT_TXPAR_MSK					(0x2000)
+#define ETHER_TX_STAT_COMP_OFST					(14)
+#define ETHER_TX_STAT_COMP_MSK					(0x4000)
+#define ETHER_TX_STAT_TXHALTED_OFST				(15)
+#define ETHER_TX_STAT_TXHALTED_MSK				(0x8000)
+#define ETHER_TX_STAT_SQERR_OFST				(16)
+#define ETHER_TX_STAT_SQERR_MSK					(0x10000)
+#define ETHER_TX_STAT_TXMCAST_OFST				(17)
+#define ETHER_TX_STAT_TXMCAST_MSK				(0x20000)
+#define ETHER_TX_STAT_TXBCAST_OFST				(18)
+#define ETHER_TX_STAT_TXBCAST_MSK				(0x40000)
+#define ETHER_TX_STAT_VLAN_OFST					(19)
+#define ETHER_TX_STAT_VLAN_MSK					(0x80000)
+#define ETHER_TX_STAT_MACC_OFST					(20)
+#define ETHER_TX_STAT_MACC_MSK					(0x100000)
+#define ETHER_TX_STAT_TXPAUSE_OFST				(21)
+#define ETHER_TX_STAT_TXPAUSE_MSK				(0x200000)
+
+#define ETHER_RX_CTL(base)							(ETHER00_TYPE (base + 0x10))
+#define ETHER_RX_CTL_RXEN_OFST					(0)
+#define ETHER_RX_CTL_RXEN_MSK					(0x1)
+#define ETHER_RX_CTL_RXHALT_OFST				(1)
+#define ETHER_RX_CTL_RXHALT_MSK					(0x2)
+#define ETHER_RX_CTL_LONGEN_OFST				(2)
+#define ETHER_RX_CTL_LONGEN_MSK					(0x4)
+#define ETHER_RX_CTL_SHORTEN_OFST				(3)
+#define ETHER_RX_CTL_SHORTEN_MSK				(0x8)
+#define ETHER_RX_CTL_STRIPCRC_OFST				(4)
+#define ETHER_RX_CTL_STRIPCRC_MSK				(0x10)
+#define ETHER_RX_CTL_PASSCTL_OFST				(5)
+#define ETHER_RX_CTL_PASSCTL_MSK				(0x20)
+#define ETHER_RX_CTL_IGNORECRC_OFST				(6)
+#define ETHER_RX_CTL_IGNORECRC_MSK				(0x40)
+#define ETHER_RX_CTL_ENALIGN_OFST				(8)
+#define ETHER_RX_CTL_ENALIGN_MSK				(0x100)
+#define ETHER_RX_CTL_ENCRCERR_OFST				(9)
+#define ETHER_RX_CTL_ENCRCERR_MSK				(0x200)
+#define ETHER_RX_CTL_ENOVER_OFST				(10)
+#define ETHER_RX_CTL_ENOVER_MSK					(0x400)
+#define ETHER_RX_CTL_ENLONGERR_OFST				(11)
+#define ETHER_RX_CTL_ENLONGERR_MSK				(0x800)
+#define ETHER_RX_CTL_ENRXPAR_OFST				(13)
+#define ETHER_RX_CTL_ENRXPAR_MSK				(0x2000)
+#define ETHER_RX_CTL_ENGOOD_OFST				(14)
+#define ETHER_RX_CTL_ENGOOD_MSK					(0x4000)
+
+#define ETHER_RX_STAT(base)							(ETHER00_TYPE (base + 0x14))
+#define ETHER_RX_STAT_LENERR_OFST				(4)
+#define ETHER_RX_STAT_LENERR_MSK				(0x10)
+#define ETHER_RX_STAT_CTLRECD_OFST				(5)
+#define ETHER_RX_STAT_CTLRECD_MSK				(0x20)
+#define ETHER_RX_STAT_INTRX_OFST				(6)
+#define ETHER_RX_STAT_INTRX_MSK					(0x40)
+#define ETHER_RX_STAT_RX10STAT_OFST				(7)
+#define ETHER_RX_STAT_RX10STAT_MSK				(0x80)
+#define ETHER_RX_STAT_ALIGNERR_OFST				(8)
+#define ETHER_RX_STAT_ALIGNERR_MSK				(0x100)
+#define ETHER_RX_STAT_CRCERR_OFST				(9)
+#define ETHER_RX_STAT_CRCERR_MSK				(0x200)
+#define ETHER_RX_STAT_OVERFLOW_OFST				(10)
+#define ETHER_RX_STAT_OVERFLOW_MSK				(0x400)
+#define ETHER_RX_STAT_LONGERR_OFST				(11)
+#define ETHER_RX_STAT_LONGERR_MSK				(0x800)
+#define ETHER_RX_STAT_RXPAR_OFST				(13)
+#define ETHER_RX_STAT_RXPAR_MSK					(0x2000)
+#define ETHER_RX_STAT_GOOD_OFST					(14)
+#define ETHER_RX_STAT_GOOD_MSK					(0x4000)
+#define ETHER_RX_STAT_RXHALTED_OFST				(15)
+#define ETHER_RX_STAT_RXHALTED_MSK				(0x8000)
+#define ETHER_RX_STAT_RXMCAST_OFST				(17)
+#define ETHER_RX_STAT_RXMCAST_MSK				(0x10000)
+#define ETHER_RX_STAT_RXBCAST_OFST				(18)
+#define ETHER_RX_STAT_RXBCAST_MSK				(0x20000)
+#define ETHER_RX_STAT_RXVLAN_OFST				(19)
+#define ETHER_RX_STAT_RXVLAN_MSK				(0x40000)
+#define ETHER_RX_STAT_RXPAUSE_OFST				(20)
+#define ETHER_RX_STAT_RXPAUSE_MSK				(0x80000)
+#define ETHER_RX_STAT_ARCSTATUS_OFST				(21)
+#define ETHER_RX_STAT_ARCSTATUS_MSK				(0xF00000)
+#define ETHER_RX_STAT_ARCENT_OFST				(25)
+#define ETHER_RX_STAT_ARCENT_MSK				(0x1F000000)
+
+#define ETHER_MD_DATA(base)							(ETHER00_TYPE (base + 0x18))
+
+#define ETHER_MD_CA(base)								(ETHER00_TYPE (base + 0x1c))
+#define ETHER_MD_CA_ADDR_OFST					(0)
+#define ETHER_MD_CA_ADDR_MSK					(0x1F)
+#define ETHER_MD_CA_PHY_OFST					(5)
+#define ETHER_MD_CA_PHY_MSK					(0x3E0)
+#define ETHER_MD_CA_WR_OFST					(10)
+#define ETHER_MD_CA_WR_MSK					(0x400)
+#define ETHER_MD_CA_BUSY_OFST					(11)
+#define ETHER_MD_CA_BUSY_MSK					(0x800)
+#define ETHER_MD_CA_PRESUPP_OFST				(12)
+#define ETHER_MD_CA_PRESUPP_MSK					(0x1000)
+
+#define ETHER_ARC_ADR(base)	      (ETHER00_TYPE (base + 0x160))
+#define ETHER_ARC_ADR_ARC_LOC_OFST				(2)
+#define ETHER_ARC_ADR_ARC_LOC_MSK				(0xFFC)
+
+#define ETHER_ARC_DATA(base)  (ETHER00_TYPE (base + 0x364))
+
+#define ETHER_ARC_ENA(base)   (ETHER00_TYPE (base + 0x28))
+#define ETHER_ARC_ENA_MSK					(0x1FFFFF)
+
+#define ETHER_PROM_CTL(base)							(ETHER00_TYPE (base + 0x2c))
+#define ETHER_PROM_CTL_PROM_ADDR_OFST			(0)
+#define ETHER_PROM_CTL_PROM_ADDR_MSK			(0x3F)
+#define ETHER_PROM_CTL_OPCODE_OFST				(13)
+#define ETHER_PROM_CTL_OPCODE_MSK				(0x6000)
+#define ETHER_PROM_CTL_OPCODE_READ_MSK			(0x4000)
+#define ETHER_PROM_CTL_OPCODE_WRITE_MSK			(0x2000)
+#define ETHER_PROM_CTL_OPCODE_ERASE_MSK			(0x6000)
+#define ETHER_PROM_CTL_ENABLE_MSK				(0x0030)
+#define ETHER_PROM_CTL_DISABLE_MSK				(0x0000)
+#define ETHER_PROM_CTL_BUSY_OFST				(15)
+#define ETHER_PROM_CTL_BUSY_MSK					(0x8000)
+
+#define ETHER_PROM_DATA(base)							(ETHER00_TYPE (base + 0x30))
+
+#define ETHER_MISS_CNT(base)							(ETHER00_TYPE (base + 0x3c))
+#define ETHER_MISS_CNT_COUNT_OFST				(0)
+#define ETHER_MISS_CNT_COUNT_MSK				(0xFFFF)
+
+#define ETHER_CNTDATA(base)							(ETHER00_TYPE (base + 0x80))
+
+#define ETHER_CNTACC(base)							(ETHER00_TYPE (base + 0x84))
+#define ETHER_CNTACC_ADDR_OFST					(0)
+#define ETHER_CNTACC_ADDR_MSK					(0xFF)
+#define ETHER_CNTACC_WRRDN_OFST					(8)
+#define ETHER_CNTACC_WRRDN_MSK					(0x100)
+#define ETHER_CNTACC_CLEAR_OFST					(9)
+#define ETHER_CNTACC_CLEAR_MSK					(0x200)
+
+#define ETHER_TXRMINTEN(base)							(ETHER00_TYPE (base + 0x88))
+#define ETHER_TXRMINTEN_MSK						(0x3FFFFFFF)
+
+#define ETHER_RXRMINTEN(base)							(ETHER00_TYPE (base + 0x8C))
+#define ETHER_RXRMINTEN_MSK						(0xFFFFFF)
+
+/*
+*	RMON Registers
+*/
+#define		RMON_COLLISION0						0x0
+#define		RMON_COLLISION1						0x1
+#define		RMON_COLLISION2						0x2
+#define		RMON_COLLISION3						0x3
+#define		RMON_COLLISION4						0x4
+#define		RMON_COLLISION5						0x5
+#define		RMON_COLLISION6						0x6
+#define		RMON_COLLISION7						0x7
+#define		RMON_COLLISION8						0x8
+#define		RMON_COLLISION9						0x9
+#define		RMON_COLLISION10					0xa
+#define		RMON_COLLISION11					0xb
+#define		RMON_COLLISION12					0xc
+#define		RMON_COLLISION13					0xd
+#define		RMON_COLLISION14					0xe
+#define		RMON_COLLISION15					0xf
+#define		RMON_COLLISION16					0x10
+#define		RMON_FRAMES_WITH_DEFERRED_XMISSIONS	0x11
+#define		RMON_LATE_COLLISIONS				0x12
+#define		RMON_FRAMES_LOST_DUE_TO_MAC_XMIT	0x13
+#define		RMON_CARRIER_SENSE_ERRORS			0x14
+#define		RMON_FRAMES_WITH_EXCESSIVE_DEFERAL	0x15
+#define		RMON_UNICAST_FRAMES_TRANSMITTED_OK	0x16
+#define		RMON_MULTICAST_FRAMES_XMITTED_OK	0x17
+#define		RMON_BROADCAST_FRAMES_XMITTED_OK	0x18
+#define		RMON_SQE_TEST_ERRORS				0x19
+#define		RMON_PAUSE_MACCTRL_FRAMES_XMITTED	0x1A
+#define		RMON_MACCTRL_FRAMES_XMITTED			0x1B
+#define		RMON_VLAN_FRAMES_XMITTED			0x1C
+#define		RMON_OCTETS_XMITTED_OK				0x1D
+#define		RMON_OCTETS_XMITTED_OK_HI			0x1E
+
+#define		RMON_RX_PACKET_SIZES0				0x40
+#define		RMON_RX_PACKET_SIZES1				0x41
+#define		RMON_RX_PACKET_SIZES2				0x42
+#define		RMON_RX_PACKET_SIZES3				0x43
+#define		RMON_RX_PACKET_SIZES4				0x44
+#define		RMON_RX_PACKET_SIZES5				0x45
+#define		RMON_RX_PACKET_SIZES6				0x46
+#define		RMON_RX_PACKET_SIZES7				0x47
+#define		RMON_FRAME_CHECK_SEQUENCE_ERRORS	0x48
+#define		RMON_ALIGNMENT_ERRORS				0x49
+#define		RMON_FRAGMENTS						0x4A
+#define		RMON_JABBERS						0x4B
+#define		RMON_FRAMES_LOST_TO_INTMACRCVERR	0x4C
+#define		RMON_UNICAST_FRAMES_RCVD_OK			0x4D
+#define		RMON_MULTICAST_FRAMES_RCVD_OK		0x4E
+#define		RMON_BROADCAST_FRAMES_RCVD_OK		0x4F
+#define		RMON_IN_RANGE_LENGTH_ERRORS			0x50
+#define		RMON_OUT_OF_RANGE_LENGTH_ERRORS		0x51
+#define		RMON_VLAN_FRAMES_RCVD				0x52
+#define		RMON_PAUSE_MAC_CTRL_FRAMES_RCVD		0x53
+#define		RMON_MAC_CTRL_FRAMES_RCVD			0x54
+#define		RMON_OCTETS_RCVD_OK					0x55
+#define		RMON_OCTETS_RCVD_OK_HI				0x56
+#define		RMON_OCTETS_RCVD_OTHER				0x57
+#define		RMON_OCTETS_RCVD_OTHER_HI			0x58
+
+#endif /* __ETHER00_H */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/io.h linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/io.h
--- linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/io.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/io.h	Fri Mar 29 14:50:07 2002
@@ -36,20 +36,11 @@
 #define insl    __arch_readsl*/
 
 #define __io(a)			(a)
-#if 0
-#define __mem_pci(a)		((unsigned long)(a))
-#define __mem_isa(a)		(PCI_MEMORY_VADDR + (unsigned long)(a))
-/*
- * Validate the pci memory address for ioremap.
- */
-#define iomem_valid_addr(iomem,size)	\
-	((iomem) > 0 && (iomem) + (size) <= 0x20000000)
+#define __mem_pci(a)            (a) 
+#define __arch_getw(a)			(*(volatile unsigned short  *)(a))
+#define __arch_putw(v,a)		(*(volatile unsigned short *)(a) = (v))
+#define iomem_valid_addr(off,size) (1)
+#define iomem_to_phys(off) (off)
 
-/*
- * Convert PCI memory space to a CPU physical address
- */
-#define iomem_to_phys(iomem)	((iomem) + PHYS_PCI_MEM_BASE)
-
-#endif
 
 #endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/tdkphy.h linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/tdkphy.h
--- linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/tdkphy.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/tdkphy.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,209 @@
+/*
+ *  linux/drivers/tdkphy.h
+ *
+ *  Copyright (C) 2001 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __TDKPHY_H
+#define __TDKPHY_H
+
+/*
+ * Register definitions for the TDK 78Q2120 PHY 
+ * which is on the Camelot board
+ */
+
+/*
+ * Copyright (c) Altera Corporation 2000.
+ * All rights reserved.
+ */
+#define PHY_CONTROL                                                                                     (0)
+#define PHY_CONTROL_COLT_MSK                                                            (0x80)
+#define PHY_CONTROL_COLT_OFST                                                           (7)
+#define PHY_CONTROL_DUPLEX_MSK                                                          (0x100)
+#define PHY_CONTROL_DUPLEX_OFST                                                         (8)
+#define PHY_CONTROL_RANEG_MSK                                                           (0x200)
+#define PHY_CONTROL_RANEG_OFST                                                          (9)
+#define PHY_CONTROL_ISO_MSK                                                                     (0x400)
+#define PHY_CONTROL_ISO_OFST                                                            (10)
+#define PHY_CONTROL_PWRDN_MSK                                                           (0x800)
+#define PHY_CONTROL_PWRDN_OFST                                                          (11)
+#define PHY_CONTROL_ANEGEN_MSK                                                          (0x1000)
+#define PHY_CONTROL_ANEGEN_OFST                                                         (12)
+#define PHY_CONTROL_SPEEDSL_MSK                                                         (0x2000)
+#define PHY_CONTROL_SPEEDSL_OFST                                                        (13)
+#define PHY_CONTROL_LOOPBK_MSK                                                          (0x4000)
+#define PHY_CONTROL_LOOPBK_OFST                                                         (14)
+#define PHY_CONTROL_RESET_MSK                                                           (0x8000)
+#define PHY_CONTROL_RESET_OFST                                                          (15)
+
+#define PHY_STATUS                                                                                      (1)
+#define PHY_STATUS_ETXD_MSK                                                                     (0x1)
+#define PHY_STATUS_EXTD_OFST                                                            (0)
+#define PHY_STATUS_JAB_MSK                                                                      (0x2)
+#define PHY_STATUS_JAB_OFST                                                                     (1)
+#define PHY_STATUS_LINK_MSK                                                                     (0x4)
+#define PHY_STATUS_LINK_OFST                                                            (2)
+#define PHY_STATUS_ANEGA_MSK                                                            (0x8)
+#define PHY_STATUS_ANEGA_OFST                                                           (3)
+#define PHY_STATUS_RFAULT_MSK                                                           (0x10)
+#define PHY_STATUS_RFAULT_OFST                                                          (4)
+#define PHY_STATUS_ANEGC_MSK                                                            (0x20)
+#define PHY_STATUS_ANEGC_OFST                                                           (5)
+#define PHY_STATUS_10T_H_MSK                                                            (0x800)
+#define PHY_STATUS_10T_H_OFST                                                           (11)
+#define PHY_STATUS_10T_F_MSK                                                            (0x1000)
+#define PHY_STATUS_10T_F_OFST                                                           (12)
+#define PHY_STATUS_100_X_H_MSK                                                          (0x2000)
+#define PHY_STATUS_100_X_H_OFST                                                         (13)
+#define PHY_STATUS_100_X_F_MSK                                                          (0x4000)
+#define PHY_STATUS_100_X_F_OFST                                                         (14)
+#define PHY_STATUS_100T4_MSK                                                            (0x8000)
+#define PHY_STATUS_100T4_OFST                                                           (15)
+
+#define PHY_ID1                                                                                         (2)
+#define PHY_ID1_OUI_MSK                                                                         (0xFFFF)
+#define PHY_ID1_OUI_OFST                                                                        (0)
+
+#define PHY_ID2                                                                                         (3)
+#define PHY_ID2_RN_MSK                                                                          (0xF)
+#define PHY_ID2_RN_OFST                                                                         (0)
+#define PHY_ID2_MN_MSK                                                                          (0x3F0)
+#define PHY_ID2_MN_OFST                                                                         (4)
+#define PHY_ID2_OUI_MSK                                                                         (0xFC00)
+#define PHY_ID2_OUI_OFST                                                                        (10)
+
+#define PHY_AUTO_NEG_ADVERTISEMENT                                                      (4)
+#define PHY_AUTO_NEG_ADVERTISEMENT_SELECTOR_MSK                         (0x1F)
+#define PHY_AUTO_NEG_ADVERTISEMENT_SELECTOR_OFST                        (0)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A0_MSK                                       (0x20)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A0_OFST                                      (5)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A1_MSK                                       (0x40)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A1_OFST                                      (6)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A2_MSK                                       (0x80)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A2_OFST                                      (7)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A3_MSK                                       (0x100)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A3_OFST                                      (8)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A4_MSK                                       (0x200)
+#define PHY_AUTO_NEG_ADVERTISEMENT_A4_OFST                                      (9)
+#define PHY_AUTO_NEG_ADVERTISEMENT_TAF_MSK                                      (0x1FE0)
+#define PHY_AUTO_NEG_ADVERTISEMENT_TAF_OFST                                     (5)
+#define PHY_AUTO_NEG_ADVERTISEMENT_RF_MSK                                       (0x2000)
+#define PHY_AUTO_NEG_ADVERTISEMENT_RF_OFST                                      (13)
+#define PHY_AUTO_NEG_ADVERTISEMENT_RSVD_MSK                                     (0x4000)
+#define PHY_AUTO_NEG_ADVERTISEMENT_RVSD_OFST                            (14)
+#define PHY_AUTO_NEG_ADVERTISEMENT_NP_MSK                                       (0x8000)
+#define PHY_AUTO_NEG_ADVERTISEMENT_NP_OFST                                      (15)
+
+#define PHY_AUTO_NEG_LINK_PARTNER                                                       (5)
+#define PHY_AUTO_NEG_LINK_PARTNER_S4_MSK                                        (0x1F)
+#define PHY_AUTO_NEG_LINK_PARTNER_S4_OFST                                       (0)
+#define PHY_AUTO_NEG_LINK_PARTNER_A7_MSK                                        (0x1FE0)
+#define PHY_AUTO_NEG_LINK_PARTNER_A7_OFST                                       (5)
+#define PHY_AUTO_NEG_LINK_PARTNER_RF_MSK                                        (0x2000)
+#define PHY_AUTO_NEG_LINK_PARTNER_RF_OFST                                       (13)
+#define PHY_AUTO_NEG_LINK_PARTNER_ACK_MSK                                       (0x4000)
+#define PHY_AUTO_NEG_LINK_PARTNER_ACK_OFST                                      (14)
+#define PHY_AUTO_NEG_LINK_PARTNER_NP_MSK                                        (0x8000)
+#define PHY_AUTO_NEG_LINK_PARTNER_NP_OFST                                       (15)
+
+#define PHY_AUTO_NEG_EXPANSION                                                          (6)
+#define PHY_AUTO_NEG_EXPANSION_LPANEGA_MSK                                      (0x1)
+#define PHY_AUTO_NEG_EXPANSION_LPANEGA_OFST                                     (0)
+#define PHY_AUTO_NEG_EXPANSION_PRX_MSK                                          (0x2)
+#define PHY_AUTO_NEG_EXPANSION_PRX_OFST                                         (1)
+#define PHY_AUTO_NEG_EXPANSION_NPA_MSK                                          (0x4)
+#define PHY_AUTO_NEG_EXPANSION_NPA_OFST                                         (2)
+#define PHY_AUTO_NEG_EXPANSION_LPNPA_MSK                                        (0x8)
+#define PHY_AUTO_NEG_EXPANSION_LPNPA_OFST                                       (3)
+#define PHY_AUTO_NEG_EXPANSION_PDF_MSK                                          (0x10)
+#define PHY_AUTO_NEG_EXPANSION_PDF_OFST                                         (4)
+
+#define PHY_VENDOR_SPECIFIC                                                                     (16)
+#define PHY_VENDOR_SPECIFIC_RXCC_MSK                                            (0x1)
+#define PHY_VENDOR_SPECIFIC_RXCC_OFST                                           (0)
+#define PHY_VENDOR_SPECIFIC_PCSBP_MSK                                           (0x2)
+#define PHY_VENDOR_SPECIFIC_PCSBP_OFST                                          (1)
+#define PHY_VENDOR_SPECIFIC_RVSPOL_MSK                                          (0x10)
+#define PHY_VENDOR_SPECIFIC_RVSPOL_OFST                                         (4)
+#define PHY_VENDOR_SPECIFIC_APOL_MSK                                            (0x20)  
+#define PHY_VENDOR_SPECIFIC_APOL_OFST                                           (5)
+#define PHY_VENDOR_SPECIFIC_GPIO0_DIR_MSK                                       (0x40)
+#define PHY_VENDOR_SPECIFIC_GPIO0_DIR_OFST                                      (6)
+#define PHY_VENDOR_SPECIFIC_GPIO0_DAT_MSK                                       (0x80)
+#define PHY_VENDOR_SPECIFIC_GPIO0_DAT_OFST                                      (7)
+#define PHY_VENDOR_SPECIFIC_GPIO1_DIR_MSK                                       (0x100)
+#define PHY_VENDOR_SPECIFIC_GPIO1_DIR_OFST                                      (8)
+#define PHY_VENDOR_SPECIFIC_GPIO1_DAT_MSK                                       (0x200)
+#define PHY_VENDOR_SPECIFIC_GPIO1_DAT_OFST                                      (9)
+#define PHY_VENDOR_SPECIFIC_10BT_NATURAL_LOOPBACK_DAT_MSK       (0x400)
+#define PHY_VENDOR_SPECIFIC_10BT_NATURAL_LOOPBACK_DAT_OFST      (10)
+#define PHY_VENDOR_SPECIFIC_10BT_SQE_TEST_INHIBIT_MSK           (0x800)
+#define PHY_VENDOR_SPECIFIC_10BT_SQE_TEST_INHIBIT_OFST          (11)
+#define PHY_VENDOR_SPECIFIC_TXHIM_MSK                                           (0x1000)
+#define PHY_VENDOR_SPECIFIC_TXHIM_OFST                                          (12)
+#define PHY_VENDOR_SPECIFIC_INT_LEVEL_MSK                                       (0x4000)
+#define PHY_VENDOR_SPECIFIC_INT_LEVEL_OFST                                      (14)
+#define PHY_VENDOR_SPECIFIC_RPTR_MSK                                            (0x8000)
+#define PHY_VENDOR_SPECIFIC_RPTR_OFST                                           (15)
+
+#define PHY_IRQ_CONTROL                                                                         (17)
+#define PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK                                       (0x1)
+#define PHY_IRQ_CONTROL_ANEG_COMP_INT_OFST                                      (0)
+#define PHY_IRQ_CONTROL_RFAULT_INT_MSK                                          (0x2)
+#define PHY_IRQ_CONTROL_RFAULT_INT_OFST                                         (1)
+#define PHY_IRQ_CONTROL_LS_CHG_INT_MSK                                          (0x4)
+#define PHY_IRQ_CONTROL_LS_CHG_INT_OFST                                         (2)
+#define PHY_IRQ_CONTROL_LP_ACK_INT_MSK                                          (0x8)
+#define PHY_IRQ_CONTROL_LP_ACK_INT_OFST                                         (3)
+#define PHY_IRQ_CONTROL_PDF_INT_MSK                                                     (0x10)
+#define PHY_IRQ_CONTROL_PDF_INT_OFST                                            (4)
+#define PHY_IRQ_CONTROL_PRX_INT_MSK                                                     (0x20)
+#define PHY_IRQ_CONTROL_PRX_INT_OFST                                            (5)
+#define PHY_IRQ_CONTROL_RXER_INT_MSK                                            (0x40)
+#define PHY_IRQ_CONTROL_RXER_INT_OFST                                           (6)
+#define PHY_IRQ_CONTROL_JABBER_INT_MSK                                          (0x80)
+#define PHY_IRQ_CONTROL_JABBER_INT_OFST                                         (7)
+#define PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK                                        (0x100)
+#define PHY_IRQ_CONTROL_ANEG_COMP_IE_OFST                                       (8)
+#define PHY_IRQ_CONTROL_RFAULT_IE_MSK                                           (0x200)
+#define PHY_IRQ_CONTROL_RFAULT_IE_OFST                                          (9)
+#define PHY_IRQ_CONTROL_LS_CHG_IE_MSK                                           (0x400)
+#define PHY_IRQ_CONTROL_LS_CHG_IE_OFST                                          (10)
+#define PHY_IRQ_CONTROL_LP_ACK_IE_MSK                                           (0x800)
+#define PHY_IRQ_CONTROL_LP_ACK_IE_OFST                                          (11)
+#define PHY_IRQ_CONTROL_PDF_IE_MSK                                                      (0x1000)
+#define PHY_IRQ_CONTROL_PDF_IE_OFST                                                     (12)
+#define PHY_IRQ_CONTROL_PRX_IE_MSK                                                      (0x2000)
+#define PHY_IRQ_CONTROL_PRX_IE_OFST                                                     (13)
+#define PHY_IRQ_CONTROL_RXER_IE_MSK                                                     (0x4000)
+#define PHY_IRQ_CONTROL_RXER_IE_OFST                                            (14)
+#define PHY_IRQ_CONTROL_JABBER_IE_MSK                                           (0x8000)
+#define PHY_IRQ_CONTROL_JABBER_IE_OFST                                          (15)
+
+#define PHY_DIAGNOSTIC                                                                          (18)
+#define PHY_DIAGNOSTIC_RX_LOCK_MSK                                                      (0x100)
+#define PHY_DIAGNOSTIC_RX_LOCK_OFST                                                     (8)
+#define PHY_DIAGNOSTIC_RX_PASS_MSK                                                      (0x200)
+#define PHY_DIAGNOSTIC_RX_PASS_OFST                                                     (9)
+#define PHY_DIAGNOSTIC_RATE_MSK                                                         (0x400)
+#define PHY_DIAGNOSTIC_RATE_OFST                                                        (10)
+#define PHY_DIAGNOSTIC_DPLX_MSK                                                         (0x800)
+#define PHY_DIAGNOSTIC_DPLX_OFST                                                        (11)
+#define PHY_DIAGNOSTIC_ANEGF_MSK                                                        (0x1000)
+#define PHY_DIAGNOSTIC_ANEGF_OFST                                                       (12)
+
+#endif /* __TDKPHY_H */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/time.h linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/time.h
--- linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/time.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/time.h	Fri Mar 29 14:50:07 2002
@@ -55,7 +55,7 @@
 	setup_arm_irq(IRQ_TIMER0, &timer_irq);
 
 	/* Start the timer */
-	*TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/50);
+	*TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200);
 	*TIMER0_PRESCALE(IO_ADDRESS(EXC_TIMER00_BASE))=1;
 	*TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))=TIMER0_CR_IE_MSK | TIMER0_CR_S_MSK;
 }
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-epxa10db/uncompress.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-epxa10db/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -29,14 +29,18 @@
 static void puts(const char *s)
 {
 	while (*s) {
-		while ((*UART_TSR(IO_ADDRESS(EXC_UART00_BASE)) & UART_TSR_TX_LEVEL_MSK)==15);
+		while ((*UART_TSR(EXC_UART00_BASE) &
+		       UART_TSR_TX_LEVEL_MSK)==15);
+			barrier();
 
-		*UART_TD(IO_ADDRESS(EXC_UART00_BASE)) = *s;
+		*UART_TD(EXC_UART00_BASE) = *s;
 
 		if (*s == '\n') {
-		while ((*UART_TSR(IO_ADDRESS(EXC_UART00_BASE)) & UART_TSR_TX_LEVEL_MSK)==15);
+			while ((*UART_TSR(EXC_UART00_BASE) &
+			       UART_TSR_TX_LEVEL_MSK)==15);
+				barrier();
 
-			*UART_TD(IO_ADDRESS(EXC_UART00_BASE)) = '\r';
+			*UART_TD(EXC_UART00_BASE) = '\r';
 		}
 		s++;
 	}
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-integrator/system.h linux-2.4.19-pre5/include/asm-arm/arch-integrator/system.h
--- linux-2.4.19-pre4/include/asm-arm/arch-integrator/system.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-integrator/system.h	Fri Mar 29 14:50:07 2002
@@ -21,6 +21,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <asm/hardware.h>
+#include <asm/io.h>
 #include <asm/arch/platform.h>
 
 static void arch_idle(void)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-integrator/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-integrator/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-integrator/uncompress.h	Fri Mar  2 18:38:39 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-integrator/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -31,12 +31,14 @@
 static void puts(const char *s)
 {
 	while (*s) {
-		while (AMBA_UART_FR & (1 << 5));
+		while (AMBA_UART_FR & (1 << 5))
+			barrier();
 
 		AMBA_UART_DR = *s;
 
 		if (*s == '\n') {
-			while (AMBA_UART_FR & (1 << 5));
+			while (AMBA_UART_FR & (1 << 5))
+				barrier();
 
 			AMBA_UART_DR = '\r';
 		}
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-l7200/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-l7200/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-l7200/uncompress.h	Sun Aug 13 09:54:15 2000
+++ linux-2.4.19-pre5/include/asm-arm/arch-l7200/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -19,7 +19,8 @@
 static __inline__ void putc(char c)
 {
 	while(__raw_readb(IO_UART + 0x18) & 0x20 ||
-		__raw_readb(IO_UART + 0x18) & 0x08);
+	      __raw_readb(IO_UART + 0x18) & 0x08)
+		barrier();
 	__raw_writeb(c, IO_UART + 0x00);
 }
 
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/dma.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/dma.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/dma.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/dma.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/asm-arm/mx1ads/dma.h
+ *
+ *  Copyright (C) 1997,1998 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+#define MAX_DMA_ADDRESS		0xffffffff
+
+#define MAX_DMA_CHANNELS	0
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/hardware.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/hardware.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/hardware.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,38 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/hardware.h
+ *
+ *  Copyright (C) 1999 ARM Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#include <asm/arch/platform.h>
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+#define IO_BASE			0xF0000000                 // VA of IO
+#define IO_SIZE			0x0B000000                 // How much?
+
+/* macro to get at IO space when running virtually */
+#define IO_ADDRESS(x) (x | IO_BASE)
+
+
+#endif
+
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/io.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/io.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/io.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/io.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,44 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/io.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffff
+
+
+#define __io(a)			((a))
+
+/*
+ * Generic virtual read/write
+ */
+#define __arch_getw(a)		(*(volatile unsigned short *)(a))
+#define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
+
+/*
+ * Validate the pci memory address for ioremap.
+ */
+#define iomem_valid_addr(iomem,size)	(1)
+
+/*
+ * Convert PCI memory space to a CPU physical address
+ */
+#define iomem_to_phys(iomem)	(iomem)
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/irq.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/irq.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/irq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/irq.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,20 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/irq.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#define fixup_irq(i)	(i)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/irqs.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/irqs.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/irqs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/irqs.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,33 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/irqs.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ARM_IRQS_H__
+#define __ARM_IRQS_H__
+
+/* Use the mx1ads definitions */
+#include <asm/arch/platform.h>
+
+/*
+ * Well, that's about all we need I think.
+ */
+#define NR_IRQS                         (MAXIRQNUM + 1)
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/keyboard.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/keyboard.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/keyboard.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,11 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/keyboard.h
+ *
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * Well..., what did you expect?, it's not really there :)
+ *
+ */
+#define kbd_init_hw()           do { } while (0)
+#define kbd_enable_irq()        do { } while (0)
+#define kbd_disable_irq()       do { } while (0)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/memory.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/memory.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/memory.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/memory.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,75 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/memory.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+/*
+ * Page offset: 3GB
+ */
+/* Note
+ * This should be hot-swapable with a CONFIG_MX1ADS_SDRAM
+ * or something similar, so we can swap between SRAM and
+ * SDRAM running kernel.
+ */
+
+#ifdef CONFIG_ARCH_MX1ADS_SRAM
+#define PAGE_OFFSET	(0xc0000000UL)
+#define PHYS_OFFSET	(0x12000000UL)
+#else
+#define PAGE_OFFSET	(0xc0000000UL)
+#define PHYS_OFFSET	(0x08000000UL)
+#endif
+
+/*
+ * On mx1, the sdram/sram is contiguous
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET)
+
+/*
+ * 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 - PAGE_OFFSET +  PHYS_OFFSET)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	(x -  PHYS_OFFSET + PAGE_OFFSET)
+
+#define PHYS_TO_NID(addr)	(0)
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/param.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/param.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/param.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/param.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,21 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/param.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define HZ 100
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/platform.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/platform.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/platform.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/platform.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,221 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ */
+
+/**************************************************************************
+ * * Copyright © ARM Limited 1998.  All rights reserved.
+ * ***********************************************************************/
+/* ************************************************************************
+ *
+ *   MX1 address map
+ *
+ * ***********************************************************************/
+
+
+/* ========================================================================
+ *  MX1 definitions
+ * ========================================================================
+ * ------------------------------------------------------------------------
+ *  Memory definitions
+ * ------------------------------------------------------------------------
+ *  MX1 memory map
+ */
+
+
+#ifndef __MX1ADS_PLATFORM_H__
+#define __MX1ADS_PLATFORM_H__
+
+
+#define MX1ADS_SRAM_BASE           0x00300000
+#define MX1ADS_SRAM_SIZE           SZ_128K
+
+#define MX1ADS_SFLASH_BASE         0x0C000000
+#define MX1ADS_SFLASH_SIZE         SZ_16M
+
+#define MX1ADS_IO_BASE             0x00200000
+#define MX1ADS_IO_SIZE             SZ_256K
+
+#define MX1ADS_VID_BASE            0x00300000
+#define MX1ADS_VID_SIZE            0x26000
+
+#define MX1ADS_VID_START           IO_ADDRESS(MX1ADS_VID_BASE)
+
+
+/* ------------------------------------------------------------------------
+ *  Motorola MX1 system registers
+ * ------------------------------------------------------------------------
+ *
+ */
+
+/*
+ *  Register offests.
+ *
+ */
+
+#define MX1ADS_AIPI1_OFFSET             0x00000
+#define MX1ADS_WDT_OFFSET               0x01000
+#define MX1ADS_TIM1_OFFSET              0x02000
+#define MX1ADS_TIM2_OFFSET              0x03000
+#define MX1ADS_RTC_OFFSET               0x04000
+#define MX1ADS_LCDC_OFFSET              0x05000
+#define MX1ADS_UART1_OFFSET             0x06000
+#define MX1ADS_UART2_OFFSET             0x07000
+#define MX1ADS_PWM_OFFSET               0x08000
+#define MX1ADS_DMAC_OFFSET              0x09000
+#define MX1ADS_AIPI2_OFFSET             0x10000
+#define MX1ADS_SIM_OFFSET               0x11000
+#define MX1ADS_USBD_OFFSET              0x12000
+#define MX1ADS_SPI1_OFFSET              0x13000
+#define MX1ADS_MMC_OFFSET               0x14000
+#define MX1ADS_ASP_OFFSET               0x15000
+#define MX1ADS_BTA_OFFSET               0x16000
+#define MX1ADS_I2C_OFFSET               0x17000
+#define MX1ADS_SSI_OFFSET               0x18000
+#define MX1ADS_SPI2_OFFSET              0x19000
+#define MX1ADS_MSHC_OFFSET              0x1A000
+#define MX1ADS_PLL_OFFSET               0x1B000
+#define MX1ADS_GPIO_OFFSET              0x1C000
+#define MX1ADS_EIM_OFFSET               0x20000
+#define MX1ADS_SDRAMC_OFFSET            0x21000
+#define MX1ADS_MMA_OFFSET               0x22000
+#define MX1ADS_AITC_OFFSET              0x23000
+#define MX1ADS_CSI_OFFSET               0x24000
+
+
+/*
+ *  Register BASEs, based on OFFSETs
+ *
+ */
+
+#define MX1ADS_AIPI1_BASE             (MX1ADS_AIPI1_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_WDT_BASE               (MX1ADS_WDT_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_TIM1_BASE              (MX1ADS_TIM1_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_TIM2_BASE              (MX1ADS_TIM2_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_RTC_BASE               (MX1ADS_RTC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_LCDC_BASE              (MX1ADS_LCDC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_UART1_BASE             (MX1ADS_UART1_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_UART2_BASE             (MX1ADS_UART2_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_PWM_BASE               (MX1ADS_PWM_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_DMAC_BASE              (MX1ADS_DMAC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_AIPI2_BASE             (MX1ADS_AIPI2_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_SIM_BASE               (MX1ADS_SIM_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_USBD_BASE              (MX1ADS_USBD_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_SPI1_BASE              (MX1ADS_SPI1_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_MMC_BASE               (MX1ADS_MMC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_ASP_BASE               (MX1ADS_ASP_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_BTA_BASE               (MX1ADS_BTA_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_I2C_BASE               (MX1ADS_I2C_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_SSI_BASE               (MX1ADS_SSI_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_SPI2_BASE              (MX1ADS_SPI2_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_MSHC_BASE              (MX1ADS_MSHC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_PLL_BASE               (MX1ADS_PLL_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_GPIO_BASE              (MX1ADS_GPIO_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_EIM_BASE               (MX1ADS_EIM_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_SDRAMC_BASE            (MX1ADS_SDRAMC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_MMA_BASE               (MX1ADS_MMA_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_AITC_BASE              (MX1ADS_AITC_OFFSET + MX1ADS_IO_BASE)
+#define MX1ADS_CSI_BASE               (MX1ADS_CSI_OFFSET + MX1ADS_IO_BASE)
+
+
+/*
+ *  MX1 Interrupt numbers
+ *
+ */
+#define INT_SOFTINT                 0
+#define CSI_INT                     6
+#define DSPA_MAC_INT                7
+#define DSPA_INT                    8
+#define COMP_INT                    9
+#define MSHC_XINT                   10
+#define GPIO_INT_PORTA              11
+#define GPIO_INT_PORTB              12
+#define GPIO_INT_PORTC              13
+#define LCDC_INT                    14
+#define SIM_INT                     15
+#define SIM_DATA_INT                16
+#define RTC_INT                     17
+#define RTC_SAMINT                  18
+#define UART2_MINT_PFERR            19
+#define UART2_MINT_RTS              20
+#define UART2_MINT_DTR              21
+#define UART2_MINT_UARTC            22
+#define UART2_MINT_TX               23
+#define UART2_MINT_RX               24
+#define UART1_MINT_PFERR            25
+#define UART1_MINT_RTS              26
+#define UART1_MINT_DTR              27
+#define UART1_MINT_UARTC            28
+#define UART1_MINT_TX               29
+#define UART1_MINT_RX               30
+#define VOICE_DAC_INT               31
+#define VOICE_ADC_INT               32
+#define PEN_DATA_INT                33
+#define PWM_INT                     34
+#define SDHC_INT                    35
+#define I2C_INT                     39
+#define CSPI_INT                    41
+#define SSI_TX_INT                  42
+#define SSI_TX_ERR_INT              43
+#define SSI_RX_INT                  44
+#define SSI_RX_ERR_INT              45
+#define TOUCH_INT                   46
+#define USBD_INT0                   47
+#define USBD_INT1                   48
+#define USBD_INT2                   49
+#define USBD_INT3                   50
+#define USBD_INT4                   51
+#define USBD_INT5                   52
+#define USBD_INT6                   53
+#define BTSYS_INT                   55
+#define BTTIM_INT                   56
+#define BTWUI_INT                   57
+#define TIM2_INT                    58
+#define TIM1_INT                    59
+#define DMA_ERR                     60
+#define DMA_INT                     61
+#define GPIO_INT_PORTD              62
+
+
+
+
+#define MAXIRQNUM                       62
+#define MAXFIQNUM                       62
+#define MAXSWINUM                       62
+
+
+
+
+
+#define TICKS_PER_uSEC                  24
+
+/*
+ *  These are useconds NOT ticks.
+ *
+ */
+#define mSEC_1                          1000
+#define mSEC_5                          (mSEC_1 * 5)
+#define mSEC_10                         (mSEC_1 * 10)
+#define mSEC_25                         (mSEC_1 * 25)
+#define SEC_1                           (mSEC_1 * 1000)
+
+
+
+
+/* 	END */
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/system.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/system.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/system.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/system.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,41 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/system.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <asm/arch/platform.h>
+
+static void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+	cpu_do_idle(0);
+}
+
+static inline void arch_reset(char mode)
+{
+	/* FIXME
+	 */
+}
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/time.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/time.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/time.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/time.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,138 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/time.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ */
+#include <asm/system.h>
+
+/*
+ * Where is the timer (VA)?
+ */
+#define TIMER0_VA_BASE (IO_ADDRESS(MX1ADS_TIM1_BASE)+0x00000000)
+#define TIMER1_VA_BASE (IO_ADDRESS(MX1ADS_TIM2_BASE)+0x00000000)
+
+/*
+ * How long is the timer interval?
+ *
+ * Note-
+ * Clocking is not accurate enough.  Need to change the input
+ * to CLKOUT, and fix what those values are.  However,
+ * first need to evaluate what a reasonable value is
+ * as several other things depend upon that clock.
+ *
+ */
+
+#define TIMER_RELOAD	(328)
+
+#define TICKS2USECS(x)	((x) * 30)
+
+#define TIM_32KHZ       0x08
+#define TIM_INTEN       0x10
+#define TIM_ENAB        0x01
+
+/*
+ * What does it look like?
+ */
+typedef struct TimerStruct {
+	unsigned long TimerControl;
+	unsigned long TimerPrescaler;
+	unsigned long TimerCompare;
+	unsigned long TimerCapture;
+	unsigned long TimerCounter;
+	unsigned long TimerClear;	/* Clear Status */
+} TimerStruct_t;
+
+extern unsigned long (*gettimeoffset) (void);
+
+/*
+ * Returns number of ms since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long
+mx1ads_gettimeoffset(void)
+{
+	volatile TimerStruct_t *timer1 = (TimerStruct_t *) TIMER1_VA_BASE;
+	unsigned long ticks, status;
+
+	/*
+	 * Get the current number of ticks.  Note that there is a race
+	 * condition between us reading the timer and checking for
+	 * an interrupt.  We get around this by ensuring that the
+	 * counter has not reloaded between our two reads.
+	 */
+	ticks = timer1->TimerCounter;
+
+	/*
+	 * Interrupt pending?  If so, we've reloaded once already.
+	 */
+	if (timer1->TimerClear & 1)
+		ticks += TIMER_RELOAD;
+
+	/*
+	 * Convert the ticks to usecs
+	 */
+	return TICKS2USECS(ticks);
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static void
+mx1ads_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	volatile TimerStruct_t *timer1 =
+	    (volatile TimerStruct_t *) TIMER1_VA_BASE;
+	// ...clear the interrupt
+	if (timer1->TimerClear) {
+		timer1->TimerClear = 0x0;
+	}
+
+	do_timer(regs);
+	do_profile(regs);
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static inline void
+setup_timer(void)
+{
+	volatile TimerStruct_t *timer0 =
+	    (volatile TimerStruct_t *) TIMER0_VA_BASE;
+	volatile TimerStruct_t *timer1 =
+	    (volatile TimerStruct_t *) TIMER1_VA_BASE;
+
+
+	timer_irq.handler = mx1ads_timer_interrupt;
+
+	/*
+	 * Initialise to a known state (all timers off, and timing reset)
+	 */
+	timer0->TimerControl = 0;
+	timer1->TimerControl = 0;
+	timer0->TimerPrescaler = 0;
+	timer1->TimerPrescaler = 0;
+
+	timer1->TimerCompare = 328;
+	timer1->TimerControl = (TIM_32KHZ | TIM_INTEN | TIM_ENAB);
+
+	/*
+	 * Make irqs happen for the system timer
+	 */
+	setup_arm_irq(TIM2_INT, &timer_irq);
+	gettimeoffset = mx1ads_gettimeoffset;
+}
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/timex.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/timex.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/timex.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/timex.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,24 @@
+/*
+ *  linux/include/asm-arm/mx1ads/timex.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * ??
+ */
+#define CLOCK_TICK_RATE		(50000000 / 16)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/uncompress.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,56 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/uncompress.h
+ *
+ *
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) Shane Nay (shane@minirl.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define UA1_USR2	(*(volatile unsigned char *)0x206098)
+#define UA1_TXR 	(*(volatile unsigned char *)0x206040)
+#define TXFEBIT         (14)
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+	while (*s) {
+		while (UA1_USR2 & (1 << TXFEBIT))
+			barrier();
+
+		UA1_TXR = *s;
+
+		if (*s == '\n') {
+			while (UA1_USR2 & (1 << TXFEBIT))
+				barrier();
+
+			UA1_TXR = '\r';
+		}
+		s++;
+	}
+	while (UA1_USR2 & (1 << TXFEBIT))
+		barrier();
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/vmalloc.h linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/vmalloc.h
--- linux-2.4.19-pre4/include/asm-arm/arch-mx1ads/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-mx1ads/vmalloc.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,32 @@
+/*
+ *  linux/include/asm-arm/arch-mx1ads/vmalloc.h
+ *
+ *  Copyright (C) 2000 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-nexuspci/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-nexuspci/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-nexuspci/uncompress.h	Mon Sep 18 15:15:23 2000
+++ linux-2.4.19-pre5/include/asm-arm/arch-nexuspci/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -20,7 +20,7 @@
 void _ll_write_char(char c)
 {
 	while (!(__raw_readb(DUART_START + 0x4) & 0x4))
-		;
+		barrier();
 	__raw_writeb(c, DUART_START + 0xc);
 }
 
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-rpc/io.h linux-2.4.19-pre5/include/asm-arm/arch-rpc/io.h
--- linux-2.4.19-pre4/include/asm-arm/arch-rpc/io.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-rpc/io.h	Fri Mar 29 14:50:07 2002
@@ -241,4 +241,13 @@
 /* the following macro is depreciated */
 #define ioaddr(port)			__ioaddr((port))
 
+#define insb(p,d,l)	__raw_readsb(__ioaddr(p),d,l)
+#define insw(p,d,l)	__raw_readsw(__ioaddr(p),d,l)
+
+#define outsb(p,d,l)	__raw_writesb(__ioaddr(p),d,l)
+#define outsw(p,d,l)	__raw_writesw(__ioaddr(p),d,l)
+
+#define iomem_valid_addr(o,s)	(1)
+#define iomem_to_phys(a)	(a)
+
 #endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/SA-1111.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/SA-1111.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/SA-1111.h	Thu Oct 25 13:53:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/SA-1111.h	Fri Mar 29 14:50:07 2002
@@ -1,647 +1,5 @@
 /*
- * linux/include/asm/arch/SA-1111.h
- *
- * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
- *
- * This file contains definitions for the SA-1111 Companion Chip.
- * (Structure and naming borrowed from SA-1101.h, by Peter Danielsson.)
- *
+ * Moved to new location
  */
-
-#ifndef _ASM_ARCH_SA1111
-#define _ASM_ARCH_SA1111
-
-#include <asm/arch/bitfield.h>
-
-/*
- * Macro that calculates real address for registers in the SA-1111
- */
-
-#define _SA1111( x )    ((x) + SA1111_BASE)
-
-/*
- * 26 bits of the SA-1110 address bus are available to the SA-1111.
- * Use these when feeding target addresses to the DMA engines.
- */
-
-#define SA1111_ADDR_WIDTH	(26)
-#define SA1111_ADDR_MASK	((1<<SA1111_ADDR_WIDTH)-1)
-#define SA1111_DMA_ADDR(x)	((x)&SA1111_ADDR_MASK)
-
-/*
- * Don't ask the (SAC) DMA engines to move less than this amount.
- */
-
-#define SA1111_SAC_DMA_MIN_XFER	(0x800)
-
-/*
- * SA1111 register definitions.
- */
-#define __CCREG(x)	__REGP(SA1111_VBASE + (x))
-
-/* System Bus Interface (SBI)
- *
- * Registers
- *    SKCR	Control Register
- *    SMCR	Shared Memory Controller Register
- *    SKID	ID Register
- */
-
-#define _SBI_SKCR	_SA1111(0x0000)
-#define _SBI_SMCR	_SA1111(0x0004)
-#define _SBI_SKID	_SA1111(0x0008)
-
-#if LANGUAGE == C
-
-#define SBI_SKCR	__CCREG(0x0000)
-#define SBI_SMCR	__CCREG(0x0004)
-#define SBI_SKID	__CCREG(0x0008)
-
-#endif  /* LANGUAGE == C */
-
-#define SKCR_PLL_BYPASS	(1<<0)
-#define SKCR_RCLKEN	(1<<1)
-#define SKCR_SLEEP	(1<<2)
-#define SKCR_DOZE	(1<<3)
-#define SKCR_VCO_OFF	(1<<4)
-#define SKCR_SCANTSTEN	(1<<5)
-#define SKCR_CLKTSTEN	(1<<6)
-#define SKCR_RDYEN	(1<<7)
-#define SKCR_SELAC	(1<<8)
-#define SKCR_OPPC	(1<<9)
-#define SKCR_PLLTSTEN	(1<<10)
-#define SKCR_USBIOTSTEN	(1<<11)
-/*
- * Don't believe the specs!  Take them, throw them outside.  Leave them
- * there for a week.  Spit on them.  Walk on them.  Stamp on them.
- * Pour gasoline over them and finally burn them.  Now think about coding.
- *  - The October 1999 errata (278260-007) says its bit 13, 1 to enable.
- *  - The Feb 2001 errata (278260-010) says that the previous errata
- *    (278260-009) is wrong, and its bit actually 12, fixed in spec
- *    278242-003.
- *  - The SA1111 manual (278242) says bit 12, but 0 to enable.
- *  - Reality is bit 13, 1 to enable.
- *      -- rmk
- */
-#define SKCR_OE_EN	(1<<13)
-
-#define SMCR_DTIM	(1<<0)
-#define SMCR_MBGE	(1<<1)
-#define SMCR_DRAC_0	(1<<2)
-#define SMCR_DRAC_1	(1<<3)
-#define SMCR_DRAC_2	(1<<4)
-#define SMCR_DRAC	Fld(3, 2)
-#define SMCR_CLAT	(1<<5)
-
-#define SKID_SIREV_MASK	(0x000000f0)
-#define SKID_MTREV_MASK (0x0000000f)
-#define SKID_ID_MASK	(0xffffff00)
-#define SKID_SA1111_ID	(0x690cc200)
-
-/*
- * System Controller
- *
- * Registers
- *    SKPCR	Power Control Register
- *    SKCDR	Clock Divider Register
- *    SKAUD	Audio Clock Divider Register
- *    SKPMC	PS/2 Mouse Clock Divider Register
- *    SKPTC	PS/2 Track Pad Clock Divider Register
- *    SKPEN0	PWM0 Enable Register
- *    SKPWM0	PWM0 Clock Register
- *    SKPEN1	PWM1 Enable Register
- *    SKPWM1	PWM1 Clock Register
- */
-
-#define _SKPCR		_SA1111(0x0200)
-#define _SKCDR		_SA1111(0x0204)
-#define _SKAUD		_SA1111(0x0208)
-#define _SKPMC		_SA1111(0x020c)
-#define _SKPTC		_SA1111(0x0210)
-#define _SKPEN0		_SA1111(0x0214)
-#define _SKPWM0		_SA1111(0x0218)
-#define _SKPEN1		_SA1111(0x021c)
-#define _SKPWM1		_SA1111(0x0220)
-
-#if LANGUAGE == C
-
-#define SKPCR		__CCREG(0x0200)
-#define SKCDR		__CCREG(0x0204)
-#define SKAUD		__CCREG(0x0208)
-#define SKPMC		__CCREG(0x020c)
-#define SKPTC		__CCREG(0x0210)
-#define SKPEN0		__CCREG(0x0214)
-#define SKPWM0		__CCREG(0x0218)
-#define SKPEN1		__CCREG(0x021c)
-#define SKPWM1		__CCREG(0x0220)
-
-#endif  /* LANGUAGE == C */
-
-#define SKPCR_UCLKEN	(1<<0)
-#define SKPCR_ACCLKEN	(1<<1)
-#define SKPCR_I2SCLKEN	(1<<2)
-#define SKPCR_L3CLKEN	(1<<3)
-#define SKPCR_SCLKEN	(1<<4)
-#define SKPCR_PMCLKEN	(1<<5)
-#define SKPCR_PTCLKEN	(1<<6)
-#define SKPCR_DCLKEN	(1<<7)
-#define SKPCR_PWMCLKEN	(1<<8)
-
-/*
- * USB Host controller
- */
-#define _USB_OHCI_OP_BASE	_SA1111( 0x400 )
-#define _USB_STATUS		_SA1111( 0x518 )
-#define _USB_RESET		_SA1111( 0x51c )
-#define _USB_INTERRUPTEST	_SA1111( 0x520 )
-
-#define _USB_EXTENT		(_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
-
-#if LANGUAGE == C
-
-#define USB_OHCI_OP_BASE	__CCREG(0x0400)
-#define USB_STATUS		__CCREG(0x0518)
-#define USB_RESET		__CCREG(0x051c)
-#define USB_INTERRUPTEST	__CCReG(0x0520)
-
-#endif  /* LANGUAGE == C */
-
-#define USB_RESET_FORCEIFRESET	(1 << 0)
-#define USB_RESET_FORCEHCRESET	(1 << 1)
-#define USB_RESET_CLKGENRESET	(1 << 2)
-#define USB_RESET_SIMSCALEDOWN	(1 << 3)
-#define USB_RESET_USBINTTEST	(1 << 4)
-#define USB_RESET_SLEEPSTBYEN	(1 << 5)
-#define USB_RESET_PWRSENSELOW	(1 << 6)
-#define USB_RESET_PWRCTRLLOW	(1 << 7)
-
-/*
- * Serial Audio Controller
- *
- * Registers
- *    SACR0             Serial Audio Common Control Register
- *    SACR1             Serial Audio Alternate Mode (I2C/MSB) Control Register
- *    SACR2             Serial Audio AC-link Control Register
- *    SASR0             Serial Audio I2S/MSB Interface & FIFO Status Register
- *    SASR1             Serial Audio AC-link Interface & FIFO Status Register
- *    SASCR             Serial Audio Status Clear Register
- *    L3_CAR            L3 Control Bus Address Register
- *    L3_CDR            L3 Control Bus Data Register
- *    ACCAR             AC-link Command Address Register
- *    ACCDR             AC-link Command Data Register
- *    ACSAR             AC-link Status Address Register
- *    ACSDR             AC-link Status Data Register
- *    SADTCS            Serial Audio DMA Transmit Control/Status Register
- *    SADTSA            Serial Audio DMA Transmit Buffer Start Address A
- *    SADTCA            Serial Audio DMA Transmit Buffer Count Register A
- *    SADTSB            Serial Audio DMA Transmit Buffer Start Address B
- *    SADTCB            Serial Audio DMA Transmit Buffer Count Register B
- *    SADRCS            Serial Audio DMA Receive Control/Status Register
- *    SADRSA            Serial Audio DMA Receive Buffer Start Address A
- *    SADRCA            Serial Audio DMA Receive Buffer Count Register A
- *    SADRSB            Serial Audio DMA Receive Buffer Start Address B
- *    SADRCB            Serial Audio DMA Receive Buffer Count Register B
- *    SAITR             Serial Audio Interrupt Test Register
- *    SADR              Serial Audio Data Register (16 x 32-bit)
- */
-
-#define _SACR0          _SA1111( 0x0600 )
-#define _SACR1          _SA1111( 0x0604 )
-#define _SACR2          _SA1111( 0x0608 )
-#define _SASR0          _SA1111( 0x060c )
-#define _SASR1          _SA1111( 0x0610 )
-#define _SASCR          _SA1111( 0x0618 )
-#define _L3_CAR         _SA1111( 0x061c )
-#define _L3_CDR         _SA1111( 0x0620 )
-#define _ACCAR          _SA1111( 0x0624 )
-#define _ACCDR          _SA1111( 0x0628 )
-#define _ACSAR          _SA1111( 0x062c )
-#define _ACSDR          _SA1111( 0x0630 )
-#define _SADTCS         _SA1111( 0x0634 )
-#define _SADTSA         _SA1111( 0x0638 )
-#define _SADTCA         _SA1111( 0x063c )
-#define _SADTSB         _SA1111( 0x0640 )
-#define _SADTCB         _SA1111( 0x0644 )
-#define _SADRCS         _SA1111( 0x0648 )
-#define _SADRSA         _SA1111( 0x064c )
-#define _SADRCA         _SA1111( 0x0650 )
-#define _SADRSB         _SA1111( 0x0654 )
-#define _SADRCB         _SA1111( 0x0658 )
-#define _SAITR          _SA1111( 0x065c )
-#define _SADR           _SA1111( 0x0680 )
-
-#if LANGUAGE == C
-
-#define SACR0		__CCREG(0x0600)
-#define SACR1		__CCREG(0x0604)
-#define SACR2		__CCREG(0x0608)
-#define SASR0		__CCREG(0x060c)
-#define SASR1		__CCREG(0x0610)
-#define SASCR		__CCREG(0x0618)
-#define L3_CAR		__CCREG(0x061c)
-#define L3_CDR		__CCREG(0x0620)
-#define ACCAR		__CCREG(0x0624)
-#define ACCDR		__CCREG(0x0628)
-#define ACSAR		__CCREG(0x062c)
-#define ACSDR		__CCREG(0x0630)
-#define SADTCS		__CCREG(0x0634)
-#define SADTSA		__CCREG(0x0638)
-#define SADTCA		__CCREG(0x063c)
-#define SADTSB		__CCREG(0x0640)
-#define SADTCB		__CCREG(0x0644)
-#define SADRCS		__CCREG(0x0648)
-#define SADRSA		__CCREG(0x064c)
-#define SADRCA		__CCREG(0x0650)
-#define SADRSB		__CCREG(0x0654)
-#define SADRCB		__CCREG(0x0658)
-#define SAITR		__CCREG(0x065c)
-#define SADR		__CCREG(0x0680)
-
-#endif  /* LANGUAGE == C */
-
-#define SACR0_ENB	(1<<0)
-#define SACR0_BCKD	(1<<2)
-#define SACR0_RST	(1<<3)
-
-#define SACR1_AMSL	(1<<0)
-#define SACR1_L3EN	(1<<1)
-#define SACR1_L3MB	(1<<2)
-#define SACR1_DREC	(1<<3)
-#define SACR1_DRPL	(1<<4)
-#define SACR1_ENLBF	(1<<5)
-
-#define SACR2_TS3V	(1<<0)
-#define SACR2_TS4V	(1<<1)
-#define SACR2_WKUP	(1<<2)
-#define SACR2_DREC	(1<<3)
-#define SACR2_DRPL	(1<<4)
-#define SACR2_ENLBF	(1<<5)
-#define SACR2_RESET	(1<<6)
-
-#define SASR0_TNF	(1<<0)
-#define SASR0_RNE	(1<<1)
-#define SASR0_BSY	(1<<2)
-#define SASR0_TFS	(1<<3)
-#define SASR0_RFS	(1<<4)
-#define SASR0_TUR	(1<<5)
-#define SASR0_ROR	(1<<6)
-#define SASR0_L3WD	(1<<16)
-#define SASR0_L3RD	(1<<17)
-
-#define SASR1_TNF	(1<<0)
-#define SASR1_RNE	(1<<1)
-#define SASR1_BSY	(1<<2)
-#define SASR1_TFS	(1<<3)
-#define SASR1_RFS	(1<<4)
-#define SASR1_TUR	(1<<5)
-#define SASR1_ROR	(1<<6)
-#define SASR1_CADT	(1<<16)
-#define SASR1_SADR	(1<<17)
-#define SASR1_RSTO	(1<<18)
-#define SASR1_CLPM	(1<<19)
-#define SASR1_CRDY	(1<<20)
-#define SASR1_RS3V	(1<<21)
-#define SASR1_RS4V	(1<<22)
-
-#define SASCR_TUR	(1<<5)
-#define SASCR_ROR	(1<<6)
-#define SASCR_DTS	(1<<16)
-#define SASCR_RDD	(1<<17)
-#define SASCR_STO	(1<<18)
-
-#define SADTCS_TDEN	(1<<0)
-#define SADTCS_TDIE	(1<<1)
-#define SADTCS_TDBDA	(1<<3)
-#define SADTCS_TDSTA	(1<<4)
-#define SADTCS_TDBDB	(1<<5)
-#define SADTCS_TDSTB	(1<<6)
-#define SADTCS_TBIU	(1<<7)
-
-#define SADRCS_RDEN	(1<<0)
-#define SADRCS_RDIE	(1<<1)
-#define SADRCS_RDBDA	(1<<3)
-#define SADRCS_RDSTA	(1<<4)
-#define SADRCS_RDBDB	(1<<5)
-#define SADRCS_RDSTB	(1<<6)
-#define SADRCS_RBIU	(1<<7)
-
-#define SAD_CS_DEN	(1<<0)
-#define SAD_CS_DIE	(1<<1)	/* Not functional on metal 1 */
-#define SAD_CS_DBDA	(1<<3)	/* Not functional on metal 1 */
-#define SAD_CS_DSTA	(1<<4)
-#define SAD_CS_DBDB	(1<<5)	/* Not functional on metal 1 */
-#define SAD_CS_DSTB	(1<<6)
-#define SAD_CS_BIU	(1<<7)	/* Not functional on metal 1 */
-
-#define SAITR_TFS	(1<<0)
-#define SAITR_RFS	(1<<1)
-#define SAITR_TUR	(1<<2)
-#define SAITR_ROR	(1<<3)
-#define SAITR_CADT	(1<<4)
-#define SAITR_SADR	(1<<5)
-#define SAITR_RSTO	(1<<6)
-#define SAITR_TDBDA	(1<<8)
-#define SAITR_TDBDB	(1<<9)
-#define SAITR_RDBDA	(1<<10)
-#define SAITR_RDBDB	(1<<11)
-
-/*
- * General-Purpose I/O Interface
- *
- * Registers
- *    PA_DDR		GPIO Block A Data Direction
- *    PA_DRR/PA_DWR	GPIO Block A Data Value Register (read/write)
- *    PA_SDR		GPIO Block A Sleep Direction
- *    PA_SSR		GPIO Block A Sleep State
- *    PB_DDR		GPIO Block B Data Direction
- *    PB_DRR/PB_DWR	GPIO Block B Data Value Register (read/write)
- *    PB_SDR		GPIO Block B Sleep Direction
- *    PB_SSR		GPIO Block B Sleep State
- *    PC_DDR		GPIO Block C Data Direction
- *    PC_DRR/PC_DWR	GPIO Block C Data Value Register (read/write)
- *    PC_SDR		GPIO Block C Sleep Direction
- *    PC_SSR		GPIO Block C Sleep State
- */
-
-#define _PA_DDR		_SA1111( 0x1000 )
-#define _PA_DRR		_SA1111( 0x1004 )
-#define _PA_DWR		_SA1111( 0x1004 )
-#define _PA_SDR		_SA1111( 0x1008 )
-#define _PA_SSR		_SA1111( 0x100c )
-#define _PB_DDR		_SA1111( 0x1010 )
-#define _PB_DRR		_SA1111( 0x1014 )
-#define _PB_DWR		_SA1111( 0x1014 )
-#define _PB_SDR		_SA1111( 0x1018 )
-#define _PB_SSR		_SA1111( 0x101c )
-#define _PC_DDR		_SA1111( 0x1020 )
-#define _PC_DRR		_SA1111( 0x1024 )
-#define _PC_DWR		_SA1111( 0x1024 )
-#define _PC_SDR		_SA1111( 0x1028 )
-#define _PC_SSR		_SA1111( 0x102c )
-
-#if LANGUAGE == C
-
-#define PA_DDR		__CCREG(0x1000)
-#define PA_DRR		__CCREG(0x1004)
-#define PA_DWR		__CCREG(0x1004)
-#define PA_SDR		__CCREG(0x1008)
-#define PA_SSR		__CCREG(0x100c)
-#define PB_DDR		__CCREG(0x1010)
-#define PB_DRR		__CCREG(0x1014)
-#define PB_DWR		__CCREG(0x1014)
-#define PB_SDR		__CCREG(0x1018)
-#define PB_SSR		__CCREG(0x101c)
-#define PC_DDR		__CCREG(0x1020)
-#define PC_DRR		__CCREG(0x1024)
-#define PC_DWR		__CCREG(0x1024)
-#define PC_SDR		__CCREG(0x1028)
-#define PC_SSR		__CCREG(0x102c)
-
-#endif  /* LANGUAGE == C */
-
-/*
- * Interrupt Controller
- *
- * Registers
- *    INTTEST0		Test register 0
- *    INTTEST1		Test register 1
- *    INTEN0		Interrupt Enable register 0
- *    INTEN1		Interrupt Enable register 1
- *    INTPOL0		Interrupt Polarity selection 0
- *    INTPOL1		Interrupt Polarity selection 1
- *    INTTSTSEL		Interrupt source selection
- *    INTSTATCLR0	Interrupt Status/Clear 0
- *    INTSTATCLR1	Interrupt Status/Clear 1
- *    INTSET0		Interrupt source set 0
- *    INTSET1		Interrupt source set 1
- *    WAKE_EN0		Wake-up source enable 0
- *    WAKE_EN1		Wake-up source enable 1
- *    WAKE_POL0		Wake-up polarity selection 0
- *    WAKE_POL1		Wake-up polarity selection 1
- */
-
-#define _INTTEST0	_SA1111( 0x1600 )
-#define _INTTEST1	_SA1111( 0x1604 )
-#define _INTEN0		_SA1111( 0x1608 )
-#define _INTEN1		_SA1111( 0x160c )
-#define _INTPOL0	_SA1111( 0x1610 )
-#define _INTPOL1	_SA1111( 0x1614 )
-#define _INTTSTSEL	_SA1111( 0x1618 )
-#define _INTSTATCLR0	_SA1111( 0x161c )
-#define _INTSTATCLR1	_SA1111( 0x1620 )
-#define _INTSET0	_SA1111( 0x1624 )
-#define _INTSET1	_SA1111( 0x1628 )
-#define _WAKE_EN0	_SA1111( 0x162c )
-#define _WAKE_EN1	_SA1111( 0x1630 )
-#define _WAKE_POL0	_SA1111( 0x1634 )
-#define _WAKE_POL1	_SA1111( 0x1638 )
-
-#if LANGUAGE == C
-
-#define INTTEST0	__CCREG(0x1600)
-#define INTTEST1	__CCREG(0x1604)
-#define INTEN0		__CCREG(0x1608)
-#define INTEN1		__CCREG(0x160c)
-#define INTPOL0		__CCREG(0x1610)
-#define INTPOL1		__CCREG(0x1614)
-#define INTTSTSEL	__CCREG(0x1618)
-#define INTSTATCLR0	__CCREG(0x161c)
-#define INTSTATCLR1	__CCREG(0x1620)
-#define INTSET0		__CCREG(0x1624)
-#define INTSET1		__CCREG(0x1628)
-#define WAKE_EN0	__CCREG(0x162c)
-#define WAKE_EN1	__CCREG(0x1630)
-#define WAKE_POL0	__CCREG(0x1634)
-#define WAKE_POL1	__CCREG(0x1638)
-
-#endif  /* LANGUAGE == C */
-
-/*
- * PS/2 Trackpad and Mouse Interfaces
- *
- * Registers   (prefix kbd applies to trackpad interface, mse to mouse)
- *    KBDCR     Control Register
- *    KBDSTAT       Status Register
- *    KBDDATA       Transmit/Receive Data register
- *    KBDCLKDIV     Clock Division Register
- *    KBDPRECNT     Clock Precount Register
- *    KBDTEST1      Test register 1
- *    KBDTEST2      Test register 2
- *    KBDTEST3      Test register 3
- *    KBDTEST4      Test register 4
- *    MSECR
- *    MSESTAT
- *    MSEDATA
- *    MSECLKDIV
- *    MSEPRECNT
- *    MSETEST1
- *    MSETEST2
- *    MSETEST3
- *    MSETEST4
- *
- */
-
-#define _KBD( x )   _SA1111( 0x0A00 )
-#define _MSE( x )   _SA1111( 0x0C00 )
-
-#define _KBDCR	    _SA1111( 0x0A00 )
-#define _KBDSTAT    _SA1111( 0x0A04 )
-#define _KBDDATA    _SA1111( 0x0A08 )
-#define _KBDCLKDIV  _SA1111( 0x0A0C )
-#define _KBDPRECNT  _SA1111( 0x0A10 )
-#define _MSECR	    _SA1111( 0x0C00 )
-#define _MSESTAT    _SA1111( 0x0C04 )
-#define _MSEDATA    _SA1111( 0x0C08 )
-#define _MSECLKDIV  _SA1111( 0x0C0C )
-#define _MSEPRECNT  _SA1111( 0x0C10 )
-
-#if ( LANGUAGE == C )
-
-#define KBDCR		__CCREG(0x0a00)
-#define KBDSTAT		__CCREG(0x0a04)
-#define KBDDATA		__CCREG(0x0a08)
-#define KBDCLKDIV	__CCREG(0x0a0c)
-#define KBDPRECNT	__CCREG(0x0a10)
-#define MSECR		__CCREG(0x0c00)
-#define MSESTAT		__CCREG(0x0c04)
-#define MSEDATA		__CCREG(0x0c08)
-#define MSECLKDIV	__CCREG(0x0c0c)
-#define MSEPRECNT	__CCREG(0x0c10)
-
-#define KBDCR_ENA        0x08
-#define KBDCR_FKD        0x02
-#define KBDCR_FKC        0x01
-
-#define KBDSTAT_TXE      0x80
-#define KBDSTAT_TXB      0x40
-#define KBDSTAT_RXF      0x20
-#define KBDSTAT_RXB      0x10
-#define KBDSTAT_ENA      0x08
-#define KBDSTAT_RXP      0x04
-#define KBDSTAT_KBD      0x02
-#define KBDSTAT_KBC      0x01
-
-#define KBDCLKDIV_DivVal     Fld(4,0)
-
-#define MSECR_ENA        0x08
-#define MSECR_FKD        0x02
-#define MSECR_FKC        0x01
-
-#define MSESTAT_TXE      0x80
-#define MSESTAT_TXB      0x40
-#define MSESTAT_RXF      0x20
-#define MSESTAT_RXB      0x10
-#define MSESTAT_ENA      0x08
-#define MSESTAT_RXP      0x04
-#define MSESTAT_MSD      0x02
-#define MSESTAT_MSC      0x01
-
-#define MSECLKDIV_DivVal     Fld(4,0)
-
-#define KBDTEST1_CD      0x80
-#define KBDTEST1_RC1         0x40
-#define KBDTEST1_MC      0x20
-#define KBDTEST1_C       Fld(2,3)
-#define KBDTEST1_T2      0x40
-#define KBDTEST1_T1      0x20
-#define KBDTEST1_T0      0x10
-#define KBDTEST2_TICBnRES    0x08
-#define KBDTEST2_RKC         0x04
-#define KBDTEST2_RKD         0x02
-#define KBDTEST2_SEL         0x01
-#define KBDTEST3_ms_16       0x80
-#define KBDTEST3_us_64       0x40
-#define KBDTEST3_us_16       0x20
-#define KBDTEST3_DIV8        0x10
-#define KBDTEST3_DIn         0x08
-#define KBDTEST3_CIn         0x04
-#define KBDTEST3_KD      0x02
-#define KBDTEST3_KC      0x01
-#define KBDTEST4_BC12        0x80
-#define KBDTEST4_BC11        0x40
-#define KBDTEST4_TRES        0x20
-#define KBDTEST4_CLKOE       0x10
-#define KBDTEST4_CRES        0x08
-#define KBDTEST4_RXB         0x04
-#define KBDTEST4_TXB         0x02
-#define KBDTEST4_SRX         0x01
-
-#define MSETEST1_CD      0x80
-#define MSETEST1_RC1         0x40
-#define MSETEST1_MC      0x20
-#define MSETEST1_C       Fld(2,3)
-#define MSETEST1_T2      0x40
-#define MSETEST1_T1      0x20
-#define MSETEST1_T0      0x10
-#define MSETEST2_TICBnRES    0x08
-#define MSETEST2_RKC         0x04
-#define MSETEST2_RKD         0x02
-#define MSETEST2_SEL         0x01
-#define MSETEST3_ms_16       0x80
-#define MSETEST3_us_64       0x40
-#define MSETEST3_us_16       0x20
-#define MSETEST3_DIV8        0x10
-#define MSETEST3_DIn         0x08
-#define MSETEST3_CIn         0x04
-#define MSETEST3_KD      0x02
-#define MSETEST3_KC      0x01
-#define MSETEST4_BC12        0x80
-#define MSETEST4_BC11        0x40
-#define MSETEST4_TRES        0x20
-#define MSETEST4_CLKOE       0x10
-#define MSETEST4_CRES        0x08
-#define MSETEST4_RXB         0x04
-#define MSETEST4_TXB         0x02
-#define MSETEST4_SRX         0x01
-
-#endif  /* LANGUAGE == C */
-
-/*
- * PCMCIA Interface
- *
- * Registers
- *    PCSR	Status Register
- *    PCCR	Control Register
- *    PCSSR	Sleep State Register
- */
-
-#define _PCCR		_SA1111( 0x1800 )
-#define _PCSSR		_SA1111( 0x1804 )
-#define _PCSR		_SA1111( 0x1808 )
-
-#if LANGUAGE == C
-
-#define PCCR		__CCREG(0x1800)
-#define PCSSR		__CCREG(0x1804)
-#define PCSR		__CCREG(0x1808)
-
-#endif  /* LANGUAGE == C */
-
-#define PCSR_S0_READY	(1<<0)
-#define PCSR_S1_READY	(1<<1)
-#define PCSR_S0_DETECT	(1<<2)
-#define PCSR_S1_DETECT	(1<<3)
-#define PCSR_S0_VS1	(1<<4)
-#define PCSR_S0_VS2	(1<<5)
-#define PCSR_S1_VS1	(1<<6)
-#define PCSR_S1_VS2	(1<<7)
-#define PCSR_S0_WP	(1<<8)
-#define PCSR_S1_WP	(1<<9)
-#define PCSR_S0_BVD1	(1<<10)
-#define PCSR_S0_BVD2	(1<<11)
-#define PCSR_S1_BVD1	(1<<12)
-#define PCSR_S1_BVD2	(1<<13)
-
-#define PCCR_S0_RST	(1<<0)
-#define PCCR_S1_RST	(1<<1)
-#define PCCR_S0_FLT	(1<<2)
-#define PCCR_S1_FLT	(1<<3)
-#define PCCR_S0_PWAITEN	(1<<4)
-#define PCCR_S1_PWAITEN	(1<<5)
-#define PCCR_S0_PSE	(1<<6)
-#define PCCR_S1_PSE	(1<<7)
-
-#define PCSSR_S0_SLEEP	(1<<0)
-#define PCSSR_S1_SLEEP	(1<<1)
-
-#endif  /* _ASM_ARCH_SA1111 */
+#warning using old SA-1111.h - update to <asm/hardware/sa1111.h>
+#include <asm/hardware/sa1111.h>
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/adsbitsy.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/adsbitsy.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/adsbitsy.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/adsbitsy.h	Fri Mar 29 14:50:07 2002
@@ -11,4 +11,4 @@
 #error "include <asm/hardware.h> instead"
 #endif
 
-#define	SA1111_BASE		(0x18000000)
+#define ADSBITSY_SA1111_BASE	(0x18000000)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/assabet.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/assabet.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/assabet.h	Thu Oct 25 13:53:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/assabet.h	Fri Mar 29 14:50:07 2002
@@ -29,19 +29,6 @@
 #define ASSABET_BCR_BASE  0xf1000000
 #define ASSABET_BCR (*(volatile unsigned int *)(ASSABET_BCR_BASE))
 
-#define ASSABET_BCR_DB1110 \
-	(ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
-	 ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
-	 ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
-	 ASSABET_BCR_IRDA_MD0)
-
-#define ASSABET_BCR_DB1111 \
-	(ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
-	 ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
-	 ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
-	 ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
-	 ASSABET_BCR_IRDA_MD0   | ASSABET_BCR_CF_RST)
-
 #define ASSABET_BCR_CF_PWR	(1<<0)	/* Compact Flash Power (1 = 3.3v, 0 = off) */
 #define ASSABET_BCR_CF_RST	(1<<1)	/* Compact Flash Reset (1 = power up reset) */
 #define ASSABET_BCR_GFX_RST	(1<<1)	/* Graphics Accelerator Reset (0 = hold reset) */
@@ -70,8 +57,15 @@
 
 extern unsigned long SCR_value;
 extern unsigned long BCR_value;
-#define ASSABET_BCR_set(x)	ASSABET_BCR = (BCR_value |= (x))
-#define ASSABET_BCR_clear(x)	ASSABET_BCR = (BCR_value &= ~(x))
+
+#ifdef CONFIG_SA1100_ASSABET
+extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set);
+#else
+#define ASSABET_BCR_frob(m,s)	do { } while (0)
+#endif
+
+#define ASSABET_BCR_set(x)	ASSABET_BCR_frob((x), (x))
+#define ASSABET_BCR_clear(x)	ASSABET_BCR_frob((x), 0)
 
 #define ASSABET_BSR_BASE	0xf1000000
 #define ASSABET_BSR (*(volatile unsigned int*)(ASSABET_BSR_BASE))
@@ -88,37 +82,27 @@
 
 /* GPIOs for which the generic definition doesn't say much */
 #define ASSABET_GPIO_RADIO_IRQ		GPIO_GPIO (14)	/* Radio interrupt request  */
-#define ASSABET_GPIO_L3_I2C_SDA		GPIO_GPIO (15)	/* L3 and SMB control ports */
 #define ASSABET_GPIO_PS_MODE_SYNC	GPIO_GPIO (16)	/* Power supply mode/sync   */
-#define ASSABET_GPIO_L3_MODE		GPIO_GPIO (17)	/* L3 mode signal with LED  */
-#define ASSABET_GPIO_L3_I2C_SCL		GPIO_GPIO (18)	/* L3 and I2C control ports */
 #define ASSABET_GPIO_STEREO_64FS_CLK	GPIO_GPIO (19)	/* SSP UDA1341 clock input  */
 #define ASSABET_GPIO_CF_IRQ		GPIO_GPIO (21)	/* CF IRQ   */
 #define ASSABET_GPIO_CF_CD		GPIO_GPIO (22)	/* CF CD */
-#define ASSABET_GPIO_UCB1300_IRQ	GPIO_GPIO (23)	/* UCB GPIO and touchscreen */
 #define ASSABET_GPIO_CF_BVD2		GPIO_GPIO (24)	/* CF BVD */
 #define ASSABET_GPIO_GFX_IRQ		GPIO_GPIO (24)	/* Graphics IRQ */
 #define ASSABET_GPIO_CF_BVD1		GPIO_GPIO (25)	/* CF BVD */
-#define ASSABET_GPIO_NEP_IRQ		GPIO_GPIO (25)	/* Neponset IRQ */
 #define ASSABET_GPIO_BATT_LOW		GPIO_GPIO (26)	/* Low battery */
 #define ASSABET_GPIO_RCLK		GPIO_GPIO (26)	/* CCLK/2  */
 
 #define ASSABET_IRQ_GPIO_CF_IRQ		IRQ_GPIO21
 #define ASSABET_IRQ_GPIO_CF_CD		IRQ_GPIO22
-#define ASSABET_IRQ_GPIO_UCB1300_IRQ	IRQ_GPIO23
 #define ASSABET_IRQ_GPIO_CF_BVD2	IRQ_GPIO24
 #define ASSABET_IRQ_GPIO_CF_BVD1	IRQ_GPIO25
-#define ASSABET_IRQ_GPIO_NEP_IRQ	IRQ_GPIO25
 
 
 /*
  * Neponset definitions: 
  */
 
-#define SA1111_BASE             (0x40000000)
-
-#define NEPONSET_ETHERNET_IRQ	MISC_IRQ0
-#define NEPONSET_USAR_IRQ	MISC_IRQ1
+#define NEPONSET_SA1111_BASE	(0x40000000)
 
 #define NEPONSET_CPLD_BASE      (0x10000000)
 #define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/badge4.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/badge4.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/badge4.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/badge4.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,74 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/badge4.h
+ *
+ *   Tim Connors <connors@hpl.hp.com>
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "include <asm/hardware.h> instead"
+#endif
+
+#define BADGE4_SA1111_BASE		(0x48000000)
+
+/* GPIOs on the BadgePAD 4 */
+#define BADGE4_GPIO_INT_1111		GPIO_GPIO0   /* SA-1111 IRQ */
+
+#define BADGE4_GPIO_INT_VID		GPIO_GPIO1   /* Video expansion */
+#define BADGE4_GPIO_LGP2		GPIO_GPIO2   /* GPIO_LDD8 */
+#define BADGE4_GPIO_LGP3		GPIO_GPIO3   /* GPIO_LDD9 */
+#define BADGE4_GPIO_LGP4		GPIO_GPIO4   /* GPIO_LDD10 */
+#define BADGE4_GPIO_LGP5		GPIO_GPIO5   /* GPIO_LDD11 */
+#define BADGE4_GPIO_LGP6		GPIO_GPIO6   /* GPIO_LDD12 */
+#define BADGE4_GPIO_LGP7		GPIO_GPIO7   /* GPIO_LDD13 */
+#define BADGE4_GPIO_LGP8		GPIO_GPIO8   /* GPIO_LDD14 */
+#define BADGE4_GPIO_LGP9		GPIO_GPIO9   /* GPIO_LDD15 */
+#define BADGE4_GPIO_GPA_VID		GPIO_GPIO10  /* Video expansion */
+#define BADGE4_GPIO_GPB_VID		GPIO_GPIO11  /* Video expansion */
+#define BADGE4_GPIO_GPC_VID		GPIO_GPIO12  /* Video expansion */
+
+#define BADGE4_GPIO_UART_HS1		GPIO_GPIO13
+#define BADGE4_GPIO_UART_HS2		GPIO_GPIO14
+
+#define BADGE4_GPIO_MUXSEL0		GPIO_GPIO15
+#define BADGE4_GPIO_TESTPT_J7		GPIO_GPIO16
+
+#define BADGE4_GPIO_SDSDA		GPIO_GPIO17  /* SDRAM SPD Data */
+#define BADGE4_GPIO_SDSCL		GPIO_GPIO18  /* SDRAM SPD Clock */
+#define BADGE4_GPIO_SDTYP0		GPIO_GPIO19  /* SDRAM Type Control */
+#define BADGE4_GPIO_SDTYP1		GPIO_GPIO20  /* SDRAM Type Control */
+
+#define BADGE4_GPIO_BGNT_1111		GPIO_GPIO21  /* GPIO_MBGNT */
+#define BADGE4_GPIO_BREQ_1111		GPIO_GPIO22  /* GPIO_TREQA */
+
+#define BADGE4_GPIO_TESTPT_J6		GPIO_GPIO23
+
+#define BADGE4_GPIO_PCMEN5V		GPIO_GPIO24  /* 5V power */
+
+#define BADGE4_GPIO_SA1111_NRST		GPIO_GPIO25  /* SA-1111 nRESET */
+
+#define BADGE4_GPIO_TESTPT_J5		GPIO_GPIO26
+
+#define BADGE4_GPIO_CLK_1111		GPIO_GPIO27  /* GPIO_32_768kHz */
+
+/* Interrupts on the BadgePAD 4 */
+#define BADGE4_IRQ_GPIO_SA1111		IRQ_GPIO0    /* SA-1111 interrupt */
+
+
+/* PCM5ENV Usage tracking */
+
+#define BADGE4_5V_PCMCIA_SOCK0		(1<<0)
+#define BADGE4_5V_PCMCIA_SOCK1		(1<<1)
+#define BADGE4_5V_PCMCIA_SOCK(n)	(1<<(n))
+#define BADGE4_5V_USB			(1<<2)
+
+#ifndef __ASSEMBLY__
+extern void badge4_set_5V(unsigned subsystem, int on);
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/cerf.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/cerf.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/cerf.h	Thu Oct 25 13:53:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/cerf.h	Fri Mar 29 14:50:07 2002
@@ -1,6 +1,8 @@
 #ifndef _INCLUDE_CERF_H_
 #define _INCLUDE_CERF_H_
 
+#include <linux/config.h>
+
 #ifdef CONFIG_SA1100_CERF_CPLD
 
 
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/flexanet.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/flexanet.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/flexanet.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/flexanet.h	Fri Mar 29 14:50:07 2002
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-sa1100/flexanet.h
+ * include/asm-arm/arch-sa1100/flexanet.h
  *
  * Created 2001/05/04 by Jordi Colomer <jco@ict.es>
  *
@@ -11,39 +11,79 @@
 #error "include <asm/hardware.h> instead"
 #endif
 
-
 /* Board Control Register (virtual address) */
-#define BCR_PHYS  0x10000000
-#define BCR_VIRT  0xf0000000
-#define BCR (*(volatile unsigned int *)(BCR_VIRT))
+#define FHH_BCR_PHYS  0x10000000
+#define FHH_BCR_VIRT  0xf0000000
+#define FHH_BCR (*(volatile unsigned int *)(FHH_BCR_VIRT))
 
 /* Power-up value */
-#define BCR_POWERUP	0x00000000
+#define FHH_BCR_POWERUP	0x00000000
 
 /* Mandatory bits */
-#define BCR_LED_GREEN	(1<<0)	/* General-purpose green LED (1 = on) */
-#define BCR_GUI_NRST	(1<<4)	/* GUI board reset (0 = reset) */
-
-/* Board Status Register (virtual address) */
-#define BSR_BASE  BCR_BASE
-#define BSR (*(volatile unsigned int *)(BSR_BASE))
-
+#define FHH_BCR_LED_GREEN  (1<<0)  /* General-purpose green LED (1 = on) */
+#define FHH_BCR_SPARE_1    (1<<1)  /* Not defined */
+#define FHH_BCR_CF1_RST    (1<<2)  /* Compact Flash Slot #1 Reset (1 = reset) */
+#define FHH_BCR_CF2_RST    (1<<3)  /* Compact Flash Slot #2 Reset (1 = reset) */
+#define FHH_BCR_GUI_NRST   (1<<4)  /* GUI board reset (0 = reset) */
+#define FHH_BCR_RTS1       (1<<5)  /* RS232 RTS for UART-1 */
+#define FHH_BCR_RTS3       (1<<6)  /* RS232 RTS for UART-3 */
+#define FHH_BCR_XCDBG0     (1<<7)  /* Not defined. Wired to XPLA3 for debug */
+
+/* BCR extension, only required by L3-bus in some audio codecs */
+#define FHH_BCR_L3MOD      (1<<8)  /* L3-bus MODE signal */
+#define FHH_BCR_L3DAT      (1<<9)  /* L3-bus DATA signal */
+#define FHH_BCR_L3CLK      (1<<10) /* L3-bus CLK signal */
+#define FHH_BCR_SPARE_11   (1<<11) /* Not defined */
+#define FHH_BCR_SPARE_12   (1<<12) /* Not defined */
+#define FHH_BCR_SPARE_13   (1<<13) /* Not defined */
+#define FHH_BCR_SPARE_14   (1<<14) /* Not defined */
+#define FHH_BCR_SPARE_15   (1<<15) /* Not defined */
+
+ /* Board Status Register (virtual address) */
+#define FHH_BSR_BASE  FHH_BCR_VIRT
+#define FHH_BSR (*(volatile unsigned int *)(FHH_BSR_BASE))
+
+#define FHH_BSR_CTS1       (1<<0)  /* RS232 CTS for UART-1 */
+#define FHH_BSR_CTS3       (1<<1)  /* RS232 CTS for UART-3 */
+#define FHH_BSR_DSR1       (1<<2)  /* RS232 DSR for UART-1 */
+#define FHH_BSR_DSR3       (1<<3)  /* RS232 DSR for UART-3 */
+#define FHH_BSR_ID0        (1<<4)  /* Board identification */
+#define FHH_BSR_ID1        (1<<5)
+#define FHH_BSR_CFG0       (1<<6)  /* Board configuration options */
+#define FHH_BSR_CFG1       (1<<7)
 
 #ifndef __ASSEMBLY__
-extern unsigned long BCR_value;	/* Image of the BCR */
-#define BCR_set( x )	BCR = (BCR_value |= (x))
-#define BCR_clear( x )	BCR = (BCR_value &= ~(x))
+extern unsigned long flexanet_BCR;	/* Image of the BCR */
+#define FLEXANET_BCR_set( x )    FHH_BCR = (flexanet_BCR |= (x))
+#define FLEXANET_BCR_clear( x )  FHH_BCR = (flexanet_BCR &= ~(x))
 #endif
 
-
 /* GPIOs for which the generic definition doesn't say much */
-#define GPIO_GUI_IRQ		GPIO_GPIO (23)	/* IRQ from GUI board (i.e., UCB1300) */
-#define GPIO_ETH_IRQ		GPIO_GPIO (24)	/* IRQ from Ethernet controller */
-#define GPIO_LED_RED		GPIO_GPIO (26)	/* General-purpose red LED */
+#define GPIO_CF1_NCD       GPIO_GPIO (14)  /* Card Detect from CF slot #1 */
+#define GPIO_CF2_NCD       GPIO_GPIO (15)  /* Card Detect from CF slot #2 */
+#define GPIO_CF1_IRQ       GPIO_GPIO (16)  /* IRQ from CF slot #1 */
+#define GPIO_CF2_IRQ       GPIO_GPIO (17)  /* IRQ from CF slot #2 */
+#define GPIO_APP_IRQ       GPIO_GPIO (18)  /* Extra IRQ from application bus */
+#define GPIO_RADIO_REF     GPIO_GPIO (20)  /* Ref. clock for UART3 (Radio) */
+#define GPIO_CF1_BVD1      GPIO_GPIO (21)  /* BVD1 from CF slot #1 */
+#define GPIO_CF2_BVD1      GPIO_GPIO (22)  /* BVD1 from CF slot #2 */
+#define GPIO_GUI_IRQ       GPIO_GPIO (23)  /* IRQ from GUI board (i.e., UCB1300) */
+#define GPIO_ETH_IRQ       GPIO_GPIO (24)  /* IRQ from Ethernet controller */
+#define GPIO_INTIP_IRQ     GPIO_GPIO (25)  /* Measurement IRQ (INTIP) */
+#define GPIO_LED_RED       GPIO_GPIO (26)  /* General-purpose red LED */
 
 /* IRQ sources from GPIOs */
-#define IRQ_GPIO_GUI		IRQ_GPIO23
-#define IRQ_GPIO_ETH		IRQ_GPIO24
+#define IRQ_GPIO_CF1_CD    IRQ_GPIO14
+#define IRQ_GPIO_CF2_CD    IRQ_GPIO15
+#define IRQ_GPIO_CF1_IRQ   IRQ_GPIO16
+#define IRQ_GPIO_CF2_IRQ   IRQ_GPIO17
+#define IRQ_GPIO_APP       IRQ_GPIO18
+#define IRQ_GPIO_CF1_BVD1  IRQ_GPIO21
+#define IRQ_GPIO_CF2_BVD1  IRQ_GPIO22
+#define IRQ_GPIO_GUI       IRQ_GPIO23
+#define IRQ_GPIO_ETH       IRQ_GPIO24
+#define IRQ_GPIO_INTIP     IRQ_GPIO25
+
 
 /* On-Board Ethernet */
 #define _FHH_ETH_IOBASE		0x18000000	/* I/O base (physical addr) */
@@ -58,14 +98,3 @@
 #define FHH_ETH_MMBASE		FHH_ETH_p2v(_FHH_ETH_MMBASE)
 
 
-/* Types of GUI */
-#ifndef __ASSEMBLY__
-extern unsigned long GUI_type;
-#endif
-
-#define FHH_GUI_ERROR		0xFFFFFFFF
-#define FHH_GUI_NONE		0x0000000F
-#define FHH_GUI_TYPE_0		0
-#define FHH_GUI_TYPE_1		1
-#define FHH_GUI_TYPE_2		2
-
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/frodo.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/frodo.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/frodo.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/frodo.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,56 @@
+#ifndef _INCLUDE_FRODO_H_
+#define _INCLUDE_FRODO_H_
+
+/*
+ * linux/include/asm-arm/arch-sa1100/frodo.h
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * This file contains the hardware specific definitions for 2d3D, Inc.
+ * SA-1110 Development Board.
+ *
+ * Only include this file from SA1100-specific files.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * History:
+ *
+ *   2002/02/28   Ethernet (cs89x0) support
+ *
+ *   2002/02/27   IDE support
+ *
+ *   2002/02/22   Added some CPLD registers to control backlight and
+ *                general purpose LEDs
+ *
+ *   2002/01/31   Initial version
+ */
+
+/* CPLD registers */
+#define FRODO_CPLD_UART				*((u16 *) 0xf000c000)
+#define FRODO_CPLD_IDE				*((u16 *) 0xf0008000)
+#define FRODO_CPLD_GENERAL			*((u16 *) 0xf0004004)
+#define FRODO_CPLD_PCMCIA_STATUS	*((u16 *) 0xf0004000)
+#define FRODO_CPLD_PCMCIA_COMMAND	*((u16 *) 0xf0000000)
+#define FRODO_CPLD_SCRATCHPAD		*((u16 *) 0xf0000004)
+
+/* general command/status register */
+#define FRODO_LCD_BACKLIGHT			0x0400		/* R/W */
+#define FRODO_LED1					0x0100		/* R/W */
+#define FRODO_LED2					0x0200		/* R/W */
+#define FRODO_PUSHBUTTON			0x8000		/* R/O */
+
+/* IDE related definitions */
+#define FRODO_IDE_GPIO			GPIO_GPIO23
+#define FRODO_IDE_IRQ			IRQ_GPIO23
+#define FRODO_IDE_DATA			0xf0020000
+#define FRODO_IDE_CTRL			0xf0038004
+
+/* Ethernet related definitions */
+#define FRODO_ETH_GPIO			GPIO_GPIO20
+#define FRODO_ETH_IRQ			IRQ_GPIO20
+#define FRODO_ETH_MEMORY		0xf0060000
+#define FRODO_ETH_IO			0xf0070000
+
+#endif	/* _INCLUDE_FRODO_H_ */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/graphicsmaster.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/graphicsmaster.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/graphicsmaster.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/graphicsmaster.h	Fri Mar 29 14:50:07 2002
@@ -61,6 +61,4 @@
 #define ADS_DCR		(*((volatile u_char *) ADS_p2v(_ADS_DCR)))
 #endif
 
-#define	SA1111_BASE	(0x18000000)
-
-#include "SA-1111.h"
+#define ADS_SA1111_BASE		(0x18000000)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/h3600.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/h3600.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/h3600.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/h3600.h	Fri Mar 29 14:50:07 2002
@@ -1,81 +1,153 @@
 /*
-*
-* Definitions for H3600 Handheld Computer
-*
-* Copyright 2000 Compaq Computer Corporation.
-*
-* Use consistent with the GNU GPL is permitted,
-* provided that this copyright notice is
-* preserved in its entirety in all copies and derived works.
-*
-* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
-* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
-* FITNESS FOR ANY PARTICULAR PURPOSE.
-*
-* Author: Jamey Hicks.
-*
-*/
+ *
+ * Definitions for H3600 Handheld Computer
+ *
+ * Copyright 2000 Compaq Computer Corporation.
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Jamey Hicks.
+ *
+ * History:
+ *
+ * 2001-10-??	Andrew Christian   Added support for iPAQ H3800
+ *
+ */
 
 #ifndef _INCLUDE_H3600_H_
 #define _INCLUDE_H3600_H_
 
-#define GPIO_H3600_NPOWER_BUTTON	GPIO_GPIO (0)
-#define GPIO_H3600_ACTION_BUTTON	GPIO_GPIO (18)
+#include <linux/config.h>
+
+/* generalized support for H3xxx series Compaq Pocket PC's */
+#define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600() || machine_is_h3800())
+
+/* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
+#define H3600_EGPIO_VIRT     0xf0000000
+#define H3600_BANK_2_VIRT    0xf1000000
+#define H3600_BANK_4_VIRT    0xf3800000
+
+/*
+   Machine-independent GPIO definitions
+   --- these are common across all current iPAQ platforms
+*/
+
+#define GPIO_H3600_NPOWER_BUTTON	GPIO_GPIO (0)	/* Also known as the "off button"  */
+#define GPIO_H3600_MICROCONTROLLER	GPIO_GPIO (1)	/* From ASIC2 on H3800 */
 
-#define GPIO_H3600_PCMCIA_CD0		GPIO_GPIO (17)
 #define GPIO_H3600_PCMCIA_CD1		GPIO_GPIO (10)
-#define GPIO_H3600_PCMCIA_IRQ0		GPIO_GPIO (21)
 #define GPIO_H3600_PCMCIA_IRQ1		GPIO_GPIO (11)
 
-/* audio sample rate clock generator */
-#define GPIO_H3600_CLK_SET0		GPIO_GPIO (12)
-#define GPIO_H3600_CLK_SET1		GPIO_GPIO (13)
-
 /* UDA1341 L3 Interface */
 #define GPIO_H3600_L3_DATA		GPIO_GPIO (14)
-#define GPIO_H3600_L3_CLOCK		GPIO_GPIO (16)
 #define GPIO_H3600_L3_MODE		GPIO_GPIO (15)
+#define GPIO_H3600_L3_CLOCK		GPIO_GPIO (16)
 
-#define GPIO_H3600_OPT_LOCK		GPIO_GPIO (22)
-#define GPIO_H3600_OPT_IRQ		GPIO_GPIO (24)
-#define GPIO_H3600_OPT_DET		GPIO_GPIO (27)
+#define GPIO_H3600_PCMCIA_CD0		GPIO_GPIO (17)
+#define GPIO_H3600_SYS_CLK		GPIO_GPIO (19)
+#define GPIO_H3600_PCMCIA_IRQ0		GPIO_GPIO (21)
 
 #define GPIO_H3600_COM_DCD		GPIO_GPIO (23)
+#define GPIO_H3600_OPT_IRQ		GPIO_GPIO (24)
 #define GPIO_H3600_COM_CTS		GPIO_GPIO (25)
 #define GPIO_H3600_COM_RTS		GPIO_GPIO (26)
 
-#define IRQ_GPIO_H3600_NPOWER_BUTTON    IRQ_GPIO0
-#define IRQ_GPIO_H3600_ACTION_BUTTON    IRQ_GPIO18
-#define IRQ_GPIO_H3600_PCMCIA_CD0	IRQ_GPIO17
+#define IRQ_GPIO_H3600_NPOWER_BUTTON	IRQ_GPIO0
+#define IRQ_GPIO_H3600_MICROCONTROLLER	IRQ_GPIO1
 #define IRQ_GPIO_H3600_PCMCIA_CD1	IRQ_GPIO10
-#define IRQ_GPIO_H3600_PCMCIA_IRQ0	IRQ_GPIO21
 #define IRQ_GPIO_H3600_PCMCIA_IRQ1	IRQ_GPIO11
+#define IRQ_GPIO_H3600_PCMCIA_CD0	IRQ_GPIO17
+#define IRQ_GPIO_H3600_PCMCIA_IRQ0	IRQ_GPIO21
+#define IRQ_GPIO_H3600_COM_DCD		IRQ_GPIO23
 #define IRQ_GPIO_H3600_OPT_IRQ		IRQ_GPIO24
-#define IRQ_GPIO_H3600_OPT_DET		IRQ_GPIO27
-#define IRQ_GPIO_H3600_COM_DCD          IRQ_GPIO23
-#define IRQ_GPIO_H3600_COM_CTS          IRQ_GPIO25
-
-#define EGPIO_H3600_VPP_ON		(1 << 0)
-#define EGPIO_H3600_CARD_RESET		(1 << 1)  /* reset the attached pcmcia/compactflash card.  active high. */
-#define EGPIO_H3600_OPT_RESET		(1 << 2)  /* reset the attached option pack.  active high. */
-#define EGPIO_H3600_CODEC_NRESET	(1 << 3)  /* reset the onboard UDA1341.  active low. */
-#define EGPIO_H3600_OPT_NVRAM_ON	(1 << 4)  /* apply power to optionpack nvram, active high. */
-#define EGPIO_H3600_OPT_ON		(1 << 5)  /* full power to option pack.  active high. */
-#define EGPIO_H3600_LCD_ON       	(1 << 6)  /* enable 3.3V to LCD.  active high. */
-#define EGPIO_H3600_RS232_ON		(1 << 7)  /* UART3 transceiver force on.  Active high. */
-#define EGPIO_H3600_LCD_PCI		(1 << 8)  /* LCD control IC enable.  active high. */
-#define EGPIO_H3600_IR_ON		(1 << 9)  /* apply power to IR module.  active high. */
-#define EGPIO_H3600_AUD_AMP_ON		(1 << 10) /* apply power to audio power amp.  active high. */
-#define EGPIO_H3600_AUD_PWR_ON		(1 << 11) /* apply poewr to reset of audio circuit.  active high. */
-#define EGPIO_H3600_QMUTE		(1 << 12) /* mute control for onboard UDA1341.  active high. */
-#define EGPIO_H3600_IR_FSEL		(1 << 13) /* IR speed select: 1->fast, 0->slow */
-#define EGPIO_H3600_LCD_5V_ON		(1 << 14) /* enable 5V to LCD. active high. */
-#define EGPIO_H3600_LVDD_ON		(1 << 15) /* enable 9V and -6.5V to LCD. */
+#define IRQ_GPIO_H3600_COM_CTS		IRQ_GPIO25
+
 
 #ifndef __ASSEMBLY__
-#define H3600_EGPIO	(*(volatile int *)0xf0000000)
-extern void clr_h3600_egpio(unsigned long x);
-extern void set_h3600_egpio(unsigned long x);
-#endif
+enum ipaq_model {
+	IPAQ_H3100,
+	IPAQ_H3600,
+	IPAQ_H3800
+};
+
+enum ipaq_egpio_type {
+	IPAQ_EGPIO_LCD_ON,	  /* Power to the LCD panel */
+	IPAQ_EGPIO_CODEC_NRESET,  /* Clear to reset the audio codec (remember to return high) */
+	IPAQ_EGPIO_AUDIO_ON,	  /* Audio power */
+	IPAQ_EGPIO_QMUTE,	  /* Audio muting */
+	IPAQ_EGPIO_OPT_NVRAM_ON,  /* Non-volatile RAM on extension sleeves (SPI interface) */
+	IPAQ_EGPIO_OPT_ON,	  /* Power to extension sleeves */
+	IPAQ_EGPIO_CARD_RESET,	  /* Reset PCMCIA cards on extension sleeve (???) */
+	IPAQ_EGPIO_OPT_RESET,	  /* Reset option pack (???) */
+	IPAQ_EGPIO_IR_ON,	  /* IR sensor/emitter power */
+	IPAQ_EGPIO_IR_FSEL,	  /* IR speed selection 1->fast, 0->slow */
+	IPAQ_EGPIO_RS232_ON,	  /* Maxim RS232 chip power */
+	IPAQ_EGPIO_VPP_ON,	  /* Turn on power to flash programming */
+};
+
+struct ipaq_model_ops {
+	enum ipaq_model model;
+	const char     *generic_name;
+	void	      (*initialize)(void);
+	void	      (*control)(enum ipaq_egpio_type, int);
+	unsigned long (*read)(void);
+};
+
+extern struct ipaq_model_ops ipaq_model_ops;
+
+#ifdef CONFIG_SA1100_H3XXX
+static __inline__ enum ipaq_model h3600_model( void ) {
+	return ipaq_model_ops.model;
+}
+
+static __inline__ const char * h3600_generic_name( void ) {
+	return ipaq_model_ops.generic_name;
+}
+
+static __inline__ void init_h3600_egpio( void ) {
+	if (ipaq_model_ops.initialize)
+		ipaq_model_ops.initialize();
+}
+
+static __inline__ void assign_h3600_egpio( enum ipaq_egpio_type x, int level ) {
+	if (ipaq_model_ops.control)
+		ipaq_model_ops.control(x,level);
+}
+
+static __inline__ void clr_h3600_egpio( enum ipaq_egpio_type x ) {
+	if (ipaq_model_ops.control)
+		ipaq_model_ops.control(x,0);
+}
+
+static __inline__ void set_h3600_egpio( enum ipaq_egpio_type x ) {
+	if (ipaq_model_ops.control)
+		ipaq_model_ops.control(x,1);
+}
+
+static __inline__ unsigned long read_h3600_egpio( void ) {
+	if (ipaq_model_ops.read)
+		return ipaq_model_ops.read();
+	return 0;
+}
+
+#else
+
+/*
+ * This allows some drives to loose some ifdefs
+ */
+#define assign_h3600_egpio(x,y)	do { } while (0)
+#define clr_h3600_egpio(x)	do { } while (0)
+#define set_h3600_egpio(x)	do { } while (0)
+#define read_h3600_egpio()	(0)
 
 #endif
+
+#endif /* ASSEMBLY */
+
+#endif /* _INCLUDE_H3600_H_ */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/h3600_gpio.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/h3600_gpio.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/h3600_gpio.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/h3600_gpio.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,540 @@
+/*
+ *
+ * Definitions for H3600 Handheld Computer
+ *
+ * Copyright 2000 Compaq Computer Corporation.
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Jamey Hicks.
+ *
+ * History:
+ *
+ * 2001-10-??   Andrew Christian   Added support for iPAQ H3800
+ *
+ */
+
+#ifndef _INCLUDE_H3600_GPIO_H_
+#define _INCLUDE_H3600_GPIO_H_
+
+/*
+ * GPIO lines that are common across ALL iPAQ models are in "h3600.h"
+ * This file contains machine-specific definitions
+ */
+
+#define GPIO_H3600_SUSPEND              GPIO_GPIO (0)
+/* GPIO[2:9] used by LCD on H3600/3800, used as GPIO on H3100 */
+#define GPIO_H3100_BT_ON		GPIO_GPIO (2)
+#define GPIO_H3100_GPIO3		GPIO_GPIO (3)
+#define GPIO_H3100_QMUTE		GPIO_GPIO (4)
+#define GPIO_H3100_LCD_3V_ON		GPIO_GPIO (5)
+#define GPIO_H3100_AUD_ON		GPIO_GPIO (6)
+#define GPIO_H3100_AUD_PWR_ON		GPIO_GPIO (7)
+#define GPIO_H3100_IR_ON		GPIO_GPIO (8)
+#define GPIO_H3100_IR_FSEL		GPIO_GPIO (9)
+
+/* for H3600, audio sample rate clock generator */
+#define GPIO_H3600_CLK_SET0		GPIO_GPIO (12)
+#define GPIO_H3600_CLK_SET1		GPIO_GPIO (13)
+
+#define GPIO_H3600_ACTION_BUTTON	GPIO_GPIO (18)
+#define GPIO_H3600_SOFT_RESET           GPIO_GPIO (20)   /* Also known as BATT_FAULT */
+#define GPIO_H3600_OPT_LOCK		GPIO_GPIO (22)
+#define GPIO_H3600_OPT_DET		GPIO_GPIO (27)
+
+/* H3800 specific pins */
+#define GPIO_H3800_AC_IN                GPIO_GPIO (12)
+#define GPIO_H3800_COM_DSR              GPIO_GPIO (13)
+#define GPIO_H3800_MMC_INT              GPIO_GPIO (18)
+#define GPIO_H3800_NOPT_IND             GPIO_GPIO (20)   /* Almost exactly the same as GPIO_H3600_OPT_DET */
+#define GPIO_H3800_OPT_BAT_FAULT        GPIO_GPIO (22)
+#define GPIO_H3800_CLK_OUT              GPIO_GPIO (27)
+
+/****************************************************/
+
+#define IRQ_GPIO_H3600_ACTION_BUTTON    IRQ_GPIO18
+#define IRQ_GPIO_H3600_OPT_DET		IRQ_GPIO27
+
+#define IRQ_GPIO_H3800_MMC_INT          IRQ_GPIO18
+#define IRQ_GPIO_H3800_NOPT_IND         IRQ_GPIO20 /* almost same as OPT_DET */
+
+/* H3100 / 3600 EGPIO pins */
+#define EGPIO_H3600_VPP_ON		(1 << 0)
+#define EGPIO_H3600_CARD_RESET		(1 << 1)   /* reset the attached pcmcia/compactflash card.  active high. */
+#define EGPIO_H3600_OPT_RESET		(1 << 2)   /* reset the attached option pack.  active high. */
+#define EGPIO_H3600_CODEC_NRESET	(1 << 3)   /* reset the onboard UDA1341.  active low. */
+#define EGPIO_H3600_OPT_NVRAM_ON	(1 << 4)   /* apply power to optionpack nvram, active high. */
+#define EGPIO_H3600_OPT_ON		(1 << 5)   /* full power to option pack.  active high. */
+#define EGPIO_H3600_LCD_ON		(1 << 6)   /* enable 3.3V to LCD.  active high. */
+#define EGPIO_H3600_RS232_ON		(1 << 7)   /* UART3 transceiver force on.  Active high. */
+
+/* H3600 only EGPIO pins */
+#define EGPIO_H3600_LCD_PCI		(1 << 8)   /* LCD control IC enable.  active high. */
+#define EGPIO_H3600_IR_ON		(1 << 9)   /* apply power to IR module.  active high. */
+#define EGPIO_H3600_AUD_AMP_ON		(1 << 10)  /* apply power to audio power amp.  active high. */
+#define EGPIO_H3600_AUD_PWR_ON		(1 << 11)  /* apply power to reset of audio circuit.  active high. */
+#define EGPIO_H3600_QMUTE		(1 << 12)  /* mute control for onboard UDA1341.  active high. */
+#define EGPIO_H3600_IR_FSEL		(1 << 13)  /* IR speed select: 1->fast, 0->slow */
+#define EGPIO_H3600_LCD_5V_ON		(1 << 14)  /* enable 5V to LCD. active high. */
+#define EGPIO_H3600_LVDD_ON		(1 << 15)  /* enable 9V and -6.5V to LCD. */
+
+/********************* H3800, ASIC #2 ********************/
+
+#define _H3800_ASIC2_Base            (H3600_EGPIO_VIRT)
+#define H3800_ASIC2_OFFSET(s,x,y)    \
+    (*((volatile s *) (_H3800_ASIC2_Base + _H3800_ASIC2_ ## x ## _Base + _H3800_ASIC2_ ## x ## _ ## y)))
+#define H3800_ASIC2_NOFFSET(s,x,n,y) \
+    (*((volatile s *) (_H3800_ASIC2_Base + _H3800_ASIC2_ ## x ## _ ## n ## _Base + _H3800_ASIC2_ ## x ## _ ## y)))
+
+#define _H3800_ASIC2_GPIO_Base                 0x0000
+#define _H3800_ASIC2_GPIO_Direction            0x0000    /* R/W, 16 bits 1:input, 0:output */
+#define _H3800_ASIC2_GPIO_InterruptType        0x0004    /* R/W, 12 bits 1:edge, 0:level          */
+#define _H3800_ASIC2_GPIO_InterruptEdgeType    0x0008    /* R/W, 12 bits 1:rising, 0:falling */
+#define _H3800_ASIC2_GPIO_InterruptLevelType   0x000C    /* R/W, 12 bits 1:high, 0:low  */
+#define _H3800_ASIC2_GPIO_InterruptClear       0x0010    /* W,   12 bits */
+#define _H3800_ASIC2_GPIO_InterruptFlag        0x0010    /* R,   12 bits - reads int status */
+#define _H3800_ASIC2_GPIO_Data                 0x0014    /* R/W, 16 bits */
+#define _H3800_ASIC2_GPIO_BattFaultOut         0x0018    /* R/W, 16 bit - sets level on batt fault */
+#define _H3800_ASIC2_GPIO_InterruptEnable      0x001c    /* R/W, 12 bits 1:enable interrupt */
+#define _H3800_ASIC2_GPIO_Alternate            0x003c    /* R/W, 12+1 bits - set alternate functions */
+
+#define H3800_ASIC2_GPIO_Direction          H3800_ASIC2_OFFSET( u16, GPIO, Direction )
+#define H3800_ASIC2_GPIO_InterruptType      H3800_ASIC2_OFFSET( u16, GPIO, InterruptType )
+#define H3800_ASIC2_GPIO_InterruptEdgeType  H3800_ASIC2_OFFSET( u16, GPIO, InterruptEdgeType )
+#define H3800_ASIC2_GPIO_InterruptLevelType H3800_ASIC2_OFFSET( u16, GPIO, InterruptLevelType )
+#define H3800_ASIC2_GPIO_InterruptClear     H3800_ASIC2_OFFSET( u16, GPIO, InterruptClear )
+#define H3800_ASIC2_GPIO_InterruptFlag      H3800_ASIC2_OFFSET( u16, GPIO, InterruptFlag )
+#define H3800_ASIC2_GPIO_Data               H3800_ASIC2_OFFSET( u16, GPIO, Data )
+#define H3800_ASIC2_GPIO_BattFaultOut       H3800_ASIC2_OFFSET( u16, GPIO, BattFaultOut )
+#define H3800_ASIC2_GPIO_InterruptEnable    H3800_ASIC2_OFFSET( u16, GPIO, InterruptEnable )
+#define H3800_ASIC2_GPIO_Alternate          H3800_ASIC2_OFFSET( u16, GPIO, Alternate )
+
+#define GPIO_H3800_ASIC2_IN_Y1_N          (1 << 0)   /* Output: Touchscreen Y1 */
+#define GPIO_H3800_ASIC2_IN_X0            (1 << 1)   /* Output: Touchscreen X0 */
+#define GPIO_H3800_ASIC2_IN_Y0            (1 << 2)   /* Output: Touchscreen Y0 */
+#define GPIO_H3800_ASIC2_IN_X1_N          (1 << 3)   /* Output: Touchscreen X1 */
+#define GPIO_H3800_ASIC2_BT_RST           (1 << 4)   /* Output: Bluetooth reset */
+#define GPIO_H3800_ASIC2_PEN_IRQ          (1 << 5)   /* Input : Pen down        */
+#define GPIO_H3800_ASIC2_SD_DETECT        (1 << 6)   /* Input : SD detect */
+#define GPIO_H3800_ASIC2_EAR_IN_N         (1 << 7)   /* Input : Audio jack plug inserted */
+#define GPIO_H3800_ASIC2_OPT_PCM_RESET    (1 << 8)   /* Output: */
+#define GPIO_H3800_ASIC2_OPT_RESET        (1 << 9)   /* Output: */
+#define GPIO_H3800_ASIC2_USB_DETECT_N     (1 << 10)  /* Input : */
+#define GPIO_H3800_ASIC2_SD_CON_SLT       (1 << 11)  /* Input : */
+
+#define _H3800_ASIC2_KPIO_Base                 0x0200
+#define _H3800_ASIC2_KPIO_Direction            0x0000    /* R/W, 12 bits 1:input, 0:output */
+#define _H3800_ASIC2_KPIO_InterruptType        0x0004    /* R/W, 12 bits 1:edge, 0:level          */
+#define _H3800_ASIC2_KPIO_InterruptEdgeType    0x0008    /* R/W, 12 bits 1:rising, 0:falling */
+#define _H3800_ASIC2_KPIO_InterruptLevelType   0x000C    /* R/W, 12 bits 1:high, 0:low  */
+#define _H3800_ASIC2_KPIO_InterruptClear       0x0010    /* W,   20 bits - 8 special */
+#define _H3800_ASIC2_KPIO_InterruptFlag        0x0010    /* R,   20 bits - 8 special - reads int status */
+#define _H3800_ASIC2_KPIO_Data                 0x0014    /* R/W, 16 bits */
+#define _H3800_ASIC2_KPIO_BattFaultOut         0x0018    /* R/W, 16 bit - sets level on batt fault */
+#define _H3800_ASIC2_KPIO_InterruptEnable      0x001c    /* R/W, 20 bits - 8 special */
+#define _H3800_ASIC2_KPIO_Alternate            0x003c    /* R/W, 6 bits */
+
+#define H3800_ASIC2_KPIO_Direction          H3800_ASIC2_OFFSET( u16, KPIO, Direction )
+#define H3800_ASIC2_KPIO_InterruptType      H3800_ASIC2_OFFSET( u16, KPIO, InterruptType )
+#define H3800_ASIC2_KPIO_InterruptEdgeType  H3800_ASIC2_OFFSET( u16, KPIO, InterruptEdgeType )
+#define H3800_ASIC2_KPIO_InterruptLevelType H3800_ASIC2_OFFSET( u16, KPIO, InterruptLevelType )
+#define H3800_ASIC2_KPIO_InterruptClear     H3800_ASIC2_OFFSET( u32, KPIO, InterruptClear )
+#define H3800_ASIC2_KPIO_InterruptFlag      H3800_ASIC2_OFFSET( u32, KPIO, InterruptFlag )
+#define H3800_ASIC2_KPIO_Data               H3800_ASIC2_OFFSET( u16, KPIO, Data )
+#define H3800_ASIC2_KPIO_BattFaultOut       H3800_ASIC2_OFFSET( u16, KPIO, BattFaultOut )
+#define H3800_ASIC2_KPIO_InterruptEnable    H3800_ASIC2_OFFSET( u32, KPIO, InterruptEnable )
+#define H3800_ASIC2_KPIO_Alternate          H3800_ASIC2_OFFSET( u16, KPIO, Alternate )
+
+#define H3800_ASIC2_KPIO_SPI_INT        ( 1 << 16 )
+#define H3800_ASIC2_KPIO_OWM_INT        ( 1 << 17 )
+#define H3800_ASIC2_KPIO_ADC_INT        ( 1 << 18 )
+#define H3800_ASIC2_KPIO_UART_0_INT     ( 1 << 19 )
+#define H3800_ASIC2_KPIO_UART_1_INT     ( 1 << 20 )
+#define H3800_ASIC2_KPIO_TIMER_0_INT    ( 1 << 21 )
+#define H3800_ASIC2_KPIO_TIMER_1_INT    ( 1 << 22 )
+#define H3800_ASIC2_KPIO_TIMER_2_INT    ( 1 << 23 )
+
+#define KPIO_H3800_ASIC2_RECORD_BTN_N     (1 << 0)   /* Record button */
+#define KPIO_H3800_ASIC2_KEY_5W1_N        (1 << 1)   /* Keypad */
+#define KPIO_H3800_ASIC2_KEY_5W2_N        (1 << 2)   /* */
+#define KPIO_H3800_ASIC2_KEY_5W3_N        (1 << 3)   /* */
+#define KPIO_H3800_ASIC2_KEY_5W4_N        (1 << 4)   /* */
+#define KPIO_H3800_ASIC2_KEY_5W5_N        (1 << 5)   /* */
+#define KPIO_H3800_ASIC2_KEY_LEFT_N       (1 << 6)   /* */
+#define KPIO_H3800_ASIC2_KEY_RIGHT_N      (1 << 7)   /* */
+#define KPIO_H3800_ASIC2_KEY_AP1_N        (1 << 8)   /* Old "Calendar" */
+#define KPIO_H3800_ASIC2_KEY_AP2_N        (1 << 9)   /* Old "Schedule" */
+#define KPIO_H3800_ASIC2_KEY_AP3_N        (1 << 10)  /* Old "Q"        */
+#define KPIO_H3800_ASIC2_KEY_AP4_N        (1 << 11)  /* Old "Undo"     */
+
+/* Alternate KPIO functions (set by default) */
+#define KPIO_ALT_H3800_ASIC2_KEY_5W1_N        (1 << 1)   /* Action key */
+#define KPIO_ALT_H3800_ASIC2_KEY_5W2_N        (1 << 2)   /* J1 of keypad input */
+#define KPIO_ALT_H3800_ASIC2_KEY_5W3_N        (1 << 3)   /* J2 of keypad input */
+#define KPIO_ALT_H3800_ASIC2_KEY_5W4_N        (1 << 4)   /* J3 of keypad input */
+#define KPIO_ALT_H3800_ASIC2_KEY_5W5_N        (1 << 5)   /* J4 of keypad input */
+
+#define _H3800_ASIC2_SPI_Base                  0x0400
+#define _H3800_ASIC2_SPI_Control               0x0000    /* R/W 8 bits */
+#define _H3800_ASIC2_SPI_Data                  0x0004    /* R/W 8 bits */
+#define _H3800_ASIC2_SPI_ChipSelectDisabled    0x0008    /* W   8 bits */
+
+#define H3800_ASIC2_SPI_Control             H3800_ASIC2_OFFSET( u8, SPI, Control )
+#define H3800_ASIC2_SPI_Data                H3800_ASIC2_OFFSET( u8, SPI, Data )
+#define H3800_ASIC2_SPI_ChipSelectDisabled  H3800_ASIC2_OFFSET( u8, SPI, ChipSelectDisabled )
+
+#define _H3800_ASIC2_PWM_0_Base                0x0600
+#define _H3800_ASIC2_PWM_1_Base                0x0700
+#define _H3800_ASIC2_PWM_TimeBase              0x0000    /* R/W 6 bits */
+#define _H3800_ASIC2_PWM_PeriodTime            0x0004    /* R/W 12 bits */
+#define _H3800_ASIC2_PWM_DutyTime              0x0008    /* R/W 12 bits */
+
+#define H3800_ASIC2_PWM_0_TimeBase          H3800_ASIC2_NOFFSET(  u8, PWM, 0, TimeBase )
+#define H3800_ASIC2_PWM_0_PeriodTime        H3800_ASIC2_NOFFSET( u16, PWM, 0, PeriodTime )
+#define H3800_ASIC2_PWM_0_DutyTime          H3800_ASIC2_NOFFSET( u16, PWM, 0, DutyTime )
+
+#define H3800_ASIC2_PWM_1_TimeBase          H3800_ASIC2_NOFFSET(  u8, PWM, 1, TimeBase )
+#define H3800_ASIC2_PWM_1_PeriodTime        H3800_ASIC2_NOFFSET( u16, PWM, 1, PeriodTime )
+#define H3800_ASIC2_PWM_1_DutyTime          H3800_ASIC2_NOFFSET( u16, PWM, 1, DutyTime )
+
+#define H3800_ASIC2_PWM_TIMEBASE_MASK             0xf    /* Low 4 bits sets time base, max = 8 */
+#define H3800_ASIC2_PWM_TIMEBASE_ENABLE    ( 1 << 4 )    /* Enable clock */
+#define H3800_ASIC2_PWM_TIMEBASE_CLEAR     ( 1 << 5 )    /* Clear the PWM */
+
+#define _H3800_ASIC2_LED_0_Base                0x0800
+#define _H3800_ASIC2_LED_1_Base                0x0880
+#define _H3800_ASIC2_LED_2_Base                0x0900
+#define _H3800_ASIC2_LED_TimeBase              0x0000    /* R/W  7 bits */
+#define _H3800_ASIC2_LED_PeriodTime            0x0004    /* R/W 12 bits */
+#define _H3800_ASIC2_LED_DutyTime              0x0008    /* R/W 12 bits */
+#define _H3800_ASIC2_LED_AutoStopCount         0x000c    /* R/W 16 bits */
+
+#define H3800_ASIC2_LED_0_TimeBase          H3800_ASIC2_NOFFSET(  u8, LED, 0, TimeBase )
+#define H3800_ASIC2_LED_0_PeriodTime        H3800_ASIC2_NOFFSET( u16, LED, 0, PeriodTime )
+#define H3800_ASIC2_LED_0_DutyTime          H3800_ASIC2_NOFFSET( u16, LED, 0, DutyTime )
+#define H3800_ASIC2_LED_0_AutoStopClock     H3800_ASIC2_NOFFSET( u16, LED, 0, AutoStopClock )
+
+#define H3800_ASIC2_LED_1_TimeBase          H3800_ASIC2_NOFFSET(  u8, LED, 1, TimeBase )
+#define H3800_ASIC2_LED_1_PeriodTime        H3800_ASIC2_NOFFSET( u16, LED, 1, PeriodTime )
+#define H3800_ASIC2_LED_1_DutyTime          H3800_ASIC2_NOFFSET( u16, LED, 1, DutyTime )
+#define H3800_ASIC2_LED_1_AutoStopClock     H3800_ASIC2_NOFFSET( u16, LED, 1, AutoStopClock )
+
+#define H3800_ASIC2_LED_2_TimeBase          H3800_ASIC2_NOFFSET(  u8, LED, 2, TimeBase )
+#define H3800_ASIC2_LED_2_PeriodTime        H3800_ASIC2_NOFFSET( u16, LED, 2, PeriodTime )
+#define H3800_ASIC2_LED_2_DutyTime          H3800_ASIC2_NOFFSET( u16, LED, 2, DutyTime )
+#define H3800_ASIC2_LED_2_AutoStopClock     H3800_ASIC2_NOFFSET( u16, LED, 2, AutoStopClock )
+
+#define H3800_ASIC2_LED_TIMEBASE_MASK            0x0f    /* Low 4 bits sets time base, max = 13 */
+#define H3800_ASIC2_LED_TIMEBASE_BLINK     ( 1 << 4 )    /* Enable blinking */
+#define H3800_ASIC2_LED_TIMEBASE_AUTOSTOP  ( 1 << 5 )
+#define H3800_ASIC2_LED_TIMEBASE_ALWAYS    ( 1 << 6 )    /* Enable blink always */
+
+#define _H3800_ASIC2_UART_0_Base               0x0A00
+#define _H3800_ASIC2_UART_1_Base               0x0C00
+#define _H3800_ASIC2_UART_Receive              0x0000    /* R    8 bits */
+#define _H3800_ASIC2_UART_Transmit             0x0000    /*   W  8 bits */
+#define _H3800_ASIC2_UART_IntEnable            0x0004    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_IntVerify            0x0008    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_FIFOControl          0x000c    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_LineControl          0x0010    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_ModemStatus          0x0014    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_LineStatus           0x0018    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_ScratchPad           0x001c    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_DivisorLatchL        0x0020    /* R/W  8 bits */
+#define _H3800_ASIC2_UART_DivisorLatchH        0x0024    /* R/W  8 bits */
+
+#define H3800_ASIC2_UART_0_Receive          H3800_ASIC2_NOFFSET(  u8, UART, 0, Receive )
+#define H3800_ASIC2_UART_0_Transmit         H3800_ASIC2_NOFFSET(  u8, UART, 0, Transmit )
+#define H3800_ASIC2_UART_0_IntEnable        H3800_ASIC2_NOFFSET(  u8, UART, 0, IntEnable )
+#define H3800_ASIC2_UART_0_IntVerify        H3800_ASIC2_NOFFSET(  u8, UART, 0, IntVerify )
+#define H3800_ASIC2_UART_0_FIFOControl      H3800_ASIC2_NOFFSET(  u8, UART, 0, FIFOControl )
+#define H3800_ASIC2_UART_0_LineControl      H3800_ASIC2_NOFFSET(  u8, UART, 0, LineControl )
+#define H3800_ASIC2_UART_0_ModemStatus      H3800_ASIC2_NOFFSET(  u8, UART, 0, ModemStatus )
+#define H3800_ASIC2_UART_0_LineStatus       H3800_ASIC2_NOFFSET(  u8, UART, 0, LineStatus )
+#define H3800_ASIC2_UART_0_ScratchPad       H3800_ASIC2_NOFFSET(  u8, UART, 0, ScratchPad )
+#define H3800_ASIC2_UART_0_DivisorLatchL    H3800_ASIC2_NOFFSET(  u8, UART, 0, DivisorLatchL )
+#define H3800_ASIC2_UART_0_DivisorLatchH    H3800_ASIC2_NOFFSET(  u8, UART, 0, DivisorLatchH )
+
+#define H3800_ASIC2_UART_1_Receive          H3800_ASIC2_NOFFSET(  u8, UART, 1, Receive )
+#define H3800_ASIC2_UART_1_Transmit         H3800_ASIC2_NOFFSET(  u8, UART, 1, Transmit )
+#define H3800_ASIC2_UART_1_IntEnable        H3800_ASIC2_NOFFSET(  u8, UART, 1, IntEnable )
+#define H3800_ASIC2_UART_1_IntVerify        H3800_ASIC2_NOFFSET(  u8, UART, 1, IntVerify )
+#define H3800_ASIC2_UART_1_FIFOControl      H3800_ASIC2_NOFFSET(  u8, UART, 1, FIFOControl )
+#define H3800_ASIC2_UART_1_LineControl      H3800_ASIC2_NOFFSET(  u8, UART, 1, LineControl )
+#define H3800_ASIC2_UART_1_ModemStatus      H3800_ASIC2_NOFFSET(  u8, UART, 1, ModemStatus )
+#define H3800_ASIC2_UART_1_LineStatus       H3800_ASIC2_NOFFSET(  u8, UART, 1, LineStatus )
+#define H3800_ASIC2_UART_1_ScratchPad       H3800_ASIC2_NOFFSET(  u8, UART, 1, ScratchPad )
+#define H3800_ASIC2_UART_1_DivisorLatchL    H3800_ASIC2_NOFFSET(  u8, UART, 1, DivisorLatchL )
+#define H3800_ASIC2_UART_1_DivisorLatchH    H3800_ASIC2_NOFFSET(  u8, UART, 1, DivisorLatchH )
+
+#define _H3800_ASIC2_TIMER_Base                0x0E00
+#define _H3800_ASIC2_TIMER_Command             0x0000    /* R/W  8 bits */
+
+#define H3800_ASIC2_TIMER_Command           H3800_ASIC2_OFFSET( u8, Timer, Command )
+
+#define H3800_ASIC2_TIMER_GAT_0            ( 1 << 0 )    /* Gate enable, counter 0 */
+#define H3800_ASIC2_TIMER_GAT_1            ( 1 << 1 )    /* Gate enable, counter 1 */
+#define H3800_ASIC2_TIMER_GAT_2            ( 1 << 2 )    /* Gate enable, counter 2 */
+#define H3800_ASIC2_TIMER_CLK_0            ( 1 << 3 )    /* Clock enable, counter 0 */
+#define H3800_ASIC2_TIMER_CLK_1            ( 1 << 4 )    /* Clock enable, counter 1 */
+#define H3800_ASIC2_TIMER_CLK_2            ( 1 << 5 )    /* Clock enable, counter 2 */
+#define H3800_ASIC2_TIMER_MODE_0           ( 1 << 6 )    /* Mode 0 enable, counter 0 */
+#define H3800_ASIC2_TIMER_MODE_1           ( 1 << 7 )    /* Mode 0 enable, counter 1 */
+
+#define _H3800_ASIC2_CLOCK_Base                0x1000
+#define _H3800_ASIC2_CLOCK_Enable              0x0000    /* R/W  18 bits */
+
+#define H3800_ASIC2_CLOCK_Enable            H3800_ASIC2_OFFSET( u32, CLOCK, Enable )
+
+#define H3800_ASIC2_CLOCK_AUDIO_1              0x0001    /* Enable 4.1 MHz clock for 8Khz and 4khz sample rate */
+#define H3800_ASIC2_CLOCK_AUDIO_2              0x0002    /* Enable 12.3 MHz clock for 48Khz and 32khz sample rate */
+#define H3800_ASIC2_CLOCK_AUDIO_3              0x0004    /* Enable 5.6 MHz clock for 11 kHZ sample rate */
+#define H3800_ASIC2_CLOCK_AUDIO_4              0x0008    /* Enable 11.289 MHz clock for 44 and 22 kHz sample rate */
+#define H3800_ASIC2_CLOCK_ADC              ( 1 << 4 )    /* 1.024 MHz clock to ADC */
+#define H3800_ASIC2_CLOCK_SPI              ( 1 << 5 )    /* 4.096 MHz clock to SPI */
+#define H3800_ASIC2_CLOCK_OWM              ( 1 << 6 )    /* 4.096 MHz clock to OWM */
+#define H3800_ASIC2_CLOCK_PWM              ( 1 << 7 )    /* 2.048 MHz clock to PWM */
+#define H3800_ASIC2_CLOCK_UART_1           ( 1 << 8 )    /* 24.576 MHz clock to UART1 (turn off bit 16) */
+#define H3800_ASIC2_CLOCK_UART_0           ( 1 << 9 )    /* 24.576 MHz clock to UART0 (turn off bit 17) */
+#define H3800_ASIC2_CLOCK_SD_1             ( 1 << 10 )   /* 16.934 MHz to SD */
+#define H3800_ASIC2_CLOCK_SD_2             ( 2 << 10 )   /* 24.576 MHz to SD */
+#define H3800_ASIC2_CLOCK_SD_3             ( 3 << 10 )   /* 33.869 MHz to SD */
+#define H3800_ASIC2_CLOCK_SD_4             ( 4 << 10 )   /* 49.152 MHz to SD */
+#define H3800_ASIC2_CLOCK_EX0              ( 1 << 13 )   /* Enable 32.768 kHz crystal */
+#define H3800_ASIC2_CLOCK_EX1              ( 1 << 14 )   /* Enable 24.576 MHz crystal */
+#define H3800_ASIC2_CLOCK_EX2              ( 1 << 15 )   /* Enable 33.869 MHz crystal */
+#define H3800_ASIC2_CLOCK_SLOW_UART_1      ( 1 << 16 )   /* Enable 3.686 MHz to UART1 (turn off bit 8) */
+#define H3800_ASIC2_CLOCK_SLOW_UART_0      ( 1 << 17 )   /* Enable 3.686 MHz to UART0 (turn off bit 9) */
+
+#define _H3800_ASIC2_ADC_Base                  0x1200
+#define _H3800_ASIC2_ADC_Multiplexer           0x0000    /* R/W 4 bits - low 3 bits set channel */
+#define _H3800_ASIC2_ADC_ControlStatus         0x0004    /* R/W 8 bits */
+#define _H3800_ASIC2_ADC_Data                  0x0008    /* R   10 bits */
+
+#define H3800_ASIC2_ADC_Multiplexer       H3800_ASIC2_OFFSET(  u8, ADC, Multiplexer )
+#define H3800_ASIC2_ADC_ControlStatus     H3800_ASIC2_OFFSET(  u8, ADC, ControlStatus )
+#define H3800_ASIC2_ADC_Data              H3800_ASIC2_OFFSET( u16, ADC, Data )
+
+#define H3600_ASIC2_ADC_MUX_CHANNEL_MASK         0x07    /* Low 3 bits sets channel.  max = 4 */
+#define H3600_ASIC2_ADC_MUX_CLKEN          ( 1 << 3 )    /* Enable clock */
+
+#define H3600_ASIC2_ADC_CSR_ADPS_MASK            0x0f    /* Low 4 bits sets prescale, max = 8 */
+#define H3600_ASIC2_ADC_CSR_FREE_RUN       ( 1 << 4 )
+#define H3600_ASIC2_ADC_CSR_INT_ENABLE     ( 1 << 5 )
+#define H3600_ASIC2_ADC_CSR_START          ( 1 << 6 )    /* Set to start conversion.  Goes to 0 when done */
+#define H3600_ASIC2_ADC_CSR_ENABLE         ( 1 << 7 )    /* 1:power up ADC, 0:power down */
+
+
+#define _H3800_ASIC2_INTR_Base                 0x1600
+#define _H3800_ASIC2_INTR_MaskAndFlag          0x0000    /* R/(W) 8bits */
+#define _H3800_ASIC2_INTR_ClockPrescale        0x0004    /* R/(W) 5bits */
+#define _H3800_ASIC2_INTR_TimerSet             0x0008    /* R/(W) 8bits */
+
+#define H3800_ASIC2_INTR_MaskAndFlag      H3800_ASIC2_OFFSET( u8, INTR, MaskAndFlag )
+#define H3800_ASIC2_INTR_ClockPrescale    H3800_ASIC2_OFFSET( u8, INTR, ClockPrescale )
+#define H3800_ASIC2_INTR_TimerSet         H3800_ASIC2_OFFSET( u8, INTR, TimerSet )
+
+#define H3800_ASIC2_INTR_GLOBAL_MASK       ( 1 << 0 )    /* Global interrupt mask */
+#define H3800_ASIC2_INTR_POWER_ON_RESET    ( 1 << 1 )    /* 01: Power on reset (bits 1 & 2 ) */
+#define H3800_ASIC2_INTR_EXTERNAL_RESET    ( 2 << 1 )    /* 10: External reset (bits 1 & 2 ) */
+#define H3800_ASIC2_INTR_MASK_UART_0       ( 1 << 4 )
+#define H3800_ASIC2_INTR_MASK_UART_1       ( 1 << 5 )
+#define H3800_ASIC2_INTR_MASK_TIMER        ( 1 << 6 )
+#define H3800_ASIC2_INTR_MASK_OWM          ( 1 << 7 )
+
+#define H3800_ASIC2_INTR_CLOCK_PRESCALE          0x0f    /* 4 bits, max 14 */
+#define H3800_ASIC2_INTR_SET               ( 1 << 4 )    /* Time base enable */
+
+
+#define _H3800_ASIC2_OWM_Base                  0x1800
+#define _H3800_ASIC2_OWM_Command               0x0000    /* R/W 4 bits command register */
+#define _H3800_ASIC2_OWM_Data                  0x0004    /* R/W 8 bits, transmit / receive buffer */
+#define _H3800_ASIC2_OWM_Interrupt             0x0008    /* R/W Command register */
+#define _H3800_ASIC2_OWM_InterruptEnable       0x000c    /* R/W Command register */
+#define _H3800_ASIC2_OWM_ClockDivisor          0x0010    /* R/W 5 bits of divisor and pre-scale */
+
+#define H3800_ASIC2_OWM_Command            H3800_ASIC2_OFFSET( u8, OWM, Command )
+#define H3800_ASIC2_OWM_Data               H3800_ASIC2_OFFSET( u8, OWM, Data )
+#define H3800_ASIC2_OWM_Interrupt          H3800_ASIC2_OFFSET( u8, OWM, Interrupt )
+#define H3800_ASIC2_OWM_InterruptEnable    H3800_ASIC2_OFFSET( u8, OWM, InterruptEnable )
+#define H3800_ASIC2_OWM_ClockDivisor       H3800_ASIC2_OFFSET( u8, OWM, ClockDivisor )
+
+#define H3800_ASIC2_OWM_CMD_ONE_WIRE_RESET ( 1 << 0 )    /* Set to force reset on 1-wire bus */
+#define H3800_ASIC2_OWM_CMD_SRA            ( 1 << 1 )    /* Set to switch to Search ROM accelerator mode */
+#define H3800_ASIC2_OWM_CMD_DQ_OUTPUT      ( 1 << 2 )    /* Write only - forces bus low */
+#define H3800_ASIC2_OWM_CMD_DQ_INPUT       ( 1 << 3 )    /* Read only - reflects state of bus */
+
+#define H3800_ASIC2_OWM_INT_PD             ( 1 << 0 )    /* Presence detect */
+#define H3800_ASIC2_OWM_INT_PDR            ( 1 << 1 )    /* Presence detect result */
+#define H3800_ASIC2_OWM_INT_TBE            ( 1 << 2 )    /* Transmit buffer empty */
+#define H3800_ASIC2_OWM_INT_TEMT           ( 1 << 3 )    /* Transmit shift register empty */
+#define H3800_ASIC2_OWM_INT_RBF            ( 1 << 4 )    /* Receive buffer full */
+
+#define H3800_ASIC2_OWM_INTEN_EPD          ( 1 << 0 )    /* Enable receive buffer full interrupt */
+#define H3800_ASIC2_OWM_INTEN_IAS          ( 1 << 1 )    /* Enable transmit shift register empty interrupt */
+#define H3800_ASIC2_OWM_INTEN_ETBE         ( 1 << 2 )    /* Enable transmit buffer empty interrupt */
+#define H3800_ASIC2_OWM_INTEN_ETMT         ( 1 << 3 )    /* INTR active state */
+#define H3800_ASIC2_OWM_INTEN_ERBF         ( 1 << 4 )    /* Enable presence detect interrupt */
+
+#define _H3800_ASIC2_FlashCtl_Base             0x1A00
+
+/****************************************************/
+/* H3800, ASIC #1
+ * This ASIC is accesed through ASIC #2, and
+ * mapped into the 1c00 - 1f00 region
+ */
+
+#define H3800_ASIC1_OFFSET(s,x,y)   \
+     (*((volatile s *) (_H3800_ASIC2_Base + _H3800_ASIC1_ ## x ## _Base + (_H3800_ASIC1_ ## x ## _ ## y << 1))))
+
+#define _H3800_ASIC1_MMC_Base             0x1c00
+
+#define _H3800_ASIC1_MMC_StartStopClock     0x00    /* R/W 8bit                                  */
+#define _H3800_ASIC1_MMC_Status             0x02    /* R   See below, default 0x0040             */
+#define _H3800_ASIC1_MMC_ClockRate          0x04    /* R/W 8bit, low 3 bits are clock divisor    */
+#define _H3800_ASIC1_MMC_SPIRegister        0x08    /* R/W 8bit, see below                       */
+#define _H3800_ASIC1_MMC_CmdDataCont        0x0a    /* R/W 8bit, write to start MMC adapter      */
+#define _H3800_ASIC1_MMC_ResponseTimeout    0x0c    /* R/W 8bit, clocks before response timeout  */
+#define _H3800_ASIC1_MMC_ReadTimeout        0x0e    /* R/W 16bit, clocks before received data timeout */
+#define _H3800_ASIC1_MMC_BlockLength        0x10    /* R/W 10bit */
+#define _H3800_ASIC1_MMC_NumOfBlocks        0x12    /* R/W 16bit, in block mode, number of blocks  */
+#define _H3800_ASIC1_MMC_InterruptMask      0x1a    /* R/W 8bit */
+#define _H3800_ASIC1_MMC_CommandNumber      0x1c    /* R/W 6 bits */
+#define _H3800_ASIC1_MMC_ArgumentH          0x1e    /* R/W 16 bits  */
+#define _H3800_ASIC1_MMC_ArgumentL          0x20    /* R/W 16 bits */
+#define _H3800_ASIC1_MMC_ResFifo            0x22    /* R   8 x 16 bits - contains response FIFO */
+#define _H3800_ASIC1_MMC_BufferPartFull     0x28    /* R/W 8 bits */
+
+#define H3800_ASIC1_MMC_StartStopClock    H3800_ASIC1_OFFSET(  u8, MMC, StartStopClock )
+#define H3800_ASIC1_MMC_Status            H3800_ASIC1_OFFSET( u16, MMC, Status )
+#define H3800_ASIC1_MMC_ClockRate         H3800_ASIC1_OFFSET(  u8, MMC, ClockRate )
+#define H3800_ASIC1_MMC_SPIRegister       H3800_ASIC1_OFFSET(  u8, MMC, SPIRegister )
+#define H3800_ASIC1_MMC_CmdDataCont       H3800_ASIC1_OFFSET(  u8, MMC, CmdDataCont )
+#define H3800_ASIC1_MMC_ResponseTimeout   H3800_ASIC1_OFFSET(  u8, MMC, ResponseTimeout )
+#define H3800_ASIC1_MMC_ReadTimeout       H3800_ASIC1_OFFSET( u16, MMC, ReadTimeout )
+#define H3800_ASIC1_MMC_BlockLength       H3800_ASIC1_OFFSET( u16, MMC, BlockLength )
+#define H3800_ASIC1_MMC_NumOfBlocks       H3800_ASIC1_OFFSET( u16, MMC, NumOfBlocks )
+#define H3800_ASIC1_MMC_InterruptMask     H3800_ASIC1_OFFSET(  u8, MMC, InterruptMask )
+#define H3800_ASIC1_MMC_CommandNumber     H3800_ASIC1_OFFSET(  u8, MMC, CommandNumber )
+#define H3800_ASIC1_MMC_ArgumentH         H3800_ASIC1_OFFSET( u16, MMC, ArgumentH )
+#define H3800_ASIC1_MMC_ArgumentL         H3800_ASIC1_OFFSET( u16, MMC, ArgumentL )
+#define H3800_ASIC1_MMC_ResFifo           H3800_ASIC1_OFFSET( u16, MMC, ResFifo )
+#define H3800_ASIC1_MMC_BufferPartFull    H3800_ASIC1_OFFSET(  u8, MMC, BufferPartFull )
+
+#define H3800_ASIC1_MMC_STOP_CLOCK                   (1 << 0)   /* Write to "StartStopClock" register */
+#define H3800_ASIC1_MMC_START_CLOCK                  (1 << 1)
+
+#define H3800_ASIC1_MMC_STATUS_READ_TIMEOUT          (1 << 0)
+#define H3800_ASIC1_MMC_STATUS_RESPONSE_TIMEOUT      (1 << 1)
+#define H3800_ASIC1_MMC_STATUS_CRC_WRITE_ERROR       (1 << 2)
+#define H3800_ASIC1_MMC_STATUS_CRC_READ_ERROR        (1 << 3)
+#define H3800_ASIC1_MMC_STATUS_SPI_READ_ERROR        (1 << 4)  /* SPI data token error received */
+#define H3800_ASIC1_MMC_STATUS_CRC_RESPONSE_ERROR    (1 << 5)
+#define H3800_ASIC1_MMC_STATUS_FIFO_EMPTY            (1 << 6)
+#define H3800_ASIC1_MMC_STATUS_FIFO_FULL             (1 << 7)
+#define H3800_ASIC1_MMC_STATUS_CLOCK_ENABLE          (1 << 8)  /* MultiMediaCard clock stopped */
+#define H3800_ASIC1_MMC_STATUS_DATA_TRANSFER_DONE    (1 << 11) /* Write operation, indicates transfer finished */
+#define H3800_ASIC1_MMC_STATUS_END_PROGRAM           (1 << 12) /* End write and read operations */
+#define H3800_ASIC1_MMC_STATUS_END_COMMAND_RESPONSE  (1 << 13) /* End command response */
+
+#define H3800_ASIC1_MMC_SPI_REG_SPI_ENABLE           (1 << 0)  /* Enables SPI mode */
+#define H3800_ASIC1_MMC_SPI_REG_CRC_ON               (1 << 1)  /* 1:turn on CRC    */
+#define H3800_ASIC1_MMC_SPI_REG_SPI_CS_ENABLE        (1 << 2)  /* 1:turn on SPI CS */
+#define H3800_ASIC1_MMC_SPI_REG_CS_ADDRESS_MASK      0x38      /* Bits 3,4,5 are the SPI CS relative address */
+
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE  0x00
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_R1           0x01
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_R2           0x02
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_R3           0x03
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_DATA_ENABLE         (1 << 2)  /* This command contains a data transfer */
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_WRITE               (1 << 3)  /* This data transfer is a write */
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_STREAM_MODE         (1 << 4)  /* This data transfer is in stream mode */
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_BUSY_BIT            (1 << 5)  /* Busy signal expected after current cmd */
+#define H3800_ASIC1_MMC_CMD_DATA_CONT_INITIALIZE          (1 << 6)  /* Enables the 80 bits for initializing card */
+
+#define H3800_ASIC1_MMC_INT_MASK_DATA_TRANSFER_DONE       (1 << 0)
+#define H3800_ASIC1_MMC_INT_MASK_PROGRAM_DONE             (1 << 1)
+#define H3800_ASIC1_MMC_INT_MASK_END_COMMAND_RESPONSE     (1 << 2)
+#define H3800_ASIC1_MMC_INT_MASK_BUFFER_READY             (1 << 3)
+
+#define H3800_ASIC1_MMC_BUFFER_PART_FULL                  (1 << 0)
+
+/********* GPIO **********/
+
+#define _H3800_ASIC1_GPIO_Base        0x1e00
+
+#define _H3800_ASIC1_GPIO_Mask          0x30    /* R/W 0:don't mask, 1:mask interrupt */
+#define _H3800_ASIC1_GPIO_Direction     0x32    /* R/W 0:input, 1:output              */
+#define _H3800_ASIC1_GPIO_Out           0x34    /* R/W 0:output low, 1:output high    */
+#define _H3800_ASIC1_GPIO_TriggerType   0x36    /* R/W 0:level, 1:edge                */
+#define _H3800_ASIC1_GPIO_EdgeTrigger   0x38    /* R/W 0:falling, 1:rising            */
+#define _H3800_ASIC1_GPIO_LevelTrigger  0x3A    /* R/W 0:low, 1:high level detect     */
+#define _H3800_ASIC1_GPIO_LevelStatus   0x3C    /* R/W 0:none, 1:detect               */
+#define _H3800_ASIC1_GPIO_EdgeStatus    0x3E    /* R/W 0:none, 1:detect               */
+#define _H3800_ASIC1_GPIO_State         0x40    /* R   See masks below  (default 0)         */
+#define _H3800_ASIC1_GPIO_Reset         0x42    /* R/W See masks below  (default 0x04)      */
+#define _H3800_ASIC1_GPIO_SleepMask     0x44    /* R/W 0:don't mask, 1:mask trigger in sleep mode  */
+#define _H3800_ASIC1_GPIO_SleepDir      0x46    /* R/W direction 0:input, 1:ouput in sleep mode    */
+#define _H3800_ASIC1_GPIO_SleepOut      0x48    /* R/W level 0:low, 1:high in sleep mode           */
+#define _H3800_ASIC1_GPIO_Status        0x4A    /* R   Pin status                                  */
+#define _H3800_ASIC1_GPIO_BattFaultDir  0x4C    /* R/W direction 0:input, 1:output in batt_fault   */
+#define _H3800_ASIC1_GPIO_BattFaultOut  0x4E    /* R/W level 0:low, 1:high in batt_fault           */
+
+#define H3800_ASIC1_GPIO_Mask         H3800_ASIC1_OFFSET( u16, GPIO, Mask )
+#define H3800_ASIC1_GPIO_Direction    H3800_ASIC1_OFFSET( u16, GPIO, Direction )
+#define H3800_ASIC1_GPIO_Out          H3800_ASIC1_OFFSET( u16, GPIO, Out )
+#define H3800_ASIC1_GPIO_TriggerType  H3800_ASIC1_OFFSET( u16, GPIO, TriggerType )
+#define H3800_ASIC1_GPIO_EdgeTrigger  H3800_ASIC1_OFFSET( u16, GPIO, EdgeTrigger )
+#define H3800_ASIC1_GPIO_LevelTrigger H3800_ASIC1_OFFSET( u16, GPIO, LevelTrigger )
+#define H3800_ASIC1_GPIO_LevelStatus  H3800_ASIC1_OFFSET( u16, GPIO, LevelStatus )
+#define H3800_ASIC1_GPIO_EdgeStatus   H3800_ASIC1_OFFSET( u16, GPIO, EdgeStatus )
+#define H3800_ASIC1_GPIO_State        H3800_ASIC1_OFFSET(  u8, GPIO, State )
+#define H3800_ASIC1_GPIO_Reset        H3800_ASIC1_OFFSET(  u8, GPIO, Reset )
+#define H3800_ASIC1_GPIO_SleepMask    H3800_ASIC1_OFFSET( u16, GPIO, SleepMask )
+#define H3800_ASIC1_GPIO_SleepDir     H3800_ASIC1_OFFSET( u16, GPIO, SleepDir )
+#define H3800_ASIC1_GPIO_SleepOut     H3800_ASIC1_OFFSET( u16, GPIO, SleepOut )
+#define H3800_ASIC1_GPIO_Status       H3800_ASIC1_OFFSET( u16, GPIO, Status )
+#define H3800_ASIC1_GPIO_BattFaultDir H3800_ASIC1_OFFSET( u16, GPIO, BattFaultDir )
+#define H3800_ASIC1_GPIO_BattFaultOut H3800_ASIC1_OFFSET( u16, GPIO, BattFaultOut )
+
+#define H3800_ASIC1_GPIO_STATE_MASK            (1 << 0)
+#define H3800_ASIC1_GPIO_STATE_DIRECTION       (1 << 1)
+#define H3800_ASIC1_GPIO_STATE_OUT             (1 << 2)
+#define H3800_ASIC1_GPIO_STATE_TRIGGER_TYPE    (1 << 3)
+#define H3800_ASIC1_GPIO_STATE_EDGE_TRIGGER    (1 << 4)
+#define H3800_ASIC1_GPIO_STATE_LEVEL_TRIGGER   (1 << 5)
+
+#define H3800_ASIC1_GPIO_RESET_SOFTWARE        (1 << 0)
+#define H3800_ASIC1_GPIO_RESET_AUTO_SLEEP      (1 << 1)
+#define H3800_ASIC1_GPIO_RESET_FIRST_PWR_ON    (1 << 2)
+
+/* These are all outputs */
+#define GPIO_H3800_ASIC1_IR_ON_N          (1 << 0)   /* Apply power to the IR Module */
+#define GPIO_H3800_ASIC1_SD_PWR_ON        (1 << 1)   /* Secure Digital power on */
+#define GPIO_H3800_ASIC1_RS232_ON         (1 << 2)   /* Turn on power to the RS232 chip ? */
+#define GPIO_H3800_ASIC1_PULSE_GEN        (1 << 3)   /* Goes to speaker / earphone */
+#define GPIO_H3800_ASIC1_CH_TIMER         (1 << 4)   /* */
+#define GPIO_H3800_ASIC1_LCD_5V_ON        (1 << 5)   /* Enables LCD_5V */
+#define GPIO_H3800_ASIC1_LCD_ON           (1 << 6)   /* Enables LCD_3V */
+#define GPIO_H3800_ASIC1_LCD_PCI          (1 << 7)   /* Connects to PDWN on LCD controller */
+#define GPIO_H3800_ASIC1_VGH_ON           (1 << 8)   /* Drives VGH on the LCD (+9??) */
+#define GPIO_H3800_ASIC1_VGL_ON           (1 << 9)   /* Drivers VGL on the LCD (-6??) */
+#define GPIO_H3800_ASIC1_FL_PWR_ON        (1 << 10)  /* Frontlight power on */
+#define GPIO_H3800_ASIC1_BT_PWR_ON        (1 << 11)  /* Bluetooth power on */
+#define GPIO_H3800_ASIC1_SPK_ON           (1 << 12)  /* */
+#define GPIO_H3800_ASIC1_EAR_ON_N         (1 << 13)  /* */
+#define GPIO_H3800_ASIC1_AUD_PWR_ON       (1 << 14)  /* */
+
+/* Write enable for the flash */
+
+#define _H3800_ASIC1_FlashWP_Base         0x1F00
+#define _H3800_ASIC1_FlashWP_VPP_ON         0x00    /* R   1: write, 0: protect */
+#define H3800_ASIC1_FlashWP_VPP_ON       H3800_ASIC1_OFFSET( u8, FlashWP, VPP_ON )
+
+#endif /* _INCLUDE_H3600_GPIO_H_ */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/hardware.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/hardware.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/hardware.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/hardware.h	Fri Mar 29 14:50:07 2002
@@ -60,6 +60,7 @@
    ( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START )
 
 #ifndef __ASSEMBLY__
+#include <asm/types.h>
 
 #if 0
 # define __REG(x)	(*((volatile u32 *)io_p2v(x)))
@@ -93,29 +94,38 @@
  * This must be called *before* the corresponding IRQ is registered.
  * Use this instead of directly setting GRER/GFER.
  */
-#define GPIO_FALLING_EDGE       1
-#define GPIO_RISING_EDGE        2
-#define GPIO_BOTH_EDGES         3
+#define GPIO_NO_EDGES		0
+#define GPIO_FALLING_EDGE	1
+#define GPIO_RISING_EDGE	2
+#define GPIO_BOTH_EDGES 	3
 #ifndef __ASSEMBLY__
 extern void set_GPIO_IRQ_edge( int gpio_mask, int edge_mask );
-
-/*
- * Return the current CPU clock frequency in units of 100kHz
- */
-extern unsigned short get_cclk_frequency(void);
-
 #endif
 
 
 /*
  * Implementation specifics.
  *
- * *** NOTE ***
+ *                      *** BIG FAT NOTE ***
+ *
  * Any definitions in these files should be prefixed by an identifier -
  * eg, ASSABET_UCB1300_IRQ  This will allow us to eleminate these
  * ifdefs, and lots of other preprocessor gunk elsewhere.
+ *
+ * Also, please try to add your entry in alphabetical order.  The
+ * initial ones below are the start of the alphabetical list.
+ *
+ * Do NOT add your ifdefs around your file.
  */
 
+#include "badge4.h"
+
+#include "frodo.h"
+
+#include "h3600.h"
+
+#include "system3.h"
+
 #ifdef CONFIG_SA1100_PANGOLIN
 #include "pangolin.h"
 #endif
@@ -145,10 +155,6 @@
 #include "empeg.h"
 #endif
 
-#ifdef CONFIG_SA1100_H3600
-#include "h3600.h"
-#endif
-
 #ifdef CONFIG_SA1100_ITSY
 #include "itsy.h"
 #endif
@@ -211,19 +217,4 @@
 #include "flexanet.h"
 #endif
 
-#ifdef CONFIG_SA1111
-
-/*
- * The SA1111 is always located at virtual 0xf4000000.
- */
-
-#define SA1111_VBASE		0xf4000000
-
-#define SA1111_p2v( x )         ((x) - SA1111_BASE + SA1111_VBASE)
-#define SA1111_v2p( x )         ((x) - SA1111_VBASE + SA1111_BASE)
-
-#include "SA-1111.h"
-
-#endif
-
 #endif  /* _ASM_ARCH_HARDWARE_H */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/ide.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/ide.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/ide.h	Sun Aug 12 17:36:24 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/ide.h	Fri Mar 29 14:50:07 2002
@@ -3,6 +3,9 @@
  *
  * Copyright (c) 1998 Hugo Fiennes & Nicolas Pitre
  *
+ * 26-feb-2002: Add support for 2d3D SA-1110 Development board
+ *              Abraham van der Merwe <abraham@2d3d.co.za>
+ *
  * 18-aug-2000: Cleanup by Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
  *              Get rid of the special ide_init_hwif_ports() functions
  *              and make a generalised function that can be used by all
@@ -34,6 +37,10 @@
 	if (machine_is_lart())
 		regincr = 1 << 1;
 
+	/* Frodo has the first 14 address lines unused */
+	if (machine_is_frodo())
+		regincr = 1 << 14;
+
 	memset(hw, 0, sizeof(*hw));
 
 	reg = (ide_ioreg_t)data_port;
@@ -124,6 +131,20 @@
         ide_register_hw(&hw, NULL);
 #endif
     }
+	else if (machine_is_frodo ()) {
+#ifdef CONFIG_SA1100_FRODO
+		hw_regs_t hw;
+
+		/* enable GPIO as interrupt line */
+		GPDR &= ~FRODO_IDE_GPIO;
+		set_GPIO_IRQ_edge (FRODO_IDE_GPIO,GPIO_RISING_EDGE);
+
+		/* init the interface */
+		ide_init_hwif_ports (&hw,FRODO_IDE_DATA,FRODO_IDE_CTRL,NULL);
+		hw.irq = FRODO_IDE_IRQ;
+		ide_register_hw (&hw,NULL);
+#endif
+	}
 }
 
 
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/irqs.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/irqs.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/irqs.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/irqs.h	Fri Mar 29 14:50:07 2002
@@ -4,154 +4,150 @@
  * Copyright (C) 1996 Russell King
  * Copyright (C) 1998 Deborah Wallach (updates for SA1100/Brutus).
  * Copyright (C) 1999 Nicolas Pitre (full GPIO irq isolation)
+ *
+ * 2001/11/14	RMK	Cleaned up and standardised a lot of the IRQs.
  */
-
 #include <linux/config.h>
 
-#define SA1100_IRQ(x)		(0 + (x))
-
-#define	IRQ_GPIO0		SA1100_IRQ(0)
-#define	IRQ_GPIO1		SA1100_IRQ(1)
-#define	IRQ_GPIO2		SA1100_IRQ(2)
-#define	IRQ_GPIO3		SA1100_IRQ(3)
-#define	IRQ_GPIO4		SA1100_IRQ(4)
-#define	IRQ_GPIO5		SA1100_IRQ(5)
-#define	IRQ_GPIO6		SA1100_IRQ(6)
-#define	IRQ_GPIO7		SA1100_IRQ(7)
-#define	IRQ_GPIO8		SA1100_IRQ(8)
-#define	IRQ_GPIO9		SA1100_IRQ(9)
-#define	IRQ_GPIO10		SA1100_IRQ(10)
-#define	IRQ_GPIO11_27		SA1100_IRQ(11)
-#define	IRQ_LCD  		SA1100_IRQ(12)	/* LCD controller           */
-#define	IRQ_Ser0UDC		SA1100_IRQ(13)	/* Ser. port 0 UDC          */
-#define	IRQ_Ser1SDLC		SA1100_IRQ(14)	/* Ser. port 1 SDLC         */
-#define	IRQ_Ser1UART		SA1100_IRQ(15)	/* Ser. port 1 UART         */
-#define	IRQ_Ser2ICP		SA1100_IRQ(16)	/* Ser. port 2 ICP          */
-#define	IRQ_Ser3UART		SA1100_IRQ(17)	/* Ser. port 3 UART         */
-#define	IRQ_Ser4MCP		SA1100_IRQ(18)	/* Ser. port 4 MCP          */
-#define	IRQ_Ser4SSP		SA1100_IRQ(19)	/* Ser. port 4 SSP          */
-#define	IRQ_DMA0 		SA1100_IRQ(20)	/* DMA controller channel 0 */
-#define	IRQ_DMA1 		SA1100_IRQ(21)	/* DMA controller channel 1 */
-#define	IRQ_DMA2 		SA1100_IRQ(22)	/* DMA controller channel 2 */
-#define	IRQ_DMA3 		SA1100_IRQ(23)	/* DMA controller channel 3 */
-#define	IRQ_DMA4 		SA1100_IRQ(24)	/* DMA controller channel 4 */
-#define	IRQ_DMA5 		SA1100_IRQ(25)	/* DMA controller channel 5 */
-#define	IRQ_OST0 		SA1100_IRQ(26)	/* OS Timer match 0         */
-#define	IRQ_OST1 		SA1100_IRQ(27)	/* OS Timer match 1         */
-#define	IRQ_OST2 		SA1100_IRQ(28)	/* OS Timer match 2         */
-#define	IRQ_OST3 		SA1100_IRQ(29)	/* OS Timer match 3         */
-#define	IRQ_RTC1Hz		SA1100_IRQ(30)	/* RTC 1 Hz clock           */
-#define	IRQ_RTCAlrm		SA1100_IRQ(31)	/* RTC Alarm                */
-
-#define	IRQ_GPIO_11_27(x)	(32 + (x) - 11)
-
-#define	IRQ_GPIO11		IRQ_GPIO_11_27(11)
-#define	IRQ_GPIO12		IRQ_GPIO_11_27(12)
-#define	IRQ_GPIO13		IRQ_GPIO_11_27(13)
-#define	IRQ_GPIO14		IRQ_GPIO_11_27(14)
-#define	IRQ_GPIO15		IRQ_GPIO_11_27(15)
-#define	IRQ_GPIO16		IRQ_GPIO_11_27(16)
-#define	IRQ_GPIO17		IRQ_GPIO_11_27(17)
-#define	IRQ_GPIO18		IRQ_GPIO_11_27(18)
-#define	IRQ_GPIO19		IRQ_GPIO_11_27(19)
-#define	IRQ_GPIO20		IRQ_GPIO_11_27(20)
-#define	IRQ_GPIO21		IRQ_GPIO_11_27(21)
-#define	IRQ_GPIO22		IRQ_GPIO_11_27(22)
-#define	IRQ_GPIO23		IRQ_GPIO_11_27(23)
-#define	IRQ_GPIO24		IRQ_GPIO_11_27(24)
-#define	IRQ_GPIO25		IRQ_GPIO_11_27(25)
-#define	IRQ_GPIO26		IRQ_GPIO_11_27(26)
-#define	IRQ_GPIO27		IRQ_GPIO_11_27(27)
-
-#define SA1100_GPIO_TO_IRQ(i)	(((i) < 11) ? SA1100_IRQ(i) : IRQ_GPIO_11_27(i))
-
-/* To get the GPIO number from an IRQ number */
-#define GPIO_11_27_IRQ(i)	(11 + (i) - 32)
-#define SA1100_IRQ_TO_GPIO(i) 	(((i) < 11) ? (i) : GPIO_11_27_IRQ(i))
-
-#define	NR_IRQS		(IRQ_GPIO27 + 1)
-
-
-#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_GRAPHICSMASTER)
-#define ADS_EXT_IRQ(x)	(IRQ_GPIO27 + 1 + (x))
-#undef NR_IRQS
-#define NR_IRQS		(ADS_EXT_IRQ(15) + 1)
-#endif
+#define	IRQ_GPIO0		0
+#define	IRQ_GPIO1		1
+#define	IRQ_GPIO2		2
+#define	IRQ_GPIO3		3
+#define	IRQ_GPIO4		4
+#define	IRQ_GPIO5		5
+#define	IRQ_GPIO6		6
+#define	IRQ_GPIO7		7
+#define	IRQ_GPIO8		8
+#define	IRQ_GPIO9		9
+#define	IRQ_GPIO10		10
+#define	IRQ_GPIO11_27		11
+#define	IRQ_LCD  		12	/* LCD controller           */
+#define	IRQ_Ser0UDC		13	/* Ser. port 0 UDC          */
+#define	IRQ_Ser1SDLC		14	/* Ser. port 1 SDLC         */
+#define	IRQ_Ser1UART		15	/* Ser. port 1 UART         */
+#define	IRQ_Ser2ICP		16	/* Ser. port 2 ICP          */
+#define	IRQ_Ser3UART		17	/* Ser. port 3 UART         */
+#define	IRQ_Ser4MCP		18	/* Ser. port 4 MCP          */
+#define	IRQ_Ser4SSP		19	/* Ser. port 4 SSP          */
+#define	IRQ_DMA0 		20	/* DMA controller channel 0 */
+#define	IRQ_DMA1 		21	/* DMA controller channel 1 */
+#define	IRQ_DMA2 		22	/* DMA controller channel 2 */
+#define	IRQ_DMA3 		23	/* DMA controller channel 3 */
+#define	IRQ_DMA4 		24	/* DMA controller channel 4 */
+#define	IRQ_DMA5 		25	/* DMA controller channel 5 */
+#define	IRQ_OST0 		26	/* OS Timer match 0         */
+#define	IRQ_OST1 		27	/* OS Timer match 1         */
+#define	IRQ_OST2 		28	/* OS Timer match 2         */
+#define	IRQ_OST3 		29	/* OS Timer match 3         */
+#define	IRQ_RTC1Hz		30	/* RTC 1 Hz clock           */
+#define	IRQ_RTCAlrm		31	/* RTC Alarm                */
+
+#define	IRQ_GPIO11		32
+#define	IRQ_GPIO12		33
+#define	IRQ_GPIO13		34
+#define	IRQ_GPIO14		35
+#define	IRQ_GPIO15		36
+#define	IRQ_GPIO16		37
+#define	IRQ_GPIO17		38
+#define	IRQ_GPIO18		39
+#define	IRQ_GPIO19		40
+#define	IRQ_GPIO20		41
+#define	IRQ_GPIO21		42
+#define	IRQ_GPIO22		43
+#define	IRQ_GPIO23		44
+#define	IRQ_GPIO24		45
+#define	IRQ_GPIO25		46
+#define	IRQ_GPIO26		47
+#define	IRQ_GPIO27		48
 
+/*
+ * To get the GPIO number from an IRQ number
+ */
+#define GPIO_11_27_IRQ(i)	((i) - 21)
 
-#if defined(CONFIG_SA1111)
+/*
+ * The next 16 interrupts are for board specific purposes.  Since
+ * the kernel can only run on one machine at a time, we can re-use
+ * these.  If you need more, increase IRQ_BOARD_END, but keep it
+ * within sensible limits.  IRQs 49 to 64 are available.
+ */
+#define IRQ_BOARD_START		49
+#define IRQ_BOARD_END		65
 
-#if defined(CONFIG_SA1100_GRAPHICSMASTER)
-#define	SA1111_IRQ(x)	(ADS_EXT_IRQ(15) + 1 + 1 + (x))
+#define IRQ_SA1111_START	(IRQ_BOARD_END)
+#define IRQ_GPAIN0		(IRQ_BOARD_END + 0)
+#define IRQ_GPAIN1		(IRQ_BOARD_END + 1)
+#define IRQ_GPAIN2		(IRQ_BOARD_END + 2)
+#define IRQ_GPAIN3		(IRQ_BOARD_END + 3)
+#define IRQ_GPBIN0		(IRQ_BOARD_END + 4)
+#define IRQ_GPBIN1		(IRQ_BOARD_END + 5)
+#define IRQ_GPBIN2		(IRQ_BOARD_END + 6)
+#define IRQ_GPBIN3		(IRQ_BOARD_END + 7)
+#define IRQ_GPBIN4		(IRQ_BOARD_END + 8)
+#define IRQ_GPBIN5		(IRQ_BOARD_END + 9)
+#define IRQ_GPCIN0		(IRQ_BOARD_END + 10)
+#define IRQ_GPCIN1		(IRQ_BOARD_END + 11)
+#define IRQ_GPCIN2		(IRQ_BOARD_END + 12)
+#define IRQ_GPCIN3		(IRQ_BOARD_END + 13)
+#define IRQ_GPCIN4		(IRQ_BOARD_END + 14)
+#define IRQ_GPCIN5		(IRQ_BOARD_END + 15)
+#define IRQ_GPCIN6		(IRQ_BOARD_END + 16)
+#define IRQ_GPCIN7		(IRQ_BOARD_END + 17)
+#define IRQ_MSTXINT		(IRQ_BOARD_END + 18)
+#define IRQ_MSRXINT		(IRQ_BOARD_END + 19)
+#define IRQ_MSSTOPERRINT	(IRQ_BOARD_END + 20)
+#define IRQ_TPTXINT		(IRQ_BOARD_END + 21)
+#define IRQ_TPRXINT		(IRQ_BOARD_END + 22)
+#define IRQ_TPSTOPERRINT	(IRQ_BOARD_END + 23)
+#define SSPXMTINT		(IRQ_BOARD_END + 24)
+#define SSPRCVINT		(IRQ_BOARD_END + 25)
+#define SSPROR			(IRQ_BOARD_END + 26)
+#define AUDXMTDMADONEA		(IRQ_BOARD_END + 32)
+#define AUDRCVDMADONEA		(IRQ_BOARD_END + 33)
+#define AUDXMTDMADONEB		(IRQ_BOARD_END + 34)
+#define AUDRCVDMADONEB		(IRQ_BOARD_END + 35)
+#define AUDTFSR			(IRQ_BOARD_END + 36)
+#define AUDRFSR			(IRQ_BOARD_END + 37)
+#define AUDTUR			(IRQ_BOARD_END + 38)
+#define AUDROR			(IRQ_BOARD_END + 39)
+#define AUDDTS			(IRQ_BOARD_END + 40)
+#define AUDRDD			(IRQ_BOARD_END + 41)
+#define AUDSTO			(IRQ_BOARD_END + 42)
+#define USBPWR			(IRQ_BOARD_END + 43)
+#define NIRQHCIM		(IRQ_BOARD_END + 44)
+#define IRQHCIBUFFACC		(IRQ_BOARD_END + 45)
+#define IRQHCIRMTWKP		(IRQ_BOARD_END + 46)
+#define NHCIMFCIR		(IRQ_BOARD_END + 47)
+#define USB_PORT_RESUME		(IRQ_BOARD_END + 48)
+#define S0_READY_NINT		(IRQ_BOARD_END + 49)
+#define S1_READY_NINT		(IRQ_BOARD_END + 50)
+#define S0_CD_VALID		(IRQ_BOARD_END + 51)
+#define S1_CD_VALID		(IRQ_BOARD_END + 52)
+#define S0_BVD1_STSCHG		(IRQ_BOARD_END + 53)
+#define S1_BVD1_STSCHG		(IRQ_BOARD_END + 54)
+
+/*
+ * Figure out the MAX IRQ number.
+ *
+ * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
+ * If graphicsclient or graphicsmaster, we don't have a SA1111.
+ * Otherwise, we have the standard IRQs only.
+ */
+#ifdef CONFIG_SA1111
+#define NR_IRQS			(S1_BVD1_STSCHG + 1)
+#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
+      defined(CONFIG_SA1100_GRAPHICSMASTER)
+#define NR_IRQS			(IRQ_BOARD_END)
 #else
-#define SA1111_IRQ(x)	(IRQ_GPIO27 + 1 + (x))
+#define NR_IRQS			(IRQ_BOARD_START)
 #endif
 
-#define GPAIN0		SA1111_IRQ(0)
-#define GPAIN1		SA1111_IRQ(1)
-#define GPAIN2		SA1111_IRQ(2)
-#define GPAIN3		SA1111_IRQ(3)
-#define GPBIN0		SA1111_IRQ(4)
-#define GPBIN1		SA1111_IRQ(5)
-#define GPBIN2		SA1111_IRQ(6)
-#define GPBIN3		SA1111_IRQ(7)
-#define GPBIN4		SA1111_IRQ(8)
-#define GPBIN5		SA1111_IRQ(9)
-#define GPCIN0		SA1111_IRQ(10)
-#define GPCIN1		SA1111_IRQ(11)
-#define GPCIN2		SA1111_IRQ(12)
-#define GPCIN3		SA1111_IRQ(13)
-#define GPCIN4		SA1111_IRQ(14)
-#define GPCIN5		SA1111_IRQ(15)
-#define GPCIN6		SA1111_IRQ(16)
-#define GPCIN7		SA1111_IRQ(17)
-#define MSTXINT		SA1111_IRQ(18)
-#define MSRXINT		SA1111_IRQ(19)
-#define MSSTOPERRINT	SA1111_IRQ(20)
-#define TPTXINT		SA1111_IRQ(21)
-#define TPRXINT		SA1111_IRQ(22)
-#define TPSTOPERRINT	SA1111_IRQ(23)
-#define SSPXMTINT	SA1111_IRQ(24)
-#define SSPRCVINT	SA1111_IRQ(25)
-#define SSPROR		SA1111_IRQ(26)
-#define AUDXMTDMADONEA	SA1111_IRQ(32)
-#define AUDRCVDMADONEA	SA1111_IRQ(33)
-#define AUDXMTDMADONEB	SA1111_IRQ(34)
-#define AUDRCVDMADONEB	SA1111_IRQ(35)
-#define AUDTFSR		SA1111_IRQ(36)
-#define AUDRFSR		SA1111_IRQ(37)
-#define AUDTUR		SA1111_IRQ(38)
-#define AUDROR		SA1111_IRQ(39)
-#define AUDDTS		SA1111_IRQ(40)
-#define AUDRDD		SA1111_IRQ(41)
-#define AUDSTO		SA1111_IRQ(42)
-#define USBPWR		SA1111_IRQ(43)
-#define NIRQHCIM	SA1111_IRQ(44)
-#define IRQHCIBUFFACC	SA1111_IRQ(45)
-#define IRQHCIRMTWKP	SA1111_IRQ(46)
-#define NHCIMFCIR	SA1111_IRQ(47)
-#define USB_PORT_RESUME	SA1111_IRQ(48)
-#define S0_READY_NINT	SA1111_IRQ(49)
-#define S1_READY_NINT	SA1111_IRQ(50)
-#define S0_CD_VALID	SA1111_IRQ(51)
-#define S1_CD_VALID	SA1111_IRQ(52)
-#define S0_BVD1_STSCHG	SA1111_IRQ(53)
-#define S1_BVD1_STSCHG	SA1111_IRQ(54)
-
-#define SA1111_IRQ_MAX	SA1111_IRQ(54)
-
-#undef NR_IRQS
-#define NR_IRQS		(SA1111_IRQ_MAX + 1)
-
-
-#ifdef CONFIG_ASSABET_NEPONSET
-
-#define MISC_IRQ0	SA1111_IRQ(55)
-#define MISC_IRQ1	SA1111_IRQ(56)
-
-#undef NR_IRQS
-#define NR_IRQS		(SA1111_IRQ_MAX + 3)
-
-#endif  /* CONFIG_ASSABET_NEPONSET */
+/*
+ * Board specific IRQs.  Define them here.
+ * Do not surround them with ifdefs.
+ */
+#define IRQ_NEPONSET_SMC9196	(IRQ_BOARD_START + 0)
+#define IRQ_NEPONSET_USAR	(IRQ_BOARD_START + 1)
 
-#endif  /* CONFIG_SA1111 */
+/* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */
+#define IRQ_SYSTEM3_SMC9196	(IRQ_BOARD_START + 0)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/jornada720.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/jornada720.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/jornada720.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/jornada720.h	Fri Mar 29 14:50:07 2002
@@ -11,7 +11,7 @@
 #error "include <asm/hardware.h> instead"
 #endif
 
-#define SA1111_BASE             (0x40000000)
+#define JORNADA720_SA1111_BASE		(0x40000000)
 
 #define GPIO_JORNADA720_KEYBOARD	GPIO_GPIO(0)
 #define GPIO_JORNADA720_MOUSE		GPIO_GPIO(9)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/keyboard.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/keyboard.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/keyboard.h	Thu Oct 25 13:53:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/keyboard.h	Fri Mar 29 14:50:07 2002
@@ -13,7 +13,7 @@
 #define kbd_disable_irq()	do { } while(0);
 #define kbd_enable_irq()	do { } while(0);
 
-extern void sa1111_kbd_init_hw(void);
+extern int sa1111_kbd_init_hw(void);
 extern void gc_kbd_init_hw(void);
 extern void smartio_kbd_init_hw(void);
 extern void cerf_kbd_init_hw(void);
@@ -31,6 +31,11 @@
 	if (machine_is_cerf())
 		cerf_kbd_init_hw();
 #endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+	/* TODO: add system 3 board specific functions here */
+	if (machine_is_pt_system3())
+		sa1111_kbd_init_hw();
+#endif
 }
 
 #endif  /* _SA1100_KEYBOARD_H */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/pangolin.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/pangolin.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/pangolin.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/pangolin.h	Fri Mar 29 14:50:07 2002
@@ -11,6 +11,8 @@
 #error "include <asm/hardware.h> instead"
 #endif
 
+#include <linux/config.h>
+
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
 
 /* GPIOs for which the generic definition doesn't say much */
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/pcmcia.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/pcmcia.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/pcmcia.h	Thu Apr 12 12:20:31 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/pcmcia.h	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-/*
- * linux/include/asm/arch/pcmcia.h
- *
- * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
- *
- * This file contains definitions for the low-level SA-1100 kernel PCMCIA
- * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
- */
-
-#ifndef _ASM_ARCH_PCMCIA
-#define _ASM_ARCH_PCMCIA
-
-
-/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
- * has support for two. This shows up in lots of hardwired ways, such
- * as the fact that MECR only has enough bits to configure two sockets.
- * Since it's so entrenched in the hardware, limiting the software
- * in this way doesn't seem too terrible.
- */
-#define SA1100_PCMCIA_MAX_SOCK   (2)
-
-
-#ifndef __ASSEMBLY__
-
-struct pcmcia_init {
-  void (*handler)(int irq, void *dev, struct pt_regs *regs);
-};
-
-struct pcmcia_state {
-  unsigned detect: 1,
-            ready: 1,
-             bvd1: 1,
-             bvd2: 1,
-           wrprot: 1,
-            vs_3v: 1,
-            vs_Xv: 1;
-};
-
-struct pcmcia_state_array {
-  unsigned int size;
-  struct pcmcia_state *state;
-};
-
-struct pcmcia_configure {
-  unsigned sock: 8,
-            vcc: 8,
-            vpp: 8,
-         output: 1,
-        speaker: 1,
-          reset: 1;
-};
-
-struct pcmcia_irq_info {
-  unsigned int sock;
-  unsigned int irq;
-};
-
-struct pcmcia_low_level {
-  int (*init)(struct pcmcia_init *);
-  int (*shutdown)(void);
-  int (*socket_state)(struct pcmcia_state_array *);
-  int (*get_irq_info)(struct pcmcia_irq_info *);
-  int (*configure_socket)(const struct pcmcia_configure *);
-};
-
-extern struct pcmcia_low_level *pcmcia_low_level;
-
-#endif  /* __ASSEMBLY__ */
-
-#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/pfs168.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/pfs168.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/pfs168.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/pfs168.h	Fri Mar 29 14:50:07 2002
@@ -44,7 +44,7 @@
  * PFS-168 definitions:
  */
 
-#define SA1111_BASE             (0x40000000)
+#define PFS168_SA1111_BASE	(0x40000000)
 
 #ifndef __ASSEMBLY__
 #define machine_has_neponset() (0)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/shannon.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/shannon.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/shannon.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/shannon.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,43 @@
+#ifndef _INCLUDE_SHANNON_H
+#define _INCLUDE_SHANNON_H
+
+/* taken from comp.os.inferno Tue, 12 Sep 2000 09:21:50 GMT,
+ * written by <forsyth@vitanuova.com> */
+
+#define SHANNON_GPIO_SPI_FLASH		GPIO_GPIO (0)	/* Output - Driven low, enables SPI to flash */
+#define SHANNON_GPIO_SPI_DSP		GPIO_GPIO (1)	/* Output - Driven low, enables SPI to DSP */
+/* lcd lower = GPIO 2-9 */
+#define SHANNON_GPIO_SPI_OUTPUT		GPIO_GPIO (10)	/* Output - SPI output to DSP */
+#define SHANNON_GPIO_SPI_INPUT		GPIO_GPIO (11)	/* Input  - SPI input from DSP */
+#define SHANNON_GPIO_SPI_CLOCK		GPIO_GPIO (12)	/* Output - Clock for SPI */
+#define SHANNON_GPIO_SPI_FRAME		GPIO_GPIO (13)	/* Output - Frame marker - not used */
+#define SHANNON_GPIO_SPI_RTS		GPIO_GPIO (14)	/* Input  - SPI Ready to Send */
+#define SHANNON_IRQ_GPIO_SPI_RTS	IRQ_GPIO14
+#define SHANNON_GPIO_SPI_CTS		GPIO_GPIO (15)	/* Output - SPI Clear to Send */
+#define SHANNON_GPIO_IRQ_CODEC		GPIO_GPIO (16)	/* in, irq from ucb1200 */
+#define SHANNON_IRQ_GPIO_IRQ_CODEC	IRQ_GPIO16
+#define SHANNON_GPIO_DSP_RESET		GPIO_GPIO (17)	/* Output - Drive low to reset the DSP */
+#define SHANNON_GPIO_CODEC_RESET	GPIO_GPIO (18)	/* Output - Drive low to reset the UCB1x00 */
+#define SHANNON_GPIO_U3_RTS		GPIO_GPIO (19)	/* ?? */
+#define SHANNON_GPIO_U3_CTS		GPIO_GPIO (20)	/* ?? */
+#define SHANNON_GPIO_SENSE_12V		GPIO_GPIO (21)	/* Input, 12v flash unprotect detected */
+#define SHANNON_GPIO_DISP_EN		GPIO_GPIO (22)	/* out */
+/* XXX GPIO 23 unaccounted for */
+#define SHANNON_GPIO_EJECT_0		GPIO_GPIO (24)	/* in */
+#define SHANNON_IRQ_GPIO_EJECT_0	IRQ_GPIO24
+#define SHANNON_GPIO_EJECT_1		GPIO_GPIO (25)	/* in */
+#define SHANNON_IRQ_GPIO_EJECT_1	IRQ_GPIO25
+#define SHANNON_GPIO_RDY_0		GPIO_GPIO (26)	/* in */
+#define SHANNON_IRQ_GPIO_RDY_0		IRQ_GPIO26
+#define SHANNON_GPIO_RDY_1		GPIO_GPIO (27)	/* in */
+#define SHANNON_IRQ_GPIO_RDY_1		IRQ_GPIO27
+
+/* MCP UCB codec GPIO pins... */
+
+#define SHANNON_UCB_GPIO_BACKLIGHT	9
+#define SHANNON_UCB_GPIO_BRIGHT_MASK  	7
+#define SHANNON_UCB_GPIO_BRIGHT		6
+#define SHANNON_UCB_GPIO_CONTRAST_MASK	0x3f
+#define SHANNON_UCB_GPIO_CONTRAST	0
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/simpad.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/simpad.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/simpad.h	Thu Oct 25 13:53:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/simpad.h	Fri Mar 29 14:50:07 2002
@@ -39,7 +39,6 @@
 
 #define IRQ_GPIO_UCB1300_IRQ IRQ_GPIO22 
 
-
 /*---  PCMCIA  ---*/
 #define GPIO_CF_CD              GPIO_GPIO24
 #define GPIO_CF_IRQ             GPIO_GPIO1          
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/system.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/system.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/system.h	Thu Oct 25 13:53:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/system.h	Fri Mar 29 14:50:07 2002
@@ -4,6 +4,7 @@
  * Copyright (c) 1999 Nicolas Pitre <nico@cam.org>
  */
 #include <linux/config.h>
+#include <asm/arch/hardware.h>
 
 static inline void arch_idle(void)
 {
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/system3.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/system3.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/system3.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/system3.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,111 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/system3.h
+ *
+ * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
+ *
+ * $Id: system3.h,v 1.2.4.2 2001/12/04 14:58:50 seletz Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Log: system3.h,v $
+ * Revision 1.2.4.2  2001/12/04 14:58:50  seletz
+ * - removed neponset hack
+ * - removed irq definitions (now in irqs.h)
+ *
+ * Revision 1.2.4.1  2001/12/04 12:51:18  seletz
+ * - re-added from linux_2_4_8_ac12_rmk1_np1_pt1
+ *
+ * Revision 1.2.2.2  2001/11/16 13:58:43  seletz
+ * - simplified cpld register access
+ *
+ * Revision 1.2.2.1  2001/10/15 16:17:20  seletz
+ * - first revision
+ *
+ *
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "include <asm/hardware.h> instead"
+#endif
+
+/* System 3 LCD */
+#define SYS3LCD			SKPEN0
+#define SYS3LCDBACKL	SKPEN1
+#define SYS3LCDBRIGHT	SKPWM0
+#define SYS3LCDCONTR	SKPWM1
+
+#define PT_CPLD_BASE		(0x10000000)
+#define PT_SMC_BASE			(0x18000000)
+#define PT_SA1111_BASE		(0x40000000)
+
+#define Ptcpld_p2v( x )	((x) - PT_CPLD_BASE + 0xf3000000)
+#define Ptcpld_v2p( x )	((x) - 0xf3000000 + PT_CPLD_BASE)
+
+#define _PT_SYSID	( PT_CPLD_BASE + 0x00 )
+#define _PT_IRQSR	( PT_CPLD_BASE + 0x24 )
+#define _PT_CTRL0	( PT_CPLD_BASE + 0x90 )
+#define _PT_CTRL1	( PT_CPLD_BASE + 0xA0 )
+#define _PT_CTRL2	( PT_CPLD_BASE + 0xB0 )
+
+#define PT_SYSID	(*((volatile u_char *)Ptcpld_p2v( _PT_SYSID )))
+#define PT_IRQSR	(*((volatile u_char *)Ptcpld_p2v( _PT_IRQSR )))
+#define PT_CTRL0	(*((volatile u_char *)Ptcpld_p2v( _PT_CTRL0 )))
+#define PT_CTRL1	(*((volatile u_char *)Ptcpld_p2v( _PT_CTRL1 )))
+#define PT_CTRL2	(*((volatile u_char *)Ptcpld_p2v( _PT_CTRL2 )))
+
+#define PTCTRL0_set( x )	PT_CTRL0 |= (x)
+#define PTCTRL1_set( x )	PT_CTRL1 |= (x)
+#define PTCTRL2_set( x )	PT_CTRL2 |= (x)
+#define PTCTRL0_clear( x )	PT_CTRL0 &= ~(x)
+#define PTCTRL1_clear( x )	PT_CTRL1 &= ~(x)
+#define PTCTRL2_clear( x )	PT_CTRL2 &= ~(x)
+
+/* System ID register */
+
+/* IRQ Source Register */
+#define PT_IRQ_LAN		( 1<<0 )
+#define PT_IRQ_X		( 1<<1 )
+#define PT_IRQ_SA1111	( 1<<2 )
+#define PT_IRQ_RS1		( 1<<3 )
+#define PT_IRQ_RS1_RING	( 1<<4 )
+#define PT_IRQ_RS1_DCD	( 1<<5 )
+#define PT_IRQ_RS1_DSR	( 1<<6 )
+#define PT_IRQ_RS2		( 1<<7 )
+
+/* FIXME */
+#define PT_IRQ_USAR		( 1<<1 )
+
+/* CTRL 0 */
+#define PT_CTRL0_USBSLAVE	( 1<<0 )
+#define PT_CTRL0_USBHOST	( 1<<1 )
+#define PT_CTRL0_LCD_BL		( 1<<2 )
+#define PT_CTRL0_LAN_EN		( 1<<3 )	/* active low */
+#define PT_CTRL0_IRDA_M(x)	( (((u_char)x)&0x03)<<4 )
+#define PT_CTRL0_IRDA_M0	( 1<<4 )
+#define PT_CTRL0_IRDA_M1	( 1<<5 )
+#define PT_CTRL0_IRDA_FSEL	( 1<<6 )
+#define PT_CTRL0_LCD_EN		( 1<<7 )
+
+#define PT_CTRL0_INIT	( PT_CTRL0_USBSLAVE | PT_CTRL0_USBHOST | \
+						PT_CTRL0_LCD_BL | PT_CTRL0_LAN_EN | PT_CTRL0_LCD_EN )
+
+/* CTRL 1 */
+#define PT_CTRL1_RS3_MUX(x) ( (((u_char)x)&0x03)<<0 )
+#define PT_CTRL1_RS3_MUX0	( 1<<0 )
+#define PT_CTRL1_RS3_MUX1	( 1<<1 )
+#define PT_CTRL1_RS3_RST	( 1<<2 )
+#define PT_CTRL1_RS3_RS485_TERM	( 1<<4 )
+#define PT_CTRL1_X			( 1<<4 )
+#define PT_CTRL1_PCMCIA_A0VPP	( 1<<6 )
+#define PT_CTRL1_PCMCIA_A1VPP	( 1<<7 )
+
+#define PT_RS3_MUX_ALIRS	( 0 )
+#define PT_RS3_MUX_IDATA	( 1 )
+#define PT_RS3_MUX_RADIO	( 2 )
+#define PT_RS3_MUX_RS485	( 3 )
+
+/* CTRL 2 */
+#define PT_CTRL2_RS1_RTS	( 1<<0 )
+#define PT_CTRL2_RS1_DTR	( 1<<1 )
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/time.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/time.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/time.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/time.h	Fri Mar 29 14:50:07 2002
@@ -10,7 +10,7 @@
  */
 
 
-#define RTC_DEF_DIVIDER		32768 - 1
+#define RTC_DEF_DIVIDER		(32768 - 1)
 #define RTC_DEF_TRIM            0
 
 static unsigned long __init sa1100_get_rtc_time(void)
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-sa1100/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-sa1100/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-sa1100/uncompress.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-sa1100/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -33,14 +33,16 @@
 
 	for (; *s; s++) {
 		/* wait for space in the UART's transmiter */
-		while (!(UART(UTSR1) & UTSR1_TNF));
+		while (!(UART(UTSR1) & UTSR1_TNF))
+			barrier();
 
 		/* send the character out. */
 		UART(UTDR) = *s;
 
 		/* if a LF, also do CR... */
 		if (*s == 10) {
-			while (!(UART(UTSR1) & UTSR1_TNF));
+			while (!(UART(UTSR1) & UTSR1_TNF))
+				barrier();
 			UART(UTDR) = 13;
 		}
 	}
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-shark/keyboard.h linux-2.4.19-pre5/include/asm-arm/arch-shark/keyboard.h
--- linux-2.4.19-pre4/include/asm-arm/arch-shark/keyboard.h	Thu Oct 25 13:53:55 2001
+++ linux-2.4.19-pre5/include/asm-arm/arch-shark/keyboard.h	Fri Mar 29 14:50:07 2002
@@ -6,6 +6,7 @@
  * (C) 1998 Russell King
  * (C) 1998 Phil Blundell
  */
+#include <linux/config.h>
 #include <linux/ioport.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -28,7 +29,6 @@
 
 static inline void kbd_init_hw(void)
 {
-	if (have_isa_bridge) {
 		k_setkeycode    = pckbd_setkeycode;
 		k_getkeycode    = pckbd_getkeycode;
 		k_translate     = pckbd_translate;
@@ -39,7 +39,6 @@
 		k_sysrq_xlate   = pckbd_sysrq_xlate;
 #endif
 		pckbd_init_hw();
-	}
 }
 
 /*
diff -urN linux-2.4.19-pre4/include/asm-arm/arch-tbox/uncompress.h linux-2.4.19-pre5/include/asm-arm/arch-tbox/uncompress.h
--- linux-2.4.19-pre4/include/asm-arm/arch-tbox/uncompress.h	Mon Sep 18 15:15:23 2000
+++ linux-2.4.19-pre5/include/asm-arm/arch-tbox/uncompress.h	Fri Mar 29 14:50:07 2002
@@ -18,10 +18,12 @@
   while (*s)
   {
     char c = *(s++);
-    while (!(__raw_readb(UARTBASE + 0x14) & 0x20));
+    while (!(__raw_readb(UARTBASE + 0x14) & 0x20))
+      barrier();
     __raw_writeb(c, UARTBASE);
     if (c == 10) {
-      while (!(__raw_readb(UARTBASE + 0x14) & 0x20));
+      while (!(__raw_readb(UARTBASE + 0x14) & 0x20))
+        barrier();
       __raw_writeb(13, UARTBASE);
     }
   }
diff -urN linux-2.4.19-pre4/include/asm-arm/checksum.h linux-2.4.19-pre5/include/asm-arm/checksum.h
--- linux-2.4.19-pre4/include/asm-arm/checksum.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/checksum.h	Fri Mar 29 14:50:07 2002
@@ -55,25 +55,24 @@
 	unsigned int sum, tmp1;
 
 	__asm__ __volatile__(
-	"ldr	%0, [%1], #4		@ ip_fast_csum
-	ldr	%3, [%1], #4
-	sub	%2, %2, #5
-	adds	%0, %0, %3
-	ldr	%3, [%1], #4
-	adcs	%0, %0, %3
-	ldr	%3, [%1], #4
-	adcs	%0, %0, %3
-1:	ldr	%3, [%1], #4
-	adcs	%0, %0, %3
-	tst	%2, #15
-	subne	%2, %2, #1
-	bne	1b
-	adc	%0, %0, #0
-	adds	%0, %0, %0, lsl #16
-	addcs	%0, %0, #0x10000
-	mvn	%0, %0
-	mov	%0, %0, lsr #16
-	"
+	"ldr	%0, [%1], #4		@ ip_fast_csum		\n\
+	ldr	%3, [%1], #4					\n\
+	sub	%2, %2, #5					\n\
+	adds	%0, %0, %3					\n\
+	ldr	%3, [%1], #4					\n\
+	adcs	%0, %0, %3					\n\
+	ldr	%3, [%1], #4					\n\
+1:	adcs	%0, %0, %3					\n\
+	ldr	%3, [%1], #4					\n\
+	tst	%2, #15			@ do this carefully	\n\
+	subne	%2, %2, #1		@ without destroying	\n\
+	bne	1b			@ the carry flag	\n\
+	adcs	%0, %0, %3					\n\
+	adc	%0, %0, #0					\n\
+	adds	%0, %0, %0, lsl #16				\n\
+	addcs	%0, %0, #0x10000				\n\
+	mvn	%0, %0						\n\
+	mov	%0, %0, lsr #16"
 	: "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (tmp1)
 	: "1" (iph), "2" (ihl)
 	: "cc");
@@ -87,7 +86,7 @@
 csum_fold(unsigned int sum)
 {
 	__asm__(
-	"adds	%0, %1, %1, lsl #16	@ csum_fold
+	"adds	%0, %1, %1, lsl #16	@ csum_fold		\n\
 	addcs	%0, %0, #0x10000"
 	: "=r" (sum)
 	: "r" (sum)
@@ -100,10 +99,10 @@
 		   unsigned int proto, unsigned int sum)
 {
 	__asm__(
-	"adds	%0, %1, %2		@ csum_tcpudp_nofold
-	adcs	%0, %0, %3
-	adcs	%0, %0, %4
-	adcs	%0, %0, %5
+	"adds	%0, %1, %2		@ csum_tcpudp_nofold	\n\
+	adcs	%0, %0, %3					\n\
+	adcs	%0, %0, %4					\n\
+	adcs	%0, %0, %5					\n\
 	adc	%0, %0, #0"
 	: "=&r"(sum)
 	: "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8)
@@ -119,13 +118,13 @@
 		  unsigned int proto, unsigned int sum)
 {
 	__asm__(
-	"adds	%0, %1, %2		@ csum_tcpudp_magic
-	adcs	%0, %0, %3
-	adcs	%0, %0, %4
-	adcs	%0, %0, %5
-	adc	%0, %0, #0
-	adds	%0, %0, %0, lsl #16
-	addcs	%0, %0, #0x10000
+	"adds	%0, %1, %2		@ csum_tcpudp_magic	\n\
+	adcs	%0, %0, %3					\n\
+	adcs	%0, %0, %4					\n\
+	adcs	%0, %0, %5					\n\
+	adc	%0, %0, #0					\n\
+	adds	%0, %0, %0, lsl #16				\n\
+	addcs	%0, %0, #0x10000				\n\
 	mvn	%0, %0"
 	: "=&r"(sum)
 	: "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len)), "Ir" (proto << 8)
diff -urN linux-2.4.19-pre4/include/asm-arm/hardware/clps7111.h linux-2.4.19-pre5/include/asm-arm/hardware/clps7111.h
--- linux-2.4.19-pre4/include/asm-arm/hardware/clps7111.h	Thu Apr 12 12:20:31 2001
+++ linux-2.4.19-pre5/include/asm-arm/hardware/clps7111.h	Fri Mar 29 14:50:07 2002
@@ -27,8 +27,10 @@
 
 #ifndef __ASSEMBLY__
 #define clps_readb(off)		__raw_readb(CLPS7111_BASE + (off))
+#define clps_readw(off)		__raw_readw(CLPS7111_BASE + (off))
 #define clps_readl(off)		__raw_readl(CLPS7111_BASE + (off))
 #define clps_writeb(val,off)	__raw_writeb(val, CLPS7111_BASE + (off))
+#define clps_writew(val,off)	__raw_writew(val, CLPS7111_BASE + (off))
 #define clps_writel(val,off)	__raw_writel(val, CLPS7111_BASE + (off))
 #endif
 
@@ -48,6 +50,7 @@
 #define INTSR1		(0x0240)
 #define INTMR1		(0x0280)
 #define LCDCON		(0x02c0)
+#define TC1D            (0x0300)
 #define TC2D		(0x0340)
 #define RTCDR		(0x0380)
 #define RTCMR		(0x03c0)
diff -urN linux-2.4.19-pre4/include/asm-arm/hardware/cs89712.h linux-2.4.19-pre5/include/asm-arm/hardware/cs89712.h
--- linux-2.4.19-pre4/include/asm-arm/hardware/cs89712.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/hardware/cs89712.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,49 @@
+/*
+ *  linux/include/asm-arm/hardware/cs89712.h
+ *
+ *  This file contains the hardware definitions of the CS89712
+ *  additional internal registers.
+ *
+ *  Copyright (C) 2001 Thomas Gleixner autronix automation <gleixner@autronix.de>
+ *			
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_HARDWARE_CS89712_H
+#define __ASM_HARDWARE_CS89712_H
+
+/*
+*	CS89712 additional registers
+*/
+                                  
+#define PCDR			0x0002	/* Port C Data register ---------------------------- */
+#define PCDDR			0x0042	/* Port C Data Direction register ------------------ */
+#define SDCONF			0x2300  /* SDRAM Configuration register ---------------------*/
+#define SDRFPR			0x2340  /* SDRAM Refresh period register --------------------*/
+
+#define SDCONF_ACTIVE		(1 << 10)
+#define SDCONF_CLKCTL		(1 << 9)
+#define SDCONF_WIDTH_4		(0 << 7)
+#define SDCONF_WIDTH_8		(1 << 7)
+#define SDCONF_WIDTH_16		(2 << 7)
+#define SDCONF_WIDTH_32		(3 << 7)
+#define SDCONF_SIZE_16		(0 << 5)
+#define SDCONF_SIZE_64		(1 << 5)
+#define SDCONF_SIZE_128		(2 << 5)
+#define SDCONF_SIZE_256		(3 << 5)
+#define SDCONF_CASLAT_2		(2)
+#define SDCONF_CASLAT_3		(3)
+
+#endif /* __ASM_HARDWARE_CS89712_H */
diff -urN linux-2.4.19-pre4/include/asm-arm/hardware/ep7212.h linux-2.4.19-pre5/include/asm-arm/hardware/ep7212.h
--- linux-2.4.19-pre4/include/asm-arm/hardware/ep7212.h	Thu Oct 25 13:53:55 2001
+++ linux-2.4.19-pre5/include/asm-arm/hardware/ep7212.h	Fri Mar 29 14:50:07 2002
@@ -23,8 +23,6 @@
 #ifndef __ASM_HARDWARE_EP7212_H
 #define __ASM_HARDWARE_EP7212_H
 
-#include <linux/config.h>
-
 /*
  * define EP7212_BASE to be the base address of the region
  * you want to access.
@@ -49,10 +47,6 @@
 #define INTSR3			0x2240
 #define INTMR3			0x2280
 #define LEDFLSH			0x22c0
-#if defined (CONFIG_ARCH_CDB89712)
-#define SDCONF			0x2300
-#define SDRFPR			0x2340
-#endif
 
 #define DAIR_DAIEN		(1 << 16)
 #define DAIR_ECS		(1 << 17)
@@ -86,19 +80,4 @@
 #define SYSCON3_FASTWAKE	(1 << 8)
 #define SYSCON3_DAIEN		(1 << 9)
 
-#if defined (CONFIG_ARCH_CDB89712)
-#define SDCONF_ACTIVE		(1 << 10)
-#define SDCONF_CLKCTL		(1 << 9)
-#define SDCONF_WIDTH_4		(0 << 7)
-#define SDCONF_WIDTH_8		(1 << 7)
-#define SDCONF_WIDTH_16		(2 << 7)
-#define SDCONF_WIDTH_32		(3 << 7)
-#define SDCONF_SIZE_16		(0 << 5)
-#define SDCONF_SIZE_64		(1 << 5)
-#define SDCONF_SIZE_128		(2 << 5)
-#define SDCONF_SIZE_256		(3 << 5)
-#define SDCONF_CASLAT_2		(2)
-#define SDCONF_CASLAT_3		(3)
-#endif
-
 #endif /* __ASM_HARDWARE_EP7212_H */
diff -urN linux-2.4.19-pre4/include/asm-arm/hardware/sa1111.h linux-2.4.19-pre5/include/asm-arm/hardware/sa1111.h
--- linux-2.4.19-pre4/include/asm-arm/hardware/sa1111.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-arm/hardware/sa1111.h	Fri Mar 29 14:50:07 2002
@@ -0,0 +1,678 @@
+/*
+ * linux/include/asm-arm/hardware/SA-1111.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
+ *
+ * This file contains definitions for the SA-1111 Companion Chip.
+ * (Structure and naming borrowed from SA-1101.h, by Peter Danielsson.)
+ *
+ * Macro that calculates real address for registers in the SA-1111
+ */
+
+#ifndef _ASM_ARCH_SA1111
+#define _ASM_ARCH_SA1111
+
+#include <asm/arch/bitfield.h>
+
+/*
+ * The SA1111 is always located at virtual 0xf4000000, and is always
+ * "native" endian.
+ */
+
+#define SA1111_VBASE		0xf4000000
+
+/* Don't use these! */
+#define SA1111_p2v( x )         ((x) - SA1111_BASE + SA1111_VBASE)
+#define SA1111_v2p( x )         ((x) - SA1111_VBASE + SA1111_BASE)
+
+#ifndef __ASSEMBLY__
+
+extern struct resource sa1111_resource;
+#define _SA1111(x)	((x) + sa1111_resource.start)
+#endif
+
+/*
+ * 26 bits of the SA-1110 address bus are available to the SA-1111.
+ * Use these when feeding target addresses to the DMA engines.
+ */
+
+#define SA1111_ADDR_WIDTH	(26)
+#define SA1111_ADDR_MASK	((1<<SA1111_ADDR_WIDTH)-1)
+#define SA1111_DMA_ADDR(x)	((x)&SA1111_ADDR_MASK)
+
+/*
+ * Don't ask the (SAC) DMA engines to move less than this amount.
+ */
+
+#define SA1111_SAC_DMA_MIN_XFER	(0x800)
+
+/*
+ * SA1111 register definitions.
+ */
+#define __CCREG(x)	__REGP(SA1111_VBASE + (x))
+
+/* System Bus Interface (SBI)
+ *
+ * Registers
+ *    SKCR	Control Register
+ *    SMCR	Shared Memory Controller Register
+ *    SKID	ID Register
+ */
+#define SA1111_SKCR	0x0000
+#define SA1111_SMCR	0x0004
+#define SA1111_SKID	0x0008
+
+#define _SBI_SKCR	_SA1111(SA1111_SKCR)
+#define _SBI_SMCR	_SA1111(SA1111_SMCR)
+#define _SBI_SKID	_SA1111(SA1111_SKID)
+
+#if LANGUAGE == C
+
+#define SBI_SKCR	__CCREG(SA1111_SKCR)
+#define SBI_SMCR	__CCREG(SA1111_SMCR)
+#define SBI_SKID	__CCREG(SA1111_SKID)
+
+#endif  /* LANGUAGE == C */
+
+#define SKCR_PLL_BYPASS	(1<<0)
+#define SKCR_RCLKEN	(1<<1)
+#define SKCR_SLEEP	(1<<2)
+#define SKCR_DOZE	(1<<3)
+#define SKCR_VCO_OFF	(1<<4)
+#define SKCR_SCANTSTEN	(1<<5)
+#define SKCR_CLKTSTEN	(1<<6)
+#define SKCR_RDYEN	(1<<7)
+#define SKCR_SELAC	(1<<8)
+#define SKCR_OPPC	(1<<9)
+#define SKCR_PLLTSTEN	(1<<10)
+#define SKCR_USBIOTSTEN	(1<<11)
+/*
+ * Don't believe the specs!  Take them, throw them outside.  Leave them
+ * there for a week.  Spit on them.  Walk on them.  Stamp on them.
+ * Pour gasoline over them and finally burn them.  Now think about coding.
+ *  - The October 1999 errata (278260-007) says its bit 13, 1 to enable.
+ *  - The Feb 2001 errata (278260-010) says that the previous errata
+ *    (278260-009) is wrong, and its bit actually 12, fixed in spec
+ *    278242-003.
+ *  - The SA1111 manual (278242) says bit 12, but 0 to enable.
+ *  - Reality is bit 13, 1 to enable.
+ *      -- rmk
+ */
+#define SKCR_OE_EN	(1<<13)
+
+#define SMCR_DTIM	(1<<0)
+#define SMCR_MBGE	(1<<1)
+#define SMCR_DRAC_0	(1<<2)
+#define SMCR_DRAC_1	(1<<3)
+#define SMCR_DRAC_2	(1<<4)
+#define SMCR_DRAC	Fld(3, 2)
+#define SMCR_CLAT	(1<<5)
+
+#define SKID_SIREV_MASK	(0x000000f0)
+#define SKID_MTREV_MASK (0x0000000f)
+#define SKID_ID_MASK	(0xffffff00)
+#define SKID_SA1111_ID	(0x690cc200)
+
+/*
+ * System Controller
+ *
+ * Registers
+ *    SKPCR	Power Control Register
+ *    SKCDR	Clock Divider Register
+ *    SKAUD	Audio Clock Divider Register
+ *    SKPMC	PS/2 Mouse Clock Divider Register
+ *    SKPTC	PS/2 Track Pad Clock Divider Register
+ *    SKPEN0	PWM0 Enable Register
+ *    SKPWM0	PWM0 Clock Register
+ *    SKPEN1	PWM1 Enable Register
+ *    SKPWM1	PWM1 Clock Register
+ */
+
+#define _SKPCR		_SA1111(0x0200)
+#define _SKCDR		_SA1111(0x0204)
+#define _SKAUD		_SA1111(0x0208)
+#define _SKPMC		_SA1111(0x020c)
+#define _SKPTC		_SA1111(0x0210)
+#define _SKPEN0		_SA1111(0x0214)
+#define _SKPWM0		_SA1111(0x0218)
+#define _SKPEN1		_SA1111(0x021c)
+#define _SKPWM1		_SA1111(0x0220)
+
+#if LANGUAGE == C
+
+#define SKPCR		__CCREG(0x0200)
+#define SKCDR		__CCREG(0x0204)
+#define SKAUD		__CCREG(0x0208)
+#define SKPMC		__CCREG(0x020c)
+#define SKPTC		__CCREG(0x0210)
+#define SKPEN0		__CCREG(0x0214)
+#define SKPWM0		__CCREG(0x0218)
+#define SKPEN1		__CCREG(0x021c)
+#define SKPWM1		__CCREG(0x0220)
+
+#endif  /* LANGUAGE == C */
+
+#define SKPCR_UCLKEN	(1<<0)
+#define SKPCR_ACCLKEN	(1<<1)
+#define SKPCR_I2SCLKEN	(1<<2)
+#define SKPCR_L3CLKEN	(1<<3)
+#define SKPCR_SCLKEN	(1<<4)
+#define SKPCR_PMCLKEN	(1<<5)
+#define SKPCR_PTCLKEN	(1<<6)
+#define SKPCR_DCLKEN	(1<<7)
+#define SKPCR_PWMCLKEN	(1<<8)
+
+/*
+ * USB Host controller
+ */
+#define _USB_OHCI_OP_BASE	_SA1111( 0x400 )
+#define _USB_STATUS		_SA1111( 0x518 )
+#define _USB_RESET		_SA1111( 0x51c )
+#define _USB_INTERRUPTEST	_SA1111( 0x520 )
+
+#define _USB_EXTENT		(_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
+
+#if LANGUAGE == C
+
+#define USB_OHCI_OP_BASE	__CCREG(0x0400)
+#define USB_STATUS		__CCREG(0x0518)
+#define USB_RESET		__CCREG(0x051c)
+#define USB_INTERRUPTEST	__CCReG(0x0520)
+
+#endif  /* LANGUAGE == C */
+
+#define USB_RESET_FORCEIFRESET	(1 << 0)
+#define USB_RESET_FORCEHCRESET	(1 << 1)
+#define USB_RESET_CLKGENRESET	(1 << 2)
+#define USB_RESET_SIMSCALEDOWN	(1 << 3)
+#define USB_RESET_USBINTTEST	(1 << 4)
+#define USB_RESET_SLEEPSTBYEN	(1 << 5)
+#define USB_RESET_PWRSENSELOW	(1 << 6)
+#define USB_RESET_PWRCTRLLOW	(1 << 7)
+
+/*
+ * Serial Audio Controller
+ *
+ * Registers
+ *    SACR0             Serial Audio Common Control Register
+ *    SACR1             Serial Audio Alternate Mode (I2C/MSB) Control Register
+ *    SACR2             Serial Audio AC-link Control Register
+ *    SASR0             Serial Audio I2S/MSB Interface & FIFO Status Register
+ *    SASR1             Serial Audio AC-link Interface & FIFO Status Register
+ *    SASCR             Serial Audio Status Clear Register
+ *    L3_CAR            L3 Control Bus Address Register
+ *    L3_CDR            L3 Control Bus Data Register
+ *    ACCAR             AC-link Command Address Register
+ *    ACCDR             AC-link Command Data Register
+ *    ACSAR             AC-link Status Address Register
+ *    ACSDR             AC-link Status Data Register
+ *    SADTCS            Serial Audio DMA Transmit Control/Status Register
+ *    SADTSA            Serial Audio DMA Transmit Buffer Start Address A
+ *    SADTCA            Serial Audio DMA Transmit Buffer Count Register A
+ *    SADTSB            Serial Audio DMA Transmit Buffer Start Address B
+ *    SADTCB            Serial Audio DMA Transmit Buffer Count Register B
+ *    SADRCS            Serial Audio DMA Receive Control/Status Register
+ *    SADRSA            Serial Audio DMA Receive Buffer Start Address A
+ *    SADRCA            Serial Audio DMA Receive Buffer Count Register A
+ *    SADRSB            Serial Audio DMA Receive Buffer Start Address B
+ *    SADRCB            Serial Audio DMA Receive Buffer Count Register B
+ *    SAITR             Serial Audio Interrupt Test Register
+ *    SADR              Serial Audio Data Register (16 x 32-bit)
+ */
+
+#define _SACR0          _SA1111( 0x0600 )
+#define _SACR1          _SA1111( 0x0604 )
+#define _SACR2          _SA1111( 0x0608 )
+#define _SASR0          _SA1111( 0x060c )
+#define _SASR1          _SA1111( 0x0610 )
+#define _SASCR          _SA1111( 0x0618 )
+#define _L3_CAR         _SA1111( 0x061c )
+#define _L3_CDR         _SA1111( 0x0620 )
+#define _ACCAR          _SA1111( 0x0624 )
+#define _ACCDR          _SA1111( 0x0628 )
+#define _ACSAR          _SA1111( 0x062c )
+#define _ACSDR          _SA1111( 0x0630 )
+#define _SADTCS         _SA1111( 0x0634 )
+#define _SADTSA         _SA1111( 0x0638 )
+#define _SADTCA         _SA1111( 0x063c )
+#define _SADTSB         _SA1111( 0x0640 )
+#define _SADTCB         _SA1111( 0x0644 )
+#define _SADRCS         _SA1111( 0x0648 )
+#define _SADRSA         _SA1111( 0x064c )
+#define _SADRCA         _SA1111( 0x0650 )
+#define _SADRSB         _SA1111( 0x0654 )
+#define _SADRCB         _SA1111( 0x0658 )
+#define _SAITR          _SA1111( 0x065c )
+#define _SADR           _SA1111( 0x0680 )
+
+#if LANGUAGE == C
+
+#define SACR0		__CCREG(0x0600)
+#define SACR1		__CCREG(0x0604)
+#define SACR2		__CCREG(0x0608)
+#define SASR0		__CCREG(0x060c)
+#define SASR1		__CCREG(0x0610)
+#define SASCR		__CCREG(0x0618)
+#define L3_CAR		__CCREG(0x061c)
+#define L3_CDR		__CCREG(0x0620)
+#define ACCAR		__CCREG(0x0624)
+#define ACCDR		__CCREG(0x0628)
+#define ACSAR		__CCREG(0x062c)
+#define ACSDR		__CCREG(0x0630)
+#define SADTCS		__CCREG(0x0634)
+#define SADTSA		__CCREG(0x0638)
+#define SADTCA		__CCREG(0x063c)
+#define SADTSB		__CCREG(0x0640)
+#define SADTCB		__CCREG(0x0644)
+#define SADRCS		__CCREG(0x0648)
+#define SADRSA		__CCREG(0x064c)
+#define SADRCA		__CCREG(0x0650)
+#define SADRSB		__CCREG(0x0654)
+#define SADRCB		__CCREG(0x0658)
+#define SAITR		__CCREG(0x065c)
+#define SADR		__CCREG(0x0680)
+
+#endif  /* LANGUAGE == C */
+
+#define SACR0_ENB	(1<<0)
+#define SACR0_BCKD	(1<<2)
+#define SACR0_RST	(1<<3)
+
+#define SACR1_AMSL	(1<<0)
+#define SACR1_L3EN	(1<<1)
+#define SACR1_L3MB	(1<<2)
+#define SACR1_DREC	(1<<3)
+#define SACR1_DRPL	(1<<4)
+#define SACR1_ENLBF	(1<<5)
+
+#define SACR2_TS3V	(1<<0)
+#define SACR2_TS4V	(1<<1)
+#define SACR2_WKUP	(1<<2)
+#define SACR2_DREC	(1<<3)
+#define SACR2_DRPL	(1<<4)
+#define SACR2_ENLBF	(1<<5)
+#define SACR2_RESET	(1<<6)
+
+#define SASR0_TNF	(1<<0)
+#define SASR0_RNE	(1<<1)
+#define SASR0_BSY	(1<<2)
+#define SASR0_TFS	(1<<3)
+#define SASR0_RFS	(1<<4)
+#define SASR0_TUR	(1<<5)
+#define SASR0_ROR	(1<<6)
+#define SASR0_L3WD	(1<<16)
+#define SASR0_L3RD	(1<<17)
+
+#define SASR1_TNF	(1<<0)
+#define SASR1_RNE	(1<<1)
+#define SASR1_BSY	(1<<2)
+#define SASR1_TFS	(1<<3)
+#define SASR1_RFS	(1<<4)
+#define SASR1_TUR	(1<<5)
+#define SASR1_ROR	(1<<6)
+#define SASR1_CADT	(1<<16)
+#define SASR1_SADR	(1<<17)
+#define SASR1_RSTO	(1<<18)
+#define SASR1_CLPM	(1<<19)
+#define SASR1_CRDY	(1<<20)
+#define SASR1_RS3V	(1<<21)
+#define SASR1_RS4V	(1<<22)
+
+#define SASCR_TUR	(1<<5)
+#define SASCR_ROR	(1<<6)
+#define SASCR_DTS	(1<<16)
+#define SASCR_RDD	(1<<17)
+#define SASCR_STO	(1<<18)
+
+#define SADTCS_TDEN	(1<<0)
+#define SADTCS_TDIE	(1<<1)
+#define SADTCS_TDBDA	(1<<3)
+#define SADTCS_TDSTA	(1<<4)
+#define SADTCS_TDBDB	(1<<5)
+#define SADTCS_TDSTB	(1<<6)
+#define SADTCS_TBIU	(1<<7)
+
+#define SADRCS_RDEN	(1<<0)
+#define SADRCS_RDIE	(1<<1)
+#define SADRCS_RDBDA	(1<<3)
+#define SADRCS_RDSTA	(1<<4)
+#define SADRCS_RDBDB	(1<<5)
+#define SADRCS_RDSTB	(1<<6)
+#define SADRCS_RBIU	(1<<7)
+
+#define SAD_CS_DEN	(1<<0)
+#define SAD_CS_DIE	(1<<1)	/* Not functional on metal 1 */
+#define SAD_CS_DBDA	(1<<3)	/* Not functional on metal 1 */
+#define SAD_CS_DSTA	(1<<4)
+#define SAD_CS_DBDB	(1<<5)	/* Not functional on metal 1 */
+#define SAD_CS_DSTB	(1<<6)
+#define SAD_CS_BIU	(1<<7)	/* Not functional on metal 1 */
+
+#define SAITR_TFS	(1<<0)
+#define SAITR_RFS	(1<<1)
+#define SAITR_TUR	(1<<2)
+#define SAITR_ROR	(1<<3)
+#define SAITR_CADT	(1<<4)
+#define SAITR_SADR	(1<<5)
+#define SAITR_RSTO	(1<<6)
+#define SAITR_TDBDA	(1<<8)
+#define SAITR_TDBDB	(1<<9)
+#define SAITR_RDBDA	(1<<10)
+#define SAITR_RDBDB	(1<<11)
+
+/*
+ * General-Purpose I/O Interface
+ *
+ * Registers
+ *    PA_DDR		GPIO Block A Data Direction
+ *    PA_DRR/PA_DWR	GPIO Block A Data Value Register (read/write)
+ *    PA_SDR		GPIO Block A Sleep Direction
+ *    PA_SSR		GPIO Block A Sleep State
+ *    PB_DDR		GPIO Block B Data Direction
+ *    PB_DRR/PB_DWR	GPIO Block B Data Value Register (read/write)
+ *    PB_SDR		GPIO Block B Sleep Direction
+ *    PB_SSR		GPIO Block B Sleep State
+ *    PC_DDR		GPIO Block C Data Direction
+ *    PC_DRR/PC_DWR	GPIO Block C Data Value Register (read/write)
+ *    PC_SDR		GPIO Block C Sleep Direction
+ *    PC_SSR		GPIO Block C Sleep State
+ */
+
+#define _PA_DDR		_SA1111( 0x1000 )
+#define _PA_DRR		_SA1111( 0x1004 )
+#define _PA_DWR		_SA1111( 0x1004 )
+#define _PA_SDR		_SA1111( 0x1008 )
+#define _PA_SSR		_SA1111( 0x100c )
+#define _PB_DDR		_SA1111( 0x1010 )
+#define _PB_DRR		_SA1111( 0x1014 )
+#define _PB_DWR		_SA1111( 0x1014 )
+#define _PB_SDR		_SA1111( 0x1018 )
+#define _PB_SSR		_SA1111( 0x101c )
+#define _PC_DDR		_SA1111( 0x1020 )
+#define _PC_DRR		_SA1111( 0x1024 )
+#define _PC_DWR		_SA1111( 0x1024 )
+#define _PC_SDR		_SA1111( 0x1028 )
+#define _PC_SSR		_SA1111( 0x102c )
+
+#if LANGUAGE == C
+
+#define PA_DDR		__CCREG(0x1000)
+#define PA_DRR		__CCREG(0x1004)
+#define PA_DWR		__CCREG(0x1004)
+#define PA_SDR		__CCREG(0x1008)
+#define PA_SSR		__CCREG(0x100c)
+#define PB_DDR		__CCREG(0x1010)
+#define PB_DRR		__CCREG(0x1014)
+#define PB_DWR		__CCREG(0x1014)
+#define PB_SDR		__CCREG(0x1018)
+#define PB_SSR		__CCREG(0x101c)
+#define PC_DDR		__CCREG(0x1020)
+#define PC_DRR		__CCREG(0x1024)
+#define PC_DWR		__CCREG(0x1024)
+#define PC_SDR		__CCREG(0x1028)
+#define PC_SSR		__CCREG(0x102c)
+
+#endif  /* LANGUAGE == C */
+
+/*
+ * Interrupt Controller
+ *
+ * Registers
+ *    INTTEST0		Test register 0
+ *    INTTEST1		Test register 1
+ *    INTEN0		Interrupt Enable register 0
+ *    INTEN1		Interrupt Enable register 1
+ *    INTPOL0		Interrupt Polarity selection 0
+ *    INTPOL1		Interrupt Polarity selection 1
+ *    INTTSTSEL		Interrupt source selection
+ *    INTSTATCLR0	Interrupt Status/Clear 0
+ *    INTSTATCLR1	Interrupt Status/Clear 1
+ *    INTSET0		Interrupt source set 0
+ *    INTSET1		Interrupt source set 1
+ *    WAKE_EN0		Wake-up source enable 0
+ *    WAKE_EN1		Wake-up source enable 1
+ *    WAKE_POL0		Wake-up polarity selection 0
+ *    WAKE_POL1		Wake-up polarity selection 1
+ */
+
+#define SA1111_INTTEST0		0x1600
+#define SA1111_INTTEST1		0x1604
+#define SA1111_INTEN0		0x1608
+#define SA1111_INTEN1		0x160c
+#define SA1111_INTPOL0		0x1610
+#define SA1111_INTPOL1		0x1614
+#define SA1111_INTTSTSEL	0x1618
+#define SA1111_INTSTATCLR0	0x161c
+#define SA1111_INTSTATCLR1	0x1620
+#define SA1111_INTSET0		0x1624
+#define SA1111_INTSET1		0x1628
+#define SA1111_WAKE_EN0		0x162c
+#define SA1111_WAKE_EN1		0x1630
+#define SA1111_WAKE_POL0	0x1634
+#define SA1111_WAKE_POL1	0x1638
+
+#define _INTTEST0	_SA1111(SA1111_INTTEST0)
+#define _INTTEST1	_SA1111(SA1111_INTTEST1)
+#define _INTEN0		_SA1111(SA1111_INTEN0)
+#define _INTEN1		_SA1111(SA1111_INTEN1)
+#define _INTPOL0	_SA1111(SA1111_INTPOL0)
+#define _INTPOL1	_SA1111(SA1111_INTPOL1)
+#define _INTTSTSEL	_SA1111(SA1111_INTTSTSEL)
+#define _INTSTATCLR0	_SA1111(SA1111_INTSTATCLR0)
+#define _INTSTATCLR1	_SA1111(SA1111_INTSTATCLR1)
+#define _INTSET0	_SA1111(SA1111_INTSET0)
+#define _INTSET1	_SA1111(SA1111_INTSET1)
+#define _WAKE_EN0	_SA1111(SA1111_WAKE_EN0)
+#define _WAKE_EN1	_SA1111(SA1111_WAKE_EN1)
+#define _WAKE_POL0	_SA1111(SA1111_WAKE_POL0)
+#define _WAKE_POL1	_SA1111(SA1111_WAKE_POL1)
+
+#if LANGUAGE == C
+
+#define INTTEST0	__CCREG(SA1111_INTTEST0)
+#define INTTEST1	__CCREG(SA1111_INTTEST1)
+#define INTEN0		__CCREG(SA1111_INTEN0)
+#define INTEN1		__CCREG(SA1111_INTEN1)
+#define INTPOL0		__CCREG(SA1111_INTPOL0)
+#define INTPOL1		__CCREG(SA1111_INTPOL1)
+#define INTTSTSEL	__CCREG(SA1111_INTTSTSEL)
+#define INTSTATCLR0	__CCREG(SA1111_INTSTATCLR0)
+#define INTSTATCLR1	__CCREG(SA1111_INTSTATCLR1)
+#define INTSET0		__CCREG(SA1111_INTSET0)
+#define INTSET1		__CCREG(SA1111_INTSET1)
+#define WAKE_EN0	__CCREG(SA1111_WAKE_EN0)
+#define WAKE_EN1	__CCREG(SA1111_WAKE_EN1)
+#define WAKE_POL0	__CCREG(SA1111_WAKE_POL0)
+#define WAKE_POL1	__CCREG(SA1111_WAKE_POL1)
+
+#endif  /* LANGUAGE == C */
+
+/*
+ * PS/2 Trackpad and Mouse Interfaces
+ *
+ * Registers   (prefix kbd applies to trackpad interface, mse to mouse)
+ *    KBDCR     Control Register
+ *    KBDSTAT       Status Register
+ *    KBDDATA       Transmit/Receive Data register
+ *    KBDCLKDIV     Clock Division Register
+ *    KBDPRECNT     Clock Precount Register
+ *    KBDTEST1      Test register 1
+ *    KBDTEST2      Test register 2
+ *    KBDTEST3      Test register 3
+ *    KBDTEST4      Test register 4
+ *    MSECR
+ *    MSESTAT
+ *    MSEDATA
+ *    MSECLKDIV
+ *    MSEPRECNT
+ *    MSETEST1
+ *    MSETEST2
+ *    MSETEST3
+ *    MSETEST4
+ *
+ */
+
+#define _KBD( x )   _SA1111( 0x0A00 )
+#define _MSE( x )   _SA1111( 0x0C00 )
+
+#define _KBDCR	    _SA1111( 0x0A00 )
+#define _KBDSTAT    _SA1111( 0x0A04 )
+#define _KBDDATA    _SA1111( 0x0A08 )
+#define _KBDCLKDIV  _SA1111( 0x0A0C )
+#define _KBDPRECNT  _SA1111( 0x0A10 )
+#define _MSECR	    _SA1111( 0x0C00 )
+#define _MSESTAT    _SA1111( 0x0C04 )
+#define _MSEDATA    _SA1111( 0x0C08 )
+#define _MSECLKDIV  _SA1111( 0x0C0C )
+#define _MSEPRECNT  _SA1111( 0x0C10 )
+
+#if ( LANGUAGE == C )
+
+#define KBDCR		__CCREG(0x0a00)
+#define KBDSTAT		__CCREG(0x0a04)
+#define KBDDATA		__CCREG(0x0a08)
+#define KBDCLKDIV	__CCREG(0x0a0c)
+#define KBDPRECNT	__CCREG(0x0a10)
+#define MSECR		__CCREG(0x0c00)
+#define MSESTAT		__CCREG(0x0c04)
+#define MSEDATA		__CCREG(0x0c08)
+#define MSECLKDIV	__CCREG(0x0c0c)
+#define MSEPRECNT	__CCREG(0x0c10)
+
+#define KBDCR_ENA        0x08
+#define KBDCR_FKD        0x02
+#define KBDCR_FKC        0x01
+
+#define KBDSTAT_TXE      0x80
+#define KBDSTAT_TXB      0x40
+#define KBDSTAT_RXF      0x20
+#define KBDSTAT_RXB      0x10
+#define KBDSTAT_ENA      0x08
+#define KBDSTAT_RXP      0x04
+#define KBDSTAT_KBD      0x02
+#define KBDSTAT_KBC      0x01
+
+#define KBDCLKDIV_DivVal     Fld(4,0)
+
+#define MSECR_ENA        0x08
+#define MSECR_FKD        0x02
+#define MSECR_FKC        0x01
+
+#define MSESTAT_TXE      0x80
+#define MSESTAT_TXB      0x40
+#define MSESTAT_RXF      0x20
+#define MSESTAT_RXB      0x10
+#define MSESTAT_ENA      0x08
+#define MSESTAT_RXP      0x04
+#define MSESTAT_MSD      0x02
+#define MSESTAT_MSC      0x01
+
+#define MSECLKDIV_DivVal     Fld(4,0)
+
+#define KBDTEST1_CD      0x80
+#define KBDTEST1_RC1         0x40
+#define KBDTEST1_MC      0x20
+#define KBDTEST1_C       Fld(2,3)
+#define KBDTEST1_T2      0x40
+#define KBDTEST1_T1      0x20
+#define KBDTEST1_T0      0x10
+#define KBDTEST2_TICBnRES    0x08
+#define KBDTEST2_RKC         0x04
+#define KBDTEST2_RKD         0x02
+#define KBDTEST2_SEL         0x01
+#define KBDTEST3_ms_16       0x80
+#define KBDTEST3_us_64       0x40
+#define KBDTEST3_us_16       0x20
+#define KBDTEST3_DIV8        0x10
+#define KBDTEST3_DIn         0x08
+#define KBDTEST3_CIn         0x04
+#define KBDTEST3_KD      0x02
+#define KBDTEST3_KC      0x01
+#define KBDTEST4_BC12        0x80
+#define KBDTEST4_BC11        0x40
+#define KBDTEST4_TRES        0x20
+#define KBDTEST4_CLKOE       0x10
+#define KBDTEST4_CRES        0x08
+#define KBDTEST4_RXB         0x04
+#define KBDTEST4_TXB         0x02
+#define KBDTEST4_SRX         0x01
+
+#define MSETEST1_CD      0x80
+#define MSETEST1_RC1         0x40
+#define MSETEST1_MC      0x20
+#define MSETEST1_C       Fld(2,3)
+#define MSETEST1_T2      0x40
+#define MSETEST1_T1      0x20
+#define MSETEST1_T0      0x10
+#define MSETEST2_TICBnRES    0x08
+#define MSETEST2_RKC         0x04
+#define MSETEST2_RKD         0x02
+#define MSETEST2_SEL         0x01
+#define MSETEST3_ms_16       0x80
+#define MSETEST3_us_64       0x40
+#define MSETEST3_us_16       0x20
+#define MSETEST3_DIV8        0x10
+#define MSETEST3_DIn         0x08
+#define MSETEST3_CIn         0x04
+#define MSETEST3_KD      0x02
+#define MSETEST3_KC      0x01
+#define MSETEST4_BC12        0x80
+#define MSETEST4_BC11        0x40
+#define MSETEST4_TRES        0x20
+#define MSETEST4_CLKOE       0x10
+#define MSETEST4_CRES        0x08
+#define MSETEST4_RXB         0x04
+#define MSETEST4_TXB         0x02
+#define MSETEST4_SRX         0x01
+
+#endif  /* LANGUAGE == C */
+
+/*
+ * PCMCIA Interface
+ *
+ * Registers
+ *    PCSR	Status Register
+ *    PCCR	Control Register
+ *    PCSSR	Sleep State Register
+ */
+
+#define _PCCR		_SA1111( 0x1800 )
+#define _PCSSR		_SA1111( 0x1804 )
+#define _PCSR		_SA1111( 0x1808 )
+
+#if LANGUAGE == C
+
+#define PCCR		__CCREG(0x1800)
+#define PCSSR		__CCREG(0x1804)
+#define PCSR		__CCREG(0x1808)
+
+#endif  /* LANGUAGE == C */
+
+#define PCSR_S0_READY	(1<<0)
+#define PCSR_S1_READY	(1<<1)
+#define PCSR_S0_DETECT	(1<<2)
+#define PCSR_S1_DETECT	(1<<3)
+#define PCSR_S0_VS1	(1<<4)
+#define PCSR_S0_VS2	(1<<5)
+#define PCSR_S1_VS1	(1<<6)
+#define PCSR_S1_VS2	(1<<7)
+#define PCSR_S0_WP	(1<<8)
+#define PCSR_S1_WP	(1<<9)
+#define PCSR_S0_BVD1	(1<<10)
+#define PCSR_S0_BVD2	(1<<11)
+#define PCSR_S1_BVD1	(1<<12)
+#define PCSR_S1_BVD2	(1<<13)
+
+#define PCCR_S0_RST	(1<<0)
+#define PCCR_S1_RST	(1<<1)
+#define PCCR_S0_FLT	(1<<2)
+#define PCCR_S1_FLT	(1<<3)
+#define PCCR_S0_PWAITEN	(1<<4)
+#define PCCR_S1_PWAITEN	(1<<5)
+#define PCCR_S0_PSE	(1<<6)
+#define PCCR_S1_PSE	(1<<7)
+
+#define PCSSR_S0_SLEEP	(1<<0)
+#define PCSSR_S1_SLEEP	(1<<1)
+
+#endif  /* _ASM_ARCH_SA1111 */
diff -urN linux-2.4.19-pre4/include/asm-arm/hdreg.h linux-2.4.19-pre5/include/asm-arm/hdreg.h
--- linux-2.4.19-pre4/include/asm-arm/hdreg.h	Thu May 13 11:00:08 1999
+++ linux-2.4.19-pre5/include/asm-arm/hdreg.h	Fri Mar 29 14:50:07 2002
@@ -7,7 +7,7 @@
 #ifndef __ASMARM_HDREG_H
 #define __ASMARM_HDREG_H
 
-typedef unsigned long ide_ioreg_t;
+typedef unsigned int ide_ioreg_t;
 
 #endif /* __ASMARM_HDREG_H */
 
diff -urN linux-2.4.19-pre4/include/asm-arm/io.h linux-2.4.19-pre5/include/asm-arm/io.h
--- linux-2.4.19-pre4/include/asm-arm/io.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/io.h	Fri Mar 29 14:50:07 2002
@@ -37,9 +37,9 @@
 #define __arch_putb(v,a)		(*(volatile unsigned char *)(a) = (v))
 #define __arch_putl(v,a)		(*(volatile unsigned int  *)(a) = (v))
 
-extern void __raw_writesb(unsigned int addr, void *data, int bytelen);
-extern void __raw_writesw(unsigned int addr, void *data, int wordlen);
-extern void __raw_writesl(unsigned int addr, void *data, int longlen);
+extern void __raw_writesb(unsigned int addr, const void *data, int bytelen);
+extern void __raw_writesw(unsigned int addr, const void *data, int wordlen);
+extern void __raw_writesl(unsigned int addr, const void *data, int longlen);
 
 extern void __raw_readsb(unsigned int addr, void *data, int bytelen);
 extern void __raw_readsw(unsigned int addr, void *data, int wordlen);
diff -urN linux-2.4.19-pre4/include/asm-arm/leds.h linux-2.4.19-pre5/include/asm-arm/leds.h
--- linux-2.4.19-pre4/include/asm-arm/leds.h	Mon Sep 18 15:15:23 2000
+++ linux-2.4.19-pre5/include/asm-arm/leds.h	Fri Mar 29 14:50:07 2002
@@ -23,12 +23,16 @@
 	led_stop,
 	led_claim,		/* override idle & timer leds */
 	led_release,		/* restore idle & timer leds */
+	led_start_timer_mode,
+	led_stop_timer_mode,
 	led_green_on,
 	led_green_off,
 	led_amber_on,
 	led_amber_off,
 	led_red_on,
 	led_red_off,
+	led_blue_on,
+	led_blue_off,
 	/*
 	 * I want this between led_timer and led_start, but
 	 * someone has decided to export this to user space
diff -urN linux-2.4.19-pre4/include/asm-arm/mach/amba_kmi.h linux-2.4.19-pre5/include/asm-arm/mach/amba_kmi.h
--- linux-2.4.19-pre4/include/asm-arm/mach/amba_kmi.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/mach/amba_kmi.h	Fri Mar 29 14:50:07 2002
@@ -24,10 +24,16 @@
 	u_char			type;
 	u_char			state;
 	u_char			prev_rx;
+
 	u_char			last_tx;
 	u_char			resend_count;
 	u_short			res;
+
 	u_char			present;
+	u_char			reconnect;
+	u_char			config_num;
+	u_char			hotplug_state;
+
 	wait_queue_head_t	wait_q;
 	void			(*rx)(struct kmi_info *, u_int val,
 				      struct pt_regs *regs);
diff -urN linux-2.4.19-pre4/include/asm-arm/mach/serial_sa1100.h linux-2.4.19-pre5/include/asm-arm/mach/serial_sa1100.h
--- linux-2.4.19-pre4/include/asm-arm/mach/serial_sa1100.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/mach/serial_sa1100.h	Fri Mar 29 14:50:07 2002
@@ -18,9 +18,10 @@
  */
 struct sa1100_port_fns {
 	void	(*set_mctrl)(struct uart_port *, u_int);
-	int	(*get_mctrl)(struct uart_port *);
+	u_int	(*get_mctrl)(struct uart_port *);
 	void	(*enable_ms)(struct uart_port *);
 	void	(*pm)(struct uart_port *, u_int, u_int);
+	int	(*set_wake)(struct uart_port *, u_int);
 	int	(*open)(struct uart_port *, struct uart_info *);
 	void	(*close)(struct uart_port *, struct uart_info *);
 };
diff -urN linux-2.4.19-pre4/include/asm-arm/mmu_context.h linux-2.4.19-pre5/include/asm-arm/mmu_context.h
--- linux-2.4.19-pre4/include/asm-arm/mmu_context.h	Mon Sep 18 15:15:24 2000
+++ linux-2.4.19-pre5/include/asm-arm/mmu_context.h	Fri Mar 29 14:50:07 2002
@@ -42,11 +42,8 @@
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk, unsigned int cpu)
 {
-	if (prev != next) {
+	if (prev != next)
 		cpu_switch_mm(next->pgd, tsk);
-		clear_bit(cpu, &prev->cpu_vm_mask);
-	}
-	set_bit(cpu, &next->cpu_vm_mask);
 }
 
 #define activate_mm(prev, next) \
diff -urN linux-2.4.19-pre4/include/asm-arm/page.h linux-2.4.19-pre5/include/asm-arm/page.h
--- linux-2.4.19-pre4/include/asm-arm/page.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/asm-arm/page.h	Fri Mar 29 14:50:07 2002
@@ -63,11 +63,21 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
 extern void __bug(const char *file, int line, void *data);
 
+/* give file/line information */
 #define BUG()		__bug(__FILE__, __LINE__, NULL)
 #define PAGE_BUG(page)	__bug(__FILE__, __LINE__, page)
 
+#else
+
+/* these just cause an oops */
+#define BUG()		(*(int *)0 = 0)
+#define PAGE_BUG(page)	(*(int *)0 = 0)
+
+#endif
+
 /* Pure 2^n version of get_order */
 static inline int get_order(unsigned long size)
 {
@@ -96,9 +106,6 @@
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
 #endif
 
-#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
-				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #endif
 
 #endif
diff -urN linux-2.4.19-pre4/include/asm-arm/proc-armv/cache.h linux-2.4.19-pre5/include/asm-arm/proc-armv/cache.h
--- linux-2.4.19-pre4/include/asm-arm/proc-armv/cache.h	Thu Oct 25 13:53:55 2001
+++ linux-2.4.19-pre5/include/asm-arm/proc-armv/cache.h	Fri Mar 29 14:50:07 2002
@@ -44,15 +44,17 @@
 
 #define flush_cache_range(_mm,_start,_end)				\
 	do {								\
-		if ((_mm) == current->mm)				\
-			cpu_cache_clean_invalidate_range((_start), (_end), 1); \
+		if ((_mm) == current->active_mm)			\
+			cpu_cache_clean_invalidate_range((_start) & PAGE_MASK, \
+							 PAGE_ALIGN(_end), 1); \
 	} while (0)
 
 #define flush_cache_page(_vma,_vmaddr)					\
 	do {								\
-		if ((_vma)->vm_mm == current->mm) {			\
-			cpu_cache_clean_invalidate_range((_vmaddr),	\
-				(_vmaddr) + PAGE_SIZE,			\
+		if ((_vma)->vm_mm == current->active_mm) {		\
+			unsigned long _addr = (_vmaddr) & PAGE_MASK;	\
+			cpu_cache_clean_invalidate_range(_addr,		\
+				_addr + PAGE_SIZE,			\
 				((_vma)->vm_flags & VM_EXEC));		\
 		} \
 	} while (0)
@@ -114,10 +116,11 @@
  * about to change to user space.  This is the same method as used on SPARC64.
  * See update_mmu_cache for the user space part.
  */
+#define mapping_mapped(map)	((map)->i_mmap || (map)->i_mmap_shared)
+
 static inline void flush_dcache_page(struct page *page)
 {
-	if (page->mapping && !(page->mapping->i_mmap) &&
-	     !(page->mapping->i_mmap_shared))
+	if (page->mapping && !mapping_mapped(page->mapping))
 		set_bit(PG_dcache_dirty, &page->flags);
 	else {
 		unsigned long virt = (unsigned long)page_address(page);
@@ -128,21 +131,6 @@
 #define clean_dcache_entry(_s)		cpu_dcache_clean_entry((unsigned long)(_s))
 
 /*
- * I cache coherency stuff.
- *
- * This *is not* just icache.  It is to make data written to memory
- * consistent such that instructions fetched from the region are what
- * we expect.
- *
- * This generally means that we have to clean out the Dcache and write
- * buffers, and maybe flush the Icache in the specified range.
- */
-#define flush_icache_range(_s,_e)					\
-	do {								\
-		cpu_icache_invalidate_range((_s), (_e));		\
-	} while (0)
-
-/*
  * This function is misnamed IMHO.  There are three places where it
  * is called, each of which is preceded immediately by a call to
  * flush_page_to_ram:
@@ -169,13 +157,19 @@
 #define flush_icache_page(vma,pg)	do { } while (0)
 
 /*
- * Old ARM MEMC stuff.  This supports the reversed mapping handling that
- * we have on the older 26-bit machines.  We don't have a MEMC chip, so...
+ * I cache coherency stuff.
+ *
+ * This *is not* just icache.  It is to make data written to memory
+ * consistent such that instructions fetched from the region are what
+ * we expect.
+ *
+ * This generally means that we have to clean out the Dcache and write
+ * buffers, and maybe flush the Icache in the specified range.
  */
-#define memc_update_all()		do { } while (0)
-#define memc_update_mm(mm)		do { } while (0)
-#define memc_update_addr(mm,pte,log)	do { } while (0)
-#define memc_clear(mm,physaddr)		do { } while (0)
+#define flush_icache_range(_s,_e)					\
+	do {								\
+		cpu_icache_invalidate_range((_s), (_e));		\
+	} while (0)
 
 /*
  * TLB flushing.
@@ -239,3 +233,13 @@
  * back to the page.
  */
 extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
+
+/*
+ * Old ARM MEMC stuff.  This supports the reversed mapping handling that
+ * we have on the older 26-bit machines.  We don't have a MEMC chip, so...
+ */
+#define memc_update_all()		do { } while (0)
+#define memc_update_mm(mm)		do { } while (0)
+#define memc_update_addr(mm,pte,log)	do { } while (0)
+#define memc_clear(mm,physaddr)		do { } while (0)
+
diff -urN linux-2.4.19-pre4/include/asm-arm/proc-fns.h linux-2.4.19-pre5/include/asm-arm/proc-fns.h
--- linux-2.4.19-pre4/include/asm-arm/proc-fns.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre5/include/asm-arm/proc-fns.h	Fri Mar 29 14:50:07 2002
@@ -60,6 +60,14 @@
 #   define CPU_NAME arm920
 #  endif
 # endif
+# ifdef CONFIG_CPU_ARM922T
+#  ifdef CPU_NAME
+#   undef  MULTI_CPU
+#   define MULTI_CPU
+#  else
+#   define CPU_NAME arm922
+#  endif
+# endif
 # ifdef CONFIG_CPU_ARM926T
 #  ifdef CPU_NAME
 #   undef  MULTI_CPU
diff -urN linux-2.4.19-pre4/include/asm-arm/processor.h linux-2.4.19-pre5/include/asm-arm/processor.h
--- linux-2.4.19-pre4/include/asm-arm/processor.h	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre5/include/asm-arm/processor.h	Fri Mar 29 14:50:07 2002
@@ -68,13 +68,6 @@
 	EXTRA_THREAD_STRUCT
 };
 
-#define INIT_MMAP {					\
-	vm_mm:		&init_mm,			\
-	vm_page_prot:	PAGE_SHARED,			\
-	vm_flags:	VM_READ | VM_WRITE | VM_EXEC,	\
-	vm_avl_height:	1,				\
-}
-
 #define INIT_THREAD  {					\
 	refcount:	ATOMIC_INIT(1),			\
 	EXTRA_THREAD_STRUCT_INIT			\
diff -urN linux-2.4.19-pre4/include/asm-arm/scatterlist.h linux-2.4.19-pre5/include/asm-arm/scatterlist.h
--- linux-2.4.19-pre4/include/asm-arm/scatterlist.h	Fri Oct 12 15:35:54 2001
+++ linux-2.4.19-pre5/include/asm-arm/scatterlist.h	Fri Mar 29 14:50:07 2002
@@ -5,6 +5,7 @@
 
 struct scatterlist {
 	char		*address;	/* virtual address		 */
+	struct page	*page;		/* Location for highmem page, if any */
 	dma_addr_t	dma_address;	/* dma address			 */
 	unsigned int	length;		/* length			 */
 };
diff -urN linux-2.4.19-pre4/include/asm-arm/unistd.h linux-2.4.19-pre5/include/asm-arm/unistd.h
--- linux-2.4.19-pre4/include/asm-arm/unistd.h	Sun Aug 12 11:14:00 2001
+++ linux-2.4.19-pre5/include/asm-arm/unistd.h	Fri Mar 29 14:50:07 2002
@@ -240,6 +240,29 @@
 #define __NR_mincore			(__NR_SYSCALL_BASE+219)
 #define __NR_madvise			(__NR_SYSCALL_BASE+220)
 #define __NR_fcntl64			(__NR_SYSCALL_BASE+221)
+					/* 222 for tux */
+#define __NR_security			(__NR_SYSCALL_BASE+223)
+#define __NR_gettid			(__NR_SYSCALL_BASE+224)
+#define __NR_readahead			(__NR_SYSCALL_BASE+225)
+#if 0 /* allocated in 2.5 */
+#define __NR_setxattr			(__NR_SYSCALL_BASE+226)
+#define __NR_lsetxattr			(__NR_SYSCALL_BASE+227)
+#define __NR_fsetxattr			(__NR_SYSCALL_BASE+228)
+#define __NR_getxattr			(__NR_SYSCALL_BASE+229)
+#define __NR_lgetxattr			(__NR_SYSCALL_BASE+230)
+#define __NR_fgetxattr			(__NR_SYSCALL_BASE+231)
+#define __NR_listxattr			(__NR_SYSCALL_BASE+232)
+#define __NR_llistxattr			(__NR_SYSCALL_BASE+233)
+#define __NR_flistxattr			(__NR_SYSCALL_BASE+234)
+#define __NR_removexattr		(__NR_SYSCALL_BASE+235)
+#define __NR_lremovexattr		(__NR_SYSCALL_BASE+236)
+#define __NR_fremovexattr		(__NR_SYSCALL_BASE+237)
+#endif
+#define __NR_tkill			(__NR_SYSCALL_BASE+238)
+/*
+ * Please check 2.5 _before_ adding calls here,
+ * and copy changes to rmk@arm.linux.org.uk.  Thanks.
+ */
 
 /*
  * The following SWIs are ARM private.
diff -urN linux-2.4.19-pre4/include/asm-arm/vt.h linux-2.4.19-pre5/include/asm-arm/vt.h
--- linux-2.4.19-pre4/include/asm-arm/vt.h	Tue Jan 20 16:39:43 1998
+++ linux-2.4.19-pre5/include/asm-arm/vt.h	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-#ifndef _ASMARM_VT_H
-#define _ASMARM_VT_H
-
-#define VT_GETSCRINFO	0x56FD	/* get screen info */
-#define VT_GETPALETTE	0x56FE  /* get palette */
-#define VT_SETPALETTE	0x56FF  /* set palette */
-
-#endif /* _ASMARM_VT_H */
diff -urN linux-2.4.19-pre4/include/asm-i386/checksum.h linux-2.4.19-pre5/include/asm-i386/checksum.h
--- linux-2.4.19-pre4/include/asm-i386/checksum.h	Thu Jul 26 13:41:22 2001
+++ linux-2.4.19-pre5/include/asm-i386/checksum.h	Fri Mar 29 14:50:07 2002
@@ -29,9 +29,9 @@
 
 /*
  *	Note: when you get a NULL pointer exception here this means someone
- *	passed in an incorrect kernel address to one of these functions. 
- *	
- *	If you use these functions directly please don't forget the 
+ *	passed in an incorrect kernel address to one of these functions.
+ *
+ *	If you use these functions directly please don't forget the
  *	verify_area().
  */
 static __inline__
@@ -66,28 +66,28 @@
  *	Arnt Gulbrandsen.
  */
 static inline unsigned short ip_fast_csum(unsigned char * iph,
-					  unsigned int ihl) {
+					  unsigned int ihl)
+{
 	unsigned int sum;
 
-	__asm__ __volatile__("
-	    movl (%1), %0
-	    subl $4, %2
-	    jbe 2f
-	    addl 4(%1), %0
-	    adcl 8(%1), %0
-	    adcl 12(%1), %0
-1:	    adcl 16(%1), %0
-	    lea 4(%1), %1
-	    decl %2
-	    jne	1b
-	    adcl $0, %0
-	    movl %0, %2
-	    shrl $16, %0
-	    addw %w2, %w0
-	    adcl $0, %0
-	    notl %0
-2:
-	    "
+	__asm__ __volatile__(
+	    "movl (%1), %0	;\n"
+	    "subl $4, %2	;\n"
+	    "jbe 2f		;\n"
+	    "addl 4(%1), %0	;\n"
+	    "adcl 8(%1), %0	;\n"
+	    "adcl 12(%1), %0	;\n"
+"1:	    adcl 16(%1), %0	;\n"
+	    "lea 4(%1), %1	;\n"
+	    "decl %2		;\n"
+	    "jne 1b		;\n"
+	    "adcl $0, %0	;\n"
+	    "movl %0, %2	;\n"
+	    "shrl $16, %0	;\n"
+	    "addw %w2, %w0	;\n"
+	    "adcl $0, %0	;\n"
+	    "notl %0		;\n"
+"2:				;\n"
 	/* Since the input registers which are loaded with iph and ipl
 	   are modified, we must also specify them as outputs, or gcc
 	   will assume they contain their original values. */
@@ -102,28 +102,26 @@
 
 static inline unsigned int csum_fold(unsigned int sum)
 {
-	__asm__("
-		addl %1, %0
-		adcl $0xffff, %0
-		"
+	__asm__(
+		"addl %1, %0		;\n"
+		"adcl $0xffff, %0	;\n"
 		: "=r" (sum)
 		: "r" (sum << 16), "0" (sum & 0xffff0000)
 	);
 	return (~sum) >> 16;
 }
- 
+
 static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
 						   unsigned long daddr,
 						   unsigned short len,
 						   unsigned short proto,
-						   unsigned int sum) 
+						   unsigned int sum)
 {
-    __asm__("
-	addl %1, %0
-	adcl %2, %0
-	adcl %3, %0
-	adcl $0, %0
-	"
+    __asm__(
+	"addl %1, %0	;\n"
+	"adcl %2, %0	;\n"
+	"adcl %3, %0	;\n"
+	"adcl $0, %0	;\n"
 	: "=r" (sum)
 	: "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
     return sum;
@@ -137,7 +135,7 @@
 						   unsigned long daddr,
 						   unsigned short len,
 						   unsigned short proto,
-						   unsigned int sum) 
+						   unsigned int sum)
 {
 	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
 }
@@ -147,7 +145,8 @@
  * in icmp.c
  */
 
-static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
     return csum_fold (csum_partial(buff, len, 0));
 }
 
@@ -156,33 +155,32 @@
 						     struct in6_addr *daddr,
 						     __u32 len,
 						     unsigned short proto,
-						     unsigned int sum) 
+						     unsigned int sum)
 {
-	__asm__("
-		addl 0(%1), %0
-		adcl 4(%1), %0
-		adcl 8(%1), %0
-		adcl 12(%1), %0
-		adcl 0(%2), %0
-		adcl 4(%2), %0
-		adcl 8(%2), %0
-		adcl 12(%2), %0
-		adcl %3, %0
-		adcl %4, %0
-		adcl $0, %0
-		"
+	__asm__(
+		"addl 0(%1), %0		;\n"
+		"adcl 4(%1), %0		;\n"
+		"adcl 8(%1), %0		;\n"
+		"adcl 12(%1), %0	;\n"
+		"adcl 0(%2), %0		;\n"
+		"adcl 4(%2), %0		;\n"
+		"adcl 8(%2), %0		;\n"
+		"adcl 12(%2), %0	;\n"
+		"adcl %3, %0		;\n"
+		"adcl %4, %0		;\n"
+		"adcl $0, %0		;\n"
 		: "=&r" (sum)
-		: "r" (saddr), "r" (daddr), 
+		: "r" (saddr), "r" (daddr),
 		  "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
 
 	return csum_fold(sum);
 }
 
-/* 
+/*
  *	Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
 				    int len, int sum, int *err_ptr)
 {
 	if (access_ok(VERIFY_WRITE, dst, len))
diff -urN linux-2.4.19-pre4/include/asm-i386/highmem.h linux-2.4.19-pre5/include/asm-i386/highmem.h
--- linux-2.4.19-pre4/include/asm-i386/highmem.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre5/include/asm-i386/highmem.h	Fri Mar 29 14:50:07 2002
@@ -62,7 +62,7 @@
 static inline void *kmap(struct page *page)
 {
 	if (in_interrupt())
-		BUG();
+		out_of_line_bug();
 	if (page < highmem_start_page)
 		return page_address(page);
 	return kmap_high(page);
@@ -71,7 +71,7 @@
 static inline void kunmap(struct page *page)
 {
 	if (in_interrupt())
-		BUG();
+		out_of_line_bug();
 	if (page < highmem_start_page)
 		return;
 	kunmap_high(page);
@@ -95,7 +95,7 @@
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #if HIGHMEM_DEBUG
 	if (!pte_none(*(kmap_pte-idx)))
-		BUG();
+		out_of_line_bug();
 #endif
 	set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
 	__flush_tlb_one(vaddr);
@@ -113,7 +113,7 @@
 		return;
 
 	if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
-		BUG();
+		out_of_line_bug();
 
 	/*
 	 * force other mappings to Oops if they'll try to access
diff -urN linux-2.4.19-pre4/include/asm-i386/mmu_context.h linux-2.4.19-pre5/include/asm-i386/mmu_context.h
--- linux-2.4.19-pre4/include/asm-i386/mmu_context.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre5/include/asm-i386/mmu_context.h	Fri Mar 29 14:50:07 2002
@@ -48,7 +48,7 @@
 	else {
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
 		if(cpu_tlbstate[cpu].active_mm != next)
-			BUG();
+			out_of_line_bug();
 		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
 			/* We were in lazy tlb mode and leave_mm disabled 
 			 * tlb flush IPI delivery. We must flush our tlb.
diff -urN linux-2.4.19-pre4/include/asm-i386/page.h linux-2.4.19-pre5/include/asm-i386/page.h
--- linux-2.4.19-pre4/include/asm-i386/page.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/asm-i386/page.h	Fri Mar 29 14:50:07 2002
@@ -91,16 +91,18 @@
 /*
  * Tell the user there is some problem. Beep too, so we can
  * see^H^H^Hhear bugs in early bootup as well!
+ * The offending file and line are encoded after the "officially
+ * undefined" opcode for parsing in the trap handler.
  */
 
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-extern void do_BUG(const char *file, int line);
-#define BUG() do {					\
-	do_BUG(__FILE__, __LINE__);			\
-	__asm__ __volatile__("ud2");			\
-} while (0)
+#if 1	/* Set to zero for a slightly smaller kernel */
+#define BUG()				\
+ __asm__ __volatile__(	"ud2\n"		\
+			"\t.word %c0\n"	\
+			"\t.long %c1\n"	\
+			 : : "i" (__LINE__), "i" (__FILE__))
 #else
-#define BUG() __asm__ __volatile__(".byte 0x0f,0x0b")
+#define BUG() __asm__ __volatile__("ud2\n")
 #endif
 
 #define PAGE_BUG(page) do { \
diff -urN linux-2.4.19-pre4/include/asm-i386/pci.h linux-2.4.19-pre5/include/asm-i386/pci.h
--- linux-2.4.19-pre4/include/asm-i386/pci.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.19-pre5/include/asm-i386/pci.h	Fri Mar 29 14:50:07 2002
@@ -73,7 +73,7 @@
 					size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	flush_write_buffers();
 	return virt_to_bus(ptr);
 }
@@ -89,7 +89,7 @@
 				    size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	/* Nothing to do */
 }
 
@@ -101,7 +101,7 @@
 				      unsigned long offset, size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 
 	return (page - mem_map) * PAGE_SIZE + offset;
 }
@@ -110,7 +110,7 @@
 				  size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	/* Nothing to do */
 }
 
@@ -143,16 +143,16 @@
 	int i;
 
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
  
  	/*
  	 * temporary 2.4 hack
  	 */
  	for (i = 0; i < nents; i++ ) {
  		if (sg[i].address && sg[i].page)
- 			BUG();
+ 			out_of_line_bug();
  		else if (!sg[i].address && !sg[i].page)
- 			BUG();
+ 			out_of_line_bug();
  
  		if (sg[i].address)
  			sg[i].dma_address = virt_to_bus(sg[i].address);
@@ -172,7 +172,7 @@
 				int nents, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	/* Nothing to do */
 }
 
@@ -190,7 +190,7 @@
 				       size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	flush_write_buffers();
 }
 
@@ -205,7 +205,7 @@
 				   int nelems, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	flush_write_buffers();
 }
 
diff -urN linux-2.4.19-pre4/include/asm-i386/smplock.h linux-2.4.19-pre5/include/asm-i386/smplock.h
--- linux-2.4.19-pre4/include/asm-i386/smplock.h	Thu Nov 22 11:46:20 2001
+++ linux-2.4.19-pre5/include/asm-i386/smplock.h	Fri Mar 29 14:50:07 2002
@@ -59,7 +59,7 @@
 static __inline__ void unlock_kernel(void)
 {
 	if (current->lock_depth < 0)
-		BUG();
+		out_of_line_bug();
 #if 1
 	if (--current->lock_depth < 0)
 		spin_unlock(&kernel_flag);
diff -urN linux-2.4.19-pre4/include/asm-ppc64/Naca.h linux-2.4.19-pre5/include/asm-ppc64/Naca.h
--- linux-2.4.19-pre4/include/asm-ppc64/Naca.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/Naca.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,39 @@
+#ifndef _NACA_H
+#define _NACA_H
+
+/* 
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/types.h>
+
+struct Naca
+{
+	void *xItVpdAreas;
+	void *xRamDisk;
+	u64 xRamDiskSize;		/* In pages */
+	struct Paca *paca;		/* Ptr to an array of pacas */
+	u64 debug_switch;		/* Bits to control debug printing */
+	u16 processorCount;		/* # of physical processors */
+	u16 dCacheL1LineSize;		/* Line size of L1 DCache in bytes */
+	u16 dCacheL1LogLineSize;	/* Log-2 of DCache line size */
+	u16 dCacheL1LinesPerPage;	/* DCache lines per page */
+	u16 iCacheL1LineSize;		/* Line size of L1 ICache in bytes */
+	u16 iCacheL1LogLineSize;	/* Log-2 of ICache line size */
+	u16 iCacheL1LinesPerPage;	/* ICache lines per page */
+	u16 slb_size;			/* SLB size in entries */
+	u64 physicalMemorySize;		/* Size of real memory in bytes */
+	u64 pftSize;			/* Log base 2 of page table size */
+	u64 serialPortAddr;		/* Phyical address of serial port */
+	u8 interrupt_controller;	/* Type of interrupt controller */ 
+	u8 resv0[6];			/* Padding */
+};
+
+extern struct Naca *naca;
+
+#endif /* _NACA_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/Paca.h linux-2.4.19-pre5/include/asm-ppc64/Paca.h
--- linux-2.4.19-pre4/include/asm-ppc64/Paca.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/Paca.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,164 @@
+#ifndef _PPC64_PACA_H
+#define _PPC64_PACA_H
+
+/*============================================================================
+ *                                                         Header File Id
+ * Name______________:	Paca.H
+ *
+ * Description_______:
+ *
+ * This control block defines the PACA which defines the processor 
+ * specific data for each logical processor on the system.  
+ * There are some pointers defined that are utilized by PLIC.
+ *
+ * C 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */    
+#include	<asm/types.h>
+
+#define N_EXC_STACK    2
+
+/*-----------------------------------------------------------------------------
+ * Other Includes
+ *-----------------------------------------------------------------------------
+ */
+#include	<asm/iSeries/ItLpPaca.h>
+#include	<asm/iSeries/ItLpRegSave.h>
+#include	<asm/iSeries/ItLpQueue.h>
+#include	<asm/rtas.h>
+#include	<asm/mmu.h>
+#include	<asm/processor.h>
+
+/* A Paca entry is required for each logical processor.  On systems
+ * that support hardware multi-threading, this is equal to twice the
+ * number of physical processors.  On LPAR systems, we are required
+ * to have space for the maximum number of logical processors we
+ * could ever possibly have.  Currently, we are limited to allocating
+ * 24 processors to a partition which gives 48 logical processors on
+ * an HMT box.  Therefore, we reserve this many Paca entries.
+ */
+#define maxProcessors 24
+#define maxPacas maxProcessors * 2
+
+extern struct Paca   xPaca[];
+#define get_paca() ((struct Paca *)mfspr(SPRG3))
+
+/*============================================================================
+ * Name_______:	Paca
+ *
+ * Description:
+ *
+ *	Defines the layout of the Paca.  
+ *
+ *	This structure is not directly accessed by PLIC or the SP except
+ *	for the first two pointers that point to the ItLpPaca area and the
+ *	ItLpRegSave area for this processor.  Both the ItLpPaca and
+ *	ItLpRegSave objects are currently contained within the
+ *	PACA but they do not need to be.
+ *
+ *============================================================================
+ */
+struct Paca
+{
+/*=====================================================================================
+ * CACHE_LINE_1 0x0000 - 0x007F
+ *=====================================================================================
+ */
+	struct ItLpPaca *xLpPacaPtr;	/* Pointer to LpPaca for PLIC		0x00 */
+	struct ItLpRegSave *xLpRegSavePtr; /* Pointer to LpRegSave for PLIC	0x08 */
+	u64 xCurrent;  		        /* Pointer to current			0x10 */
+	u16 xPacaIndex;			/* Logical processor number		0x18 */
+	u16 xHwProcNum;			/* Actual Hardware Processor Number	0x1a */
+	u32 default_decr;		/* Default decrementer value		0x1c */	
+	u64 xHrdIntStack;		/* Stack for hardware interrupts	0x20 */
+	u64 xKsave;			/* Saved Kernel stack addr or zero	0x28 */
+	u64 pvr;			/* Processor version register		0x30 */
+	u8 *exception_sp;		/*					0x38 */
+
+	struct ItLpQueue *lpQueuePtr;	/* LpQueue handled by this processor    0x40 */
+	u64  xTOC;			/* Kernel TOC address			0x48 */
+	STAB xStab_data;		/* Segment table information		0x50,0x58,0x60 */
+	u8 xSegments[STAB_CACHE_SIZE];	/* Cache of used stab entries		0x68,0x70 */
+	u8 xProcEnabled;		/* 1=soft enabled			0x78 */
+	u8 xHrdIntCount;		/* Count of active hardware interrupts  0x79  */
+	u8 prof_enabled;		/* 1=iSeries profiling enabled          0x7A */
+	u8 resv1[5];			/*					0x7B-0x7F */
+
+/*=====================================================================================
+ * CACHE_LINE_2 0x0080 - 0x00FF
+ *=====================================================================================
+ */
+	u64 *pgd_cache;			/*					0x00 */
+	u64 *pmd_cache;			/*					0x08 */
+	u64 *pte_cache;			/*					0x10 */
+	u64 pgtable_cache_sz;		/*					0x18 */
+	u64 next_jiffy_update_tb;	/* TB value for next jiffy update	0x20 */
+	u32 lpEvent_count;		/* lpEvents processed			0x28 */
+	u32 prof_multiplier;		/*					0x2C */
+	u32 prof_counter;		/*					0x30 */
+	u32 prof_shift;			/* iSeries shift for profile bucket size0x34 */
+	u32 *prof_buffer;		/* iSeries profiling buffer		0x38 */
+	u32 *prof_stext;		/* iSeries start of kernel text		0x40 */
+	u32 prof_len;			/* iSeries length of profile buffer -1	0x48 */
+	u8  rsvd2[128-76];		/*					0x4C */
+
+/*=====================================================================================
+ * CACHE_LINE_3 0x0100 - 0x017F
+ *=====================================================================================
+ */
+	u8		xProcStart;	/* At startup, processor spins until	0x100 */
+  					/* xProcStart becomes non-zero. */
+	u8		rsvd3[127];
+
+/*=====================================================================================
+ * CACHE_LINE_4-8  0x0180 - 0x03FF Contains ItLpPaca
+ *=====================================================================================
+ */
+	struct ItLpPaca xLpPaca;	/* Space for ItLpPaca */
+
+/*=====================================================================================
+ * CACHE_LINE_9-16 0x0400 - 0x07FF Contains ItLpRegSave
+ *=====================================================================================
+ */
+	struct ItLpRegSave xRegSav;	/* Register save for proc */
+
+/*=====================================================================================
+ * CACHE_LINE_17-18 0x0800 - 0x0EFF Reserved
+ *=====================================================================================
+ */
+	struct rtas_args xRtas;		/* Per processor RTAS struct */
+	u64 xR1;			/* r1 save for RTAS calls */
+	u64 xSavedMsr;			/* Old msr saved here by HvCall */
+	u8 rsvd5[256-16-sizeof(struct rtas_args)];
+
+/*=====================================================================================
+ * CACHE_LINE_19-30 0x0800 - 0x0EFF Reserved
+ *=====================================================================================
+ */
+	u8 rsvd6[0x600];
+
+/*=====================================================================================
+ * CACHE_LINE_31 0x0F00 - 0x0F7F Exception stack
+ *=====================================================================================
+ */
+	u8 exception_stack[N_EXC_STACK*EXC_FRAME_SIZE];
+
+/*=====================================================================================
+ * CACHE_LINE_32 0x0F80 - 0x0FFF Reserved
+ *=====================================================================================
+ */
+	u8 rsvd7[0x80];                  /* Give the stack some rope ... */
+
+/*=====================================================================================
+ * Page 2 Reserved for guard page.  Also used as a stack early in SMP boots before
+ *        relocation is enabled.
+ *=====================================================================================
+ */
+	u8 guard[0x1000];               /* ... and then hang 'em         */ 
+};
+
+#endif /* _PPC64_PACA_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/a.out.h linux-2.4.19-pre5/include/asm-ppc64/a.out.h
--- linux-2.4.19-pre4/include/asm-ppc64/a.out.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/a.out.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,44 @@
+#ifndef __PPC64_A_OUT_H__
+#define __PPC64_A_OUT_H__
+
+#include <asm/ppcdebug.h>
+
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+struct exec
+{
+	unsigned long a_info;	/* Use macros N_MAGIC, etc for access */
+	unsigned a_text;	/* length of text, in bytes */
+	unsigned a_data;	/* length of data, in bytes */
+	unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
+	unsigned a_syms;	/* length of symbol table data in file, in bytes */
+	unsigned a_entry;	/* start address */
+	unsigned a_trsize;	/* length of relocation info for text, in bytes */
+	unsigned a_drsize;	/* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)	((a).a_trsize)
+#define N_DRSIZE(a)	((a).a_drsize)
+#define N_SYMSIZE(a)	((a).a_syms)
+
+#ifdef __KERNEL__
+
+/* 64-bit user address space is less PGDIR_SIZE due to pgd_index() bug. */
+#define STACK_TOP_USER64 (TASK_SIZE_USER64 - PGDIR_SIZE)
+
+/* Give 32-bit user space a full 4G address space to live in. */
+#define STACK_TOP_USER32 (TASK_SIZE_USER32)
+
+#define STACK_TOP (((current->thread.flags & PPC_FLAG_32BIT)||(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \
+		STACK_TOP_USER32 : STACK_TOP_USER64)
+
+#endif /* __KERNEL__ */
+
+#endif /* __PPC64_A_OUT_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/abs_addr.h linux-2.4.19-pre5/include/asm-ppc64/abs_addr.h
--- linux-2.4.19-pre4/include/asm-ppc64/abs_addr.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/abs_addr.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,121 @@
+#ifndef _ABS_ADDR_H
+#define _ABS_ADDR_H
+
+#include <linux/config.h>
+
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/types.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/lmb.h>
+
+typedef u32 msChunks_entry;
+struct msChunks {
+        unsigned long num_chunks;
+        unsigned long chunk_size;
+        unsigned long chunk_shift;
+        unsigned long chunk_mask;
+        msChunks_entry *abs;
+};
+
+extern struct msChunks msChunks;
+
+extern unsigned long msChunks_alloc(unsigned long, unsigned long, unsigned long);
+extern unsigned long reloc_offset(void);
+
+#ifdef CONFIG_MSCHUNKS
+
+static inline unsigned long
+chunk_to_addr(unsigned long chunk)
+{
+	unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+
+	return chunk << _msChunks->chunk_shift;
+}
+
+static inline unsigned long
+addr_to_chunk(unsigned long addr)
+{
+	unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+
+	return addr >> _msChunks->chunk_shift;
+}
+
+static inline unsigned long
+chunk_offset(unsigned long addr)
+{
+	unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+
+	return addr & _msChunks->chunk_mask;
+}
+
+static inline unsigned long
+abs_chunk(unsigned long pchunk)
+{
+	unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+	if ( pchunk >= _msChunks->num_chunks ) {
+		return pchunk;
+	}
+	return PTRRELOC(_msChunks->abs)[pchunk];
+}
+
+
+static inline unsigned long
+phys_to_absolute(unsigned long pa)
+{
+	return chunk_to_addr(abs_chunk(addr_to_chunk(pa))) + chunk_offset(pa);
+}
+
+static inline unsigned long
+physRpn_to_absRpn(unsigned long rpn)
+{
+	unsigned long pa = rpn << PAGE_SHIFT;
+	unsigned long aa = phys_to_absolute(pa);
+	return (aa >> PAGE_SHIFT);
+}
+
+static inline unsigned long
+absolute_to_phys(unsigned long aa)
+{
+	return lmb_abs_to_phys(aa);
+}
+
+#else  /* !CONFIG_MSCHUNKS */
+
+#define chunk_to_addr(chunk) ((unsigned long)(chunk))
+#define addr_to_chunk(addr) (addr)
+#define chunk_offset(addr) (0)
+#define abs_chunk(pchunk) (pchunk)
+
+#define phys_to_absolute(pa) (pa)
+#define physRpn_to_absRpn(rpn) (rpn)
+#define absolute_to_phys(aa) (aa)
+
+#endif /* CONFIG_MSCHUNKS */
+
+
+static inline unsigned long
+virt_to_absolute(unsigned long ea)
+{
+	return phys_to_absolute(__pa(ea));
+}
+
+static inline unsigned long
+absolute_to_virt(unsigned long aa)
+{
+	return (unsigned long)__va(absolute_to_phys(aa));
+}
+
+#endif /* _ABS_ADDR_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/atomic.h linux-2.4.19-pre5/include/asm-ppc64/atomic.h
--- linux-2.4.19-pre4/include/asm-ppc64/atomic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/atomic.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,180 @@
+/*
+ * PowerPC64 atomic operations
+ *
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * 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.
+ */
+
+#ifndef _ASM_PPC64_ATOMIC_H_ 
+#define _ASM_PPC64_ATOMIC_H_
+
+#include <asm/memory.h>
+
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v,i)		(((v)->counter) = (i))
+
+static __inline__ void atomic_add(int a, atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%3		# atomic_add\n\
+	add	%0,%2,%0\n\
+	stwcx.	%0,0,%3\n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (a), "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ int atomic_add_return(int a, atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_add_return\n\
+	add	%0,%1,%0\n\
+	stwcx.	%0,0,%2\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (a), "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+static __inline__ void atomic_sub(int a, atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%3		# atomic_sub\n\
+	subf	%0,%2,%0\n\
+	stwcx.	%0,0,%3\n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (a), "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ int atomic_sub_return(int a, atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_sub_return\n\
+	subf	%0,%1,%0\n\
+	stwcx.	%0,0,%2\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (a), "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+static __inline__ void atomic_inc(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_inc\n\
+	addic	%0,%0,1\n\
+	stwcx.	%0,0,%2\n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ int atomic_inc_return(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# atomic_inc_return\n\
+	addic	%0,%0,1\n\
+	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+static __inline__ void atomic_dec(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_dec\n\
+	addic	%0,%0,-1\n\
+	stwcx.	%0,0,%2\n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ int atomic_dec_return(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# atomic_dec_return\n\
+	addic	%0,%0,-1\n\
+	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+#define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
+#define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
+
+/*
+ * Atomically test *v and decrement if it is greater than 0.
+ * The function returns the old value of *v minus 1.
+ */
+static __inline__ int atomic_dec_if_positive(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
+	addic.	%0,%0,-1\n\
+	blt-	2f\n\
+	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	"\n\
+2:"	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+#define smp_mb__before_atomic_dec()     smp_mb()
+#define smp_mb__after_atomic_dec()      smp_mb()
+#define smp_mb__before_atomic_inc()     smp_mb()
+#define smp_mb__after_atomic_inc()      smp_mb()
+
+#endif /* _ASM_PPC64_ATOMIC_H_ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/bitops.h linux-2.4.19-pre5/include/asm-ppc64/bitops.h
--- linux-2.4.19-pre4/include/asm-ppc64/bitops.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/bitops.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,431 @@
+/*
+ * PowerPC64 atomic bit operations.
+ * Dave Engebretsen, Todd Inglett, Don Reed, Pat McCarthy, Peter Bergner,
+ * Anton Blanchard
+ *
+ * Originally taken from the 32b PPC code.  Modified to use 64b values for
+ * the various counters & memory references.
+ *
+ * Bitops are odd when viewed on big-endian systems.  They were designed
+ * on little endian so the size of the bitset doesn't matter (low order bytes
+ * come first) as long as the bit in question is valid.
+ *
+ * Bits are "tested" often using the C expression (val & (1<<nr)) so we do
+ * our best to stay compatible with that.  The assumption is that val will
+ * be unsigned long for such tests.  As such, we assume the bits are stored
+ * as an array of unsigned long (the usual case is a single unsigned long,
+ * of course).  Here's an example bitset with bit numbering:
+ *
+ *   |63..........0|127........64|195.......128|255.......196|
+ *
+ * This leads to a problem. If an int, short or char is passed as a bitset
+ * it will be a bad memory reference since we want to store in chunks
+ * of unsigned long (64 bits here) size.
+ *
+ * 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.
+ */
+
+#ifndef _PPC64_BITOPS_H
+#define _PPC64_BITOPS_H
+
+#ifdef __KERNEL__
+
+#include <asm/byteorder.h>
+#include <asm/memory.h>
+
+/*
+ * clear_bit doesn't imply a memory barrier
+ */
+#define smp_mb__before_clear_bit()	smp_mb()
+#define smp_mb__after_clear_bit()	smp_mb()
+
+static __inline__ int test_bit(unsigned long nr, __const__ volatile void *addr)
+{
+	return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63)));
+}
+
+static __inline__ void set_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old;
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%3		# set_bit\n\
+	or	%0,%0,%2\n\
+	stdcx.	%0,0,%3\n\
+	bne-	1b"
+	: "=&r" (old), "=m" (*p)
+	: "r" (mask), "r" (p), "m" (*p)
+	: "cc");
+}
+
+static __inline__ void clear_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old;
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%3		# clear_bit\n\
+	andc	%0,%0,%2\n\
+	stdcx.	%0,0,%3\n\
+	bne-	1b"
+	: "=&r" (old), "=m" (*p)
+	: "r" (mask), "r" (p), "m" (*p)
+	: "cc");
+}
+
+static __inline__ void change_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old;
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%3		# change_bit\n\
+	xor	%0,%0,%2\n\
+	stdcx.	%0,0,%3\n\
+	bne-	1b"
+	: "=&r" (old), "=m" (*p)
+	: "r" (mask), "r" (p), "m" (*p)
+	: "cc");
+}
+
+static __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old, t;
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%3		# test_and_set_bit\n\
+	or	%1,%0,%2 \n\
+	stdcx.	%1,0,%3 \n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (old), "=&r" (t)
+	: "r" (mask), "r" (p)
+	: "cc", "memory");
+
+	return (old & mask) != 0;
+}
+
+static __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old, t;
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%3		# test_and_clear_bit\n\
+	andc	%1,%0,%2\n\
+	stdcx.	%1,0,%3\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (old), "=&r" (t)
+	: "r" (mask), "r" (p)
+	: "cc", "memory");
+
+	return (old & mask) != 0;
+}
+
+static __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old, t;
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%3		# test_and_change_bit\n\
+	xor	%1,%0,%2\n\
+	stdcx.	%1,0,%3\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (old), "=&r" (t)
+	: "r" (mask), "r" (p)
+	: "cc", "memory");
+
+	return (old & mask) != 0;
+}
+
+/*
+ * non-atomic versions
+ */
+static __inline__ void __set_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	*p |= mask;
+}
+
+static __inline__ void __clear_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	*p &= ~mask;
+}
+
+static __inline__ void __change_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+
+	*p ^= mask;
+}
+
+static __inline__ int __test_and_set_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+	unsigned long old = *p;
+
+	*p = old | mask;
+	return (old & mask) != 0;
+}
+
+static __inline__ int __test_and_clear_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+	unsigned long old = *p;
+
+	*p = old & ~mask;
+	return (old & mask) != 0;
+}
+
+static __inline__ int __test_and_change_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long mask = 1UL << (nr & 0x3f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
+	unsigned long old = *p;
+
+	*p = old ^ mask;
+	return (old & mask) != 0;
+}
+
+/*
+ * Return the zero-based bit position (from RIGHT TO LEFT, 63 -> 0) of the
+ * most significant (left-most) 1-bit in a double word.
+ */
+static __inline__ int __ilog2(unsigned long x)
+{
+	int lz;
+
+	asm ("cntlzd %0,%1" : "=r" (lz) : "r" (x));
+	return 63 - lz;
+}
+
+/* Return the zero-based bit position
+ *  from RIGHT TO LEFT  63 --> 0
+ *   of the most significant (left-most) 1-bit in an 8-byte area.
+ */
+static __inline__ long cnt_trailing_zeros(unsigned long mask)
+{
+        long cnt;
+
+	asm(
+"	addi	%0,%1,-1	\n\
+	andc	%0,%0,%1	\n\
+	cntlzd	%0,%0		\n\
+	subfic	%0,%0,64"
+	: "=r" (cnt)
+	: "r" (mask));
+	return cnt;
+}
+
+
+
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ *    Determines the bit position of the LEAST significant
+ *    (rightmost) 0 bit in the specified DOUBLE-WORD.
+ *    The returned bit position will be zero-based, starting
+ *    from the right side (63 - 0).
+ *    the code should check against ~0UL first..
+ */
+static __inline__ unsigned long ffz(unsigned long x)
+{
+	u32  tempRC;
+
+	/* Change all of x's 1s to 0s and 0s to 1s in x.
+	 * And insure at least 1 zero exists in the 8 byte area.
+	 */
+	if ((x = ~x) == 0)
+		/* no zero exists anywhere in the 8 byte area. */
+		return 64;
+
+	/* Calculate the bit position of the least significant '1' bit in x
+	 * (since x has been changed this will actually be the least
+	 * significant '0' bit in the original x).
+	 * Note: (x & -x) gives us a mask that is the LEAST significant
+	 * (RIGHT-most) 1-bit of the value in x.
+	 */
+	tempRC = __ilog2(x & -x);
+
+	return tempRC;
+}
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static __inline__ int ffs(int x)
+{
+	int result = ffz(~x);
+	return x ? result+1 : 0;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+extern unsigned long find_next_zero_bit(void * addr, unsigned long size,
+					unsigned long offset);
+/*
+ * The optimizer actually does good code for this case..
+ */
+#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
+
+/* Bitmap functions for the ext2 filesystem. */
+#define _EXT2_HAVE_ASM_BITOPS_
+
+static __inline__ int ext2_set_bit(int nr, void* addr)
+{
+	/* This method needs to take into account the fact that the ext2 file system represents
+	 *  it's bitmaps as "little endian" unsigned integers.
+	 * Note: this method is not atomic, but ext2 does not need it to be.
+	 */
+	int mask;
+	int oldbit;
+	unsigned char* ADDR = (unsigned char*) addr;
+
+	/* Determine the BYTE containing the specified bit
+	 * (nr) - important as if we go to a byte there are no
+	 * little endian concerns.
+	 */
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
+	oldbit = *ADDR & mask;  /* Save the bit's previous value. */
+	*ADDR |= mask;  /* Turn the bit on. */
+	return oldbit;  /* Return the bit's previous value. */
+}
+
+static __inline__ int ext2_clear_bit(int nr, void* addr)
+{
+	/* This method needs to take into account the fact that the ext2 file system represents
+	 * | it's bitmaps as "little endian" unsigned integers.
+	 * Note: this method is not atomic, but ext2 does not need it to be.
+	 */
+        int     mask;
+        int oldbit;
+        unsigned char* ADDR = (unsigned char*) addr;
+
+	/* Determine the BYTE containing the specified bit (nr)
+	 *  - important as if we go to a byte there are no little endian concerns.
+	 */
+        ADDR += nr >> 3;
+        mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
+        oldbit = *ADDR & mask;  /* Save the bit's previous value. */
+        *ADDR = *ADDR & ~mask;  /* Turn the bit off. */
+        return oldbit;  /* Return the bit's previous value. */
+}
+
+static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
+{
+	/* This method needs to take into account the fact that the ext2 file system represents
+	 * | it's bitmaps as "little endian" unsigned integers.
+	 * Determine the BYTE containing the specified bit (nr),
+	 *   then shift to the right the correct number of bits and return that bit's value.
+	 */
+	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
+	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
+}
+
+/* Returns the bit position of the most significant 1 bit in a WORD. */
+static __inline__ int ext2_ilog2(unsigned int x)
+{
+        int lz;
+
+        asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+        return 31 - lz;
+}
+
+/* ext2_ffz = ext2's Find First Zero.
+ *    Determines the bit position of the LEAST significant (rightmost) 0 bit in the specified WORD.
+ *    The returned bit position will be zero-based, starting from the right side (31 - 0).
+ */
+static __inline__ int ext2_ffz(unsigned int x)
+{
+	u32  tempRC;
+	/* Change all of x's 1s to 0s and 0s to 1s in x.  And insure at least 1 zero exists in the word. */
+	if ((x = ~x) == 0)
+		/* no zero exists anywhere in the 4 byte area. */
+		return 32;
+	/* Calculate the bit position of the least significant '1' bit in x
+	 * (since x has been changed this will actually be the least
+	 * significant '0' bit in the original x).
+	 * Note: (x & -x) gives us a mask that is the LEAST significant
+	 * (RIGHT-most) 1-bit of the value in x.
+	 */
+	tempRC = ext2_ilog2(x & -x);
+	return tempRC;
+}
+
+static __inline__ u32 ext2_find_next_zero_bit(void* addr, u32 size, u32 offset)
+{
+	/* This method needs to take into account the fact that the ext2 file system represents
+	 * | it's bitmaps as "little endian" unsigned integers.
+	 */
+        unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+        unsigned int result = offset & ~31;
+        unsigned int tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 31;
+        if (offset) {
+                tmp = cpu_to_le32p(p++);
+                tmp |= ~0U >> (32-offset); /* bug or feature ? */
+                if (size < 32)
+                        goto found_first;
+                if (tmp != ~0)
+                        goto found_middle;
+                size -= 32;
+                result += 32;
+        }
+        while (size >= 32) {
+                if ((tmp = cpu_to_le32p(p++)) != ~0)
+                        goto found_middle;
+                result += 32;
+                size -= 32;
+        }
+        if (!size)
+                return result;
+        tmp = cpu_to_le32p(p);
+found_first:
+        tmp |= ~0 << size;
+        if (tmp == ~0)          /* Are any bits zero? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + ext2_ffz(tmp);
+}
+
+#define ext2_find_first_zero_bit(addr, size) ext2_find_next_zero_bit((addr), (size), 0)
+
+#endif /* __KERNEL__ */
+#endif /* _PPC64_BITOPS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/bootinfo.h linux-2.4.19-pre5/include/asm-ppc64/bootinfo.h
--- linux-2.4.19-pre4/include/asm-ppc64/bootinfo.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/bootinfo.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,70 @@
+/*
+ * Non-machine dependent bootinfo structure.  Basic idea
+ * borrowed from the m68k.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@ppc.kernel.org>
+ * Copyright (c) 2001 PPC64 Team, IBM Corp 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#ifndef _PPC64_BOOTINFO_H
+#define _PPC64_BOOTINFO_H
+
+#include <asm/types.h>
+
+/* We use a u32 for the type of the fields since they're written by
+ * the bootloader which is a 32-bit process and read by the kernel
+ * which is a 64-bit process.  This way they can both agree on the
+ * size of the type.
+ */
+typedef u32 bi_rec_field;
+
+struct bi_record {
+	bi_rec_field tag;	/* tag ID */
+	bi_rec_field size;	/* size of record (in bytes) */
+	bi_rec_field data[0];	/* data */
+};
+
+#define BI_FIRST		0x1010  /* first record - marker */
+#define BI_LAST			0x1011	/* last record - marker */
+#define BI_CMD_LINE		0x1012
+#define BI_BOOTLOADER_ID	0x1013
+#define BI_INITRD		0x1014
+#define BI_SYSMAP		0x1015
+#define BI_MACHTYPE		0x1016
+
+static __inline__ struct bi_record * bi_rec_init(unsigned long addr)
+{
+	struct bi_record *bi_recs;
+	bi_recs = (struct bi_record *)_ALIGN(addr, PAGE_SIZE);
+	bi_recs->size = 0;
+	return bi_recs;
+}
+
+static __inline__ struct bi_record * bi_rec_alloc(struct bi_record *rec,
+						  unsigned long args)
+{
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	rec->size = sizeof(struct bi_record) + args*sizeof(bi_rec_field);
+	return rec;
+}
+
+static __inline__ struct bi_record * bi_rec_alloc_bytes(struct bi_record *rec,
+							unsigned long bytes)
+{
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	rec->size = sizeof(struct bi_record) + bytes;
+	return rec;
+}
+
+static __inline__ struct bi_record * bi_rec_next(struct bi_record *rec)
+{
+	return (struct bi_record *)((unsigned long)rec + rec->size);
+}
+
+#endif /* _PPC64_BOOTINFO_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/bugs.h linux-2.4.19-pre5/include/asm-ppc64/bugs.h
--- linux-2.4.19-pre4/include/asm-ppc64/bugs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/bugs.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,8 @@
+/*
+ * This file is included by 'init/main.c' to check for architecture-dependent
+ * bugs.
+ *
+ */
+
+static void check_bugs(void) {
+}
diff -urN linux-2.4.19-pre4/include/asm-ppc64/byteorder.h linux-2.4.19-pre5/include/asm-ppc64/byteorder.h
--- linux-2.4.19-pre4/include/asm-ppc64/byteorder.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/byteorder.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,95 @@
+#ifndef _PPC64_BYTEORDER_H
+#define _PPC64_BYTEORDER_H
+
+/*
+ *  
+ *
+ * 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 <asm/types.h>
+
+#ifdef __GNUC__
+
+static __inline__ __u16 ld_le16(const volatile __u16 *addr)
+{
+	__u16 val;
+
+	__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
+	return val;
+}
+
+static __inline__ void st_le16(volatile __u16 *addr, const __u16 val)
+{
+	__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+}
+
+static __inline__ __u32 ld_le32(const volatile __u32 *addr)
+{
+	__u32 val;
+
+	__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
+	return val;
+}
+
+static __inline__ void st_le32(volatile __u32 *addr, const __u32 val)
+{
+	__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+}
+
+#if 0
+static __inline__ __const__ __u16 ___arch__swab16(__u16 value)
+{
+	__u16 result;
+
+	__asm__("rlwimi %0,%1,8,16,23"
+	    : "=r" (result)
+	    : "r" (value), "0" (value >> 8));
+	return result;
+}
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 value)
+{
+	__u32 result;
+
+	__asm__("rlwimi %0,%1,24,16,23\n\t"
+	    "rlwimi %0,%1,8,8,15\n\t"
+	    "rlwimi %0,%1,24,0,7"
+	    : "=r" (result)
+	    : "r" (value), "0" (value >> 24));
+	return result;
+}
+
+static __inline__ __const__ __u64 ___arch__swab64(__u64 value)
+{
+	__u64 result;
+#error implement me
+}
+
+#define __arch__swab16(x) ___arch__swab16(x)
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab64(x) ___arch__swab64(x)
+
+#endif
+
+/* The same, but returns converted value from the location pointer by addr. */
+#define __arch__swab16p(addr) ld_le16(addr)
+#define __arch__swab32p(addr) ld_le32(addr)
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+#define __arch__swab16s(addr) st_le16(addr,*addr)
+#define __arch__swab32s(addr) st_le32(addr,*addr)
+
+#endif /* __GNUC__ */
+
+/* MIKEC: What does __BYTEORDER_HAS_U64__ mean? */
+#ifndef __STRICT_ANSI__
+#define __BYTEORDER_HAS_U64__
+#endif
+
+#include <linux/byteorder/big_endian.h>
+
+#endif /* _PPC64_BYTEORDER_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/cache.h linux-2.4.19-pre5/include/asm-ppc64/cache.h
--- linux-2.4.19-pre4/include/asm-ppc64/cache.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/cache.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,13 @@
+/*
+ * 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.
+ */
+#ifndef __ARCH_PPC64_CACHE_H
+#define __ARCH_PPC64_CACHE_H
+
+/* bytes per L1 cache line */
+#define L1_CACHE_BYTES	128
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/checksum.h linux-2.4.19-pre5/include/asm-ppc64/checksum.h
--- linux-2.4.19-pre4/include/asm-ppc64/checksum.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/checksum.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,115 @@
+#ifndef _PPC64_CHECKSUM_H
+#define _PPC64_CHECKSUM_H
+
+/*
+ * 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 is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.  ihl is the number
+ * of 32-bit words and is always >= 5.
+ */
+extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern unsigned short csum_tcpudp_magic(unsigned long saddr,
+					unsigned long daddr,
+					unsigned short len,
+					unsigned short proto,
+					unsigned int sum);
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern unsigned int csum_partial(const unsigned char * buff, int len,
+				 unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src to dst while it
+ * checksums
+ */
+unsigned int csum_partial_copy(const char *src, char *dst, 
+			       int len, unsigned int sum);
+
+extern unsigned int csum_partial_copy_generic(const char *src, char *dst,
+					      int len, unsigned int sum,
+					      int *src_err, int *dst_err);
+/*
+ * the same as csum_partial, but copies from user space.
+ */
+
+unsigned int csum_partial_copy_fromuser(const char *src, 
+					char *dst, 
+					int len, 
+					unsigned int sum,
+					int *src_err);
+
+unsigned int csum_partial_copy_nocheck(const char *src, 
+				       char *dst, 
+				       int len, 
+				       unsigned int sum);
+
+/*
+ * turns a 32-bit partial checksum (e.g. from csum_partial) into a
+ * 1's complement 16-bit checksum.
+ */
+static inline unsigned int csum_fold(unsigned int sum)
+{
+	unsigned int tmp;
+
+	/* swap the two 16-bit halves of sum */
+	__asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
+	/* if there is a carry from adding the two 16-bit halves,
+	   it will carry from the lower half into the upper half,
+	   giving us the correct sum in the upper half. */
+	sum = ~(sum + tmp) >> 16;
+	return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+	return csum_fold(csum_partial(buff, len, 0));
+}
+
+#define csum_partial_copy_from_user(src, dst, len, sum, errp)   \
+        csum_partial_copy_generic((src), (dst), (len), (sum), (errp), 0)
+
+#define csum_partial_copy_nocheck(src, dst, len, sum)   \
+        csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+
+static inline u32 csum_tcpudp_nofold(u32 saddr,
+                                     u32 daddr,
+                                     unsigned short len,
+                                     unsigned short proto,
+                                     unsigned int sum)
+{
+	unsigned long s = sum;
+
+	s += saddr;
+	s += daddr;
+	s += (proto << 16) + len;
+	s += (s >> 32);
+	return (u32) s;
+}
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/current.h linux-2.4.19-pre5/include/asm-ppc64/current.h
--- linux-2.4.19-pre4/include/asm-ppc64/current.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/current.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,15 @@
+#ifndef _PPC64_CURRENT_H
+#define _PPC64_CURRENT_H
+
+/*
+ * 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.
+ *
+ * Use r13 for current since the ppc64 ABI reserves it - Anton
+ */
+
+register struct task_struct *current asm ("r13");
+
+#endif /* !(_PPC64_CURRENT_H) */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/delay.h linux-2.4.19-pre5/include/asm-ppc64/delay.h
--- linux-2.4.19-pre4/include/asm-ppc64/delay.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/delay.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,46 @@
+#ifndef _PPC64_DELAY_H
+#define _PPC64_DELAY_H
+
+/*
+ * Copyright 1996, Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * PPC64 Support added by Dave Engebretsen, Todd Inglett, Mike Corrigan,
+ * Anton Blanchard.
+ */
+
+extern unsigned long tb_ticks_per_usec;
+
+/* define these here to prevent circular dependencies */ 
+#define __HMT_low()	asm volatile("or 1,1,1")
+#define __HMT_medium()	asm volatile("or 2,2,2")
+
+static inline unsigned long __get_tb(void)
+{
+	unsigned long rval;
+
+	asm volatile("mftb %0" : "=r" (rval));
+	return rval;
+}
+
+static inline void __delay(unsigned long loops)
+{
+	unsigned long start = __get_tb();
+
+	while((__get_tb()-start) < loops)
+		__HMT_low();
+}
+
+static inline void udelay(unsigned long usecs)
+{
+	unsigned long loops = tb_ticks_per_usec * usecs;
+
+	__delay(loops);
+	__HMT_medium();
+}
+
+#endif /* _PPC64_DELAY_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/div64.h linux-2.4.19-pre5/include/asm-ppc64/div64.h
--- linux-2.4.19-pre4/include/asm-ppc64/div64.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/div64.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,18 @@
+#ifndef __PPC_DIV64
+#define __PPC_DIV64
+
+/* Copyright 2001 PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define do_div(n,base) ({ \
+	int __res; \
+	__res = ((unsigned long) (n)) % (unsigned) (base); \
+	(n) = ((unsigned long) (n)) / (unsigned) (base); \
+	__res; })
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/dma.h linux-2.4.19-pre5/include/asm-ppc64/dma.h
--- linux-2.4.19-pre4/include/asm-ppc64/dma.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/dma.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,326 @@
+/* 
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen
+ * and John Boyd, Nov. 1992.
+ * Changes for ppc sound by Christoph Nadig
+ *
+ * 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.
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+
+#ifndef MAX_DMA_CHANNELS
+#define MAX_DMA_CHANNELS	8
+#endif
+
+/* The maximum address that we can perform a DMA transfer to on this platform */
+/* Doesn't really apply... */
+#define MAX_DMA_ADDRESS  (~0UL)
+
+#define dma_outb	outb
+#define dma_inb		inb
+
+/*
+ * NOTES about DMA transfers:
+ *
+ *  controller 1: channels 0-3, byte operations, ports 00-1F
+ *  controller 2: channels 4-7, word operations, ports C0-DF
+ *
+ *  - ALL registers are 8 bits only, regardless of transfer size
+ *  - channel 4 is not used - cascades 1 into 2.
+ *  - channels 0-3 are byte - addresses/counts are for physical bytes
+ *  - channels 5-7 are word - addresses/counts are for physical words
+ *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
+ *  - transfer count loaded to registers is 1 less than actual count
+ *  - controller 2 offsets are all even (2x offsets for controller 1)
+ *  - page registers for 5-7 don't use data bit 0, represent 128K pages
+ *  - page registers for 0-3 use bit 0, represent 64K pages
+ *
+ * On PReP, DMA transfers are limited to the lower 16MB of _physical_ memory.  
+ * On CHRP, the W83C553F (and VLSI Tollgate?) support full 32 bit addressing.
+ * Note that addresses loaded into registers must be _physical_ addresses,
+ * not logical addresses (which may differ if paging is active).
+ *
+ *  Address mapping for channels 0-3:
+ *
+ *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
+ *    |  ...  |   |  ... |   |  ... |
+ *    |  ...  |   |  ... |   |  ... |
+ *    |  ...  |   |  ... |   |  ... |
+ *   P7  ...  P0  A7 ... A0  A7 ... A0   
+ * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
+ *
+ *  Address mapping for channels 5-7:
+ *
+ *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
+ *    |  ...  |   \   \   ... \  \  \  ... \  \
+ *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
+ *    |  ...  |     \   \   ... \  \  \  ... \
+ *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
+ * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
+ *
+ * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
+ * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
+ * the hardware level, so odd-byte transfers aren't possible).
+ *
+ * Transfer count (_not # bytes_) is limited to 64K, represented as actual
+ * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
+ *
+ */
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE	0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG		0x08	/* command register (w) */
+#define DMA1_STAT_REG		0x08	/* status register (r) */
+#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
+#define DMA1_MODE_REG		0x0B	/* mode register (w) */
+#define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
+#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG		0xD0	/* command register (w) */
+#define DMA2_STAT_REG		0xD0	/* status register (r) */
+#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
+#define DMA2_MODE_REG		0xD6	/* mode register (w) */
+#define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
+#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+
+#define DMA_ADDR_0              0x00    /* DMA address registers */
+#define DMA_ADDR_1              0x02
+#define DMA_ADDR_2              0x04
+#define DMA_ADDR_3              0x06
+#define DMA_ADDR_4              0xC0
+#define DMA_ADDR_5              0xC4
+#define DMA_ADDR_6              0xC8
+#define DMA_ADDR_7              0xCC
+
+#define DMA_CNT_0               0x01    /* DMA count registers */
+#define DMA_CNT_1               0x03
+#define DMA_CNT_2               0x05
+#define DMA_CNT_3               0x07
+#define DMA_CNT_4               0xC2
+#define DMA_CNT_5               0xC6
+#define DMA_CNT_6               0xCA
+#define DMA_CNT_7               0xCE
+
+#define DMA_LO_PAGE_0              0x87    /* DMA page registers */
+#define DMA_LO_PAGE_1              0x83
+#define DMA_LO_PAGE_2              0x81
+#define DMA_LO_PAGE_3              0x82
+#define DMA_LO_PAGE_5              0x8B
+#define DMA_LO_PAGE_6              0x89
+#define DMA_LO_PAGE_7              0x8A
+
+#define DMA_HI_PAGE_0              0x487    /* DMA page registers */
+#define DMA_HI_PAGE_1              0x483
+#define DMA_HI_PAGE_2              0x481
+#define DMA_HI_PAGE_3              0x482
+#define DMA_HI_PAGE_5              0x48B
+#define DMA_HI_PAGE_6              0x489
+#define DMA_HI_PAGE_7              0x48A
+
+#define DMA1_EXT_REG               0x40B
+#define DMA2_EXT_REG               0x4D6
+
+#define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+#define DMA_AUTOINIT   	 0x10
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+	unsigned char ucDmaCmd=0x00;
+
+	if (dmanr != 4)
+	{
+		dma_outb(0, DMA2_MASK_REG);  /* This may not be enabled */
+		dma_outb(ucDmaCmd, DMA2_CMD_REG);  /* Enable group */
+	}
+	if (dmanr<=3)
+	{
+		dma_outb(dmanr,  DMA1_MASK_REG);
+		dma_outb(ucDmaCmd, DMA1_CMD_REG);  /* Enable group */
+	} else
+	{
+		dma_outb(dmanr & 3,  DMA2_MASK_REG);
+	}
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		dma_outb(dmanr | 4,  DMA1_MASK_REG);
+	else
+		dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while interrupts are disabled! ---
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		dma_outb(0,  DMA1_CLEAR_FF_REG);
+	else
+		dma_outb(0,  DMA2_CLEAR_FF_REG);
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+	if (dmanr<=3)
+		dma_outb(mode | dmanr,  DMA1_MODE_REG);
+	else
+		dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, int pagenr)
+{
+	switch(dmanr) {
+		case 0:
+			dma_outb(pagenr, DMA_LO_PAGE_0);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_0);
+			break;
+		case 1:
+			dma_outb(pagenr, DMA_LO_PAGE_1);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_1);
+			break;
+		case 2:
+			dma_outb(pagenr, DMA_LO_PAGE_2);
+			dma_outb(pagenr>>8, DMA_HI_PAGE_2); 
+			break;
+		case 3:
+			dma_outb(pagenr, DMA_LO_PAGE_3);
+			dma_outb(pagenr>>8, DMA_HI_PAGE_3); 
+			break;
+	        case 5:
+		        dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_5);
+			break;
+		case 6:
+		        dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+			dma_outb(pagenr>>8, DMA_HI_PAGE_6);
+			break;
+		case 7:
+		        dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+			dma_outb(pagenr>>8, DMA_HI_PAGE_7);
+		  break;
+	}
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys)
+{
+	if (dmanr <= 3)  {
+	    dma_outb( phys & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
+            dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
+	}  else  {
+	    dma_outb( (phys>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	    dma_outb( (phys>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	}
+	set_dma_page(dmanr, phys>>16);
+}
+
+
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
+ * a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+        count--;
+	if (dmanr <= 3)  {
+	    dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
+	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
+        } else {
+	    dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+	    dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+        }
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ *
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+	unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
+					 : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
+
+	/* using short to get 16-bit wrap around */
+	unsigned short count;
+
+	count = 1 + dma_inb(io_port);
+	count += dma_inb(io_port) << 8;
+	
+	return (dmanr <= 3)? count : (count<<1);
+}
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr);	/* release it again */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;                                        
+#else                                                         
+#define isa_dma_bridge_buggy   (0)
+#endif
+#endif /* _ASM_DMA_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/eeh.h linux-2.4.19-pre5/include/asm-ppc64/eeh.h
--- linux-2.4.19-pre4/include/asm-ppc64/eeh.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/eeh.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,150 @@
+/* 
+ * eeh.h
+ * Copyright (C) 2001  Dave Engebretsen & Todd Inglett IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Start Change Log
+ * 2001/10/27 : engebret : Created.
+ * End Change Log 
+ */
+
+#ifndef _EEH_H
+#define _EEH_H
+
+struct pci_dev;
+
+#define IO_UNMAPPED_REGION_ID 0xaUL
+
+#define IO_TOKEN_TO_ADDR(token) ((((unsigned long)(token)) & 0xFFFFFFFF) | (0xEUL << 60))
+/* Flag bits encoded in the 3 unused function bits of devfn */
+#define EEH_TOKEN_DISABLED (1UL << 34UL)	/* eeh is disabled for this token */
+#define IS_EEH_TOKEN_DISABLED(token) ((unsigned long)(token) & EEH_TOKEN_DISABLED)
+
+#define EEH_STATE_OVERRIDE 1   /* IOA does not require eeh traps */
+#define EEH_STATE_FAILURE  16  /* */
+
+/* This is for profiling only and should be removed */
+extern unsigned long eeh_total_mmio_reads;
+extern unsigned long eeh_total_mmio_ffs;
+
+void eeh_init(void);
+int eeh_get_state(unsigned long ea);
+unsigned long eeh_check_failure(void *token, unsigned long val);
+
+#define EEH_DISABLE		0
+#define EEH_ENABLE		1
+#define EEH_RELEASE_LOADSTORE	2
+#define EEH_RELEASE_DMA		3
+int eeh_set_option(struct pci_dev *dev, int options);
+
+/* Given a PCI device check if eeh should be configured or not.
+ * This may look at firmware properties and/or kernel cmdline options.
+ */
+int is_eeh_configured(struct pci_dev *dev);
+
+/* Generate an EEH token.
+ * The high nibble of the offset is cleared, otherwise bounds checking is performed.
+ * Use IO_TOKEN_TO_ADDR(token) to translate this token back to a mapped virtual addr.
+ * Do NOT do this to perform IO -- use the read/write macros!
+ */
+unsigned long eeh_token(unsigned long phb,
+			unsigned long bus,
+			unsigned long devfn,
+			unsigned long offset);
+
+extern void *memcpy(void *, const void *, unsigned long);
+extern void *memset(void *,int, unsigned long);
+
+/* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
+ *
+ * Order this macro for performance.
+ * If EEH is off for a device and it is a memory BAR, ioremap will
+ * map it to the IOREGION.  In this case addr == vaddr and since these
+ * should be in registers we compare them first.  Next we check for
+ * all ones which is perhaps fastest as ~val.  Finally we weed out
+ * EEH disabled IO BARs.
+ *
+ * If this macro yields TRUE, the caller relays to eeh_check_failure()
+ * which does further tests out of line.
+ */
+/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && ~(val) == 0 && !IS_EEH_TOKEN_DISABLED(addr)) */
+/* This version is rearranged to collect some profiling data */
+#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (++eeh_total_mmio_reads, (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr))))
+
+/* 
+ * MMIO read/write operations with EEH support.
+ *
+ * addr: 64b token of the form 0xA0PPBBDDyyyyyyyy
+ *       0xA0     : Unmapped MMIO region
+ *       PP       : PHB index (starting at zero)
+ *	 BB	  : PCI Bus number under given PHB
+ *	 DD	  : PCI devfn under given bus
+ *       yyyyyyyy : Virtual address offset
+ * 
+ * An actual virtual address is produced from this token
+ * by masking into the form:
+ *   0xE0000000yyyyyyyy
+ */
+static inline u8 eeh_readb(void *addr) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	u8 val = in_8(vaddr);
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+		return eeh_check_failure(addr, val);
+	return val;
+}
+static inline void eeh_writeb(u8 val, void *addr) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	out_8(vaddr, val);
+}
+static inline u16 eeh_readw(void *addr) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	u16 val = in_le16(vaddr);
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+		return eeh_check_failure(addr, val);
+	return val;
+}
+static inline void eeh_writew(u16 val, void *addr) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	out_le16(vaddr, val);
+}
+static inline u32 eeh_readl(void *addr) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	u32 val = in_le32(vaddr);
+	if (EEH_POSSIBLE_ERROR(addr, vaddr, val))
+		return eeh_check_failure(addr, val);
+	return val;
+}
+static inline void eeh_writel(u32 val, void *addr) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	out_le32(vaddr, val);
+}
+
+static inline void eeh_memset_io(void *addr, int c, unsigned long n) {
+	void *vaddr = (void *)IO_TOKEN_TO_ADDR(addr);
+	memset(vaddr, c, n);
+}
+static inline void eeh_memcpy_fromio(void *dest, void *src, unsigned long n) {
+	void *vsrc = (void *)IO_TOKEN_TO_ADDR(src);
+	memcpy(dest, vsrc, n);
+	/* look for ffff's here at dest[n] */
+}
+static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) {
+	void *vdest = (void *)IO_TOKEN_TO_ADDR(dest);
+	memcpy(vdest, src, n);
+}
+
+#endif /* _EEH_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/elf.h linux-2.4.19-pre5/include/asm-ppc64/elf.h
--- linux-2.4.19-pre4/include/asm-ppc64/elf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/elf.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,149 @@
+#ifndef __PPC64_ELF_H
+#define __PPC64_ELF_H
+
+/*
+ * ELF register definitions..
+ *
+ * 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 <asm/ptrace.h>
+
+#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
+#define ELF_NFPREG	33	/* includes fpscr */
+#define ELF_NVRREG	33	/* includes vscr */
+
+typedef unsigned long elf_greg_t64;
+typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG];
+
+typedef unsigned int elf_greg_t32;
+typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG];
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#ifndef ELF_ARCH
+# define ELF_ARCH	EM_PPC64
+# define ELF_CLASS	ELFCLASS64
+# define ELF_DATA	ELFDATA2MSB
+  typedef elf_greg_t64 elf_greg_t;
+  typedef elf_gregset_t64 elf_gregset_t;
+# define elf_addr_t unsigned long
+# define elf_caddr_t char *
+#else
+  /* Assumption: ELF_ARCH == EM_PPC and ELF_CLASS == ELFCLASS32 */
+  typedef elf_greg_t32 elf_greg_t;
+  typedef elf_gregset_t32 elf_gregset_t;
+# define elf_addr_t u32
+# define elf_caddr_t u32
+#endif
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.  */
+
+#define ELF_ET_DYN_BASE         (0x08000000)
+
+/* Common routine for both 32-bit and 64-bit processes */
+#define ELF_CORE_COPY_REGS(gregs, regs) elf_core_copy_regs(gregs, regs);
+static inline void
+elf_core_copy_regs(elf_gregset_t dstRegs, struct pt_regs* srcRegs)
+{
+	int i;
+
+	int numGPRS = ((sizeof(struct pt_regs)/sizeof(elf_greg_t64)) < ELF_NGREG) ? (sizeof(struct pt_regs)/sizeof(elf_greg_t64)) : ELF_NGREG;
+
+	for (i=0; i < numGPRS; i++)
+		dstRegs[i] = (elf_greg_t)((elf_greg_t64 *)srcRegs)[i];
+}
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  This could be done in userspace,
+   but it's not easy, and we've already done it here.  */
+
+#define ELF_HWCAP	(0)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.
+
+   For the moment, we have only optimizations for the Intel generations,
+   but that could change... */
+
+#define ELF_PLATFORM	(NULL)
+
+
+#define ELF_PLAT_INIT(_r, load_addr)	do { \
+	memset(_r->gpr, 0, sizeof(_r->gpr)); \
+	_r->ctr = _r->link = _r->xer = _r->ccr = 0; \
+	_r->gpr[2] = load_addr; \
+} while (0)
+
+
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2)				\
+do {	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)		\
+		current->thread.flags |= PPC_FLAG_32BIT;	\
+	else							\
+		current->thread.flags &= ~PPC_FLAG_32BIT;	\
+	if (ibcs2)						\
+		set_personality(PER_SVR4);			\
+	else if (current->personality != PER_LINUX32)		\
+		set_personality(PER_LINUX);			\
+} while (0)
+#endif
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE		19
+#define AT_ICACHEBSIZE		20
+#define AT_UCACHEBSIZE		21
+/* A special ignored type value for PPC, for glibc compatibility.  */
+#define AT_IGNOREPPC		22
+
+extern int dcache_bsize;
+extern int icache_bsize;
+extern int ucache_bsize;
+
+/*
+ * The requirements here are:
+ * - keep the final alignment of sp (sp & 0xf)
+ * - make sure the 32-bit value at the first 16 byte aligned position of
+ *   AUXV is greater than 16 for glibc compatibility.
+ *   AT_IGNOREPPC is used for that.
+ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
+ *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
+ */
+#define DLINFO_ARCH_ITEMS	3
+#define ARCH_DLINFO							\
+do {									\
+	sp -= DLINFO_ARCH_ITEMS * 2;					\
+	NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize);			\
+	NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize);			\
+	NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize);			\
+	/*								\
+	 * Now handle glibc compatibility.				\
+	 */								\
+	sp -= 2*2;							\
+	NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC);			\
+	NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC);			\
+ } while (0)
+
+#endif /* __PPC64_ELF_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/errno.h linux-2.4.19-pre5/include/asm-ppc64/errno.h
--- linux-2.4.19-pre4/include/asm-ppc64/errno.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/errno.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,145 @@
+#ifndef _PPC64_ERRNO_H
+#define _PPC64_ERRNO_H
+
+/* 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Arg list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+#define	EDEADLK		35	/* Resource deadlock would occur */
+#define	ENAMETOOLONG	36	/* File name too long */
+#define	ENOLCK		37	/* No record locks available */
+#define	ENOSYS		38	/* Function not implemented */
+#define	ENOTEMPTY	39	/* Directory not empty */
+#define	ELOOP		40	/* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	ENOMSG		42	/* No message of desired type */
+#define	EIDRM		43	/* Identifier removed */
+#define	ECHRNG		44	/* Channel number out of range */
+#define	EL2NSYNC	45	/* Level 2 not synchronized */
+#define	EL3HLT		46	/* Level 3 halted */
+#define	EL3RST		47	/* Level 3 reset */
+#define	ELNRNG		48	/* Link number out of range */
+#define	EUNATCH		49	/* Protocol driver not attached */
+#define	ENOCSI		50	/* No CSI structure available */
+#define	EL2HLT		51	/* Level 2 halted */
+#define	EBADE		52	/* Invalid exchange */
+#define	EBADR		53	/* Invalid request descriptor */
+#define	EXFULL		54	/* Exchange full */
+#define	ENOANO		55	/* No anode */
+#define	EBADRQC		56	/* Invalid request code */
+#define	EBADSLT		57	/* Invalid slot */
+#define	EDEADLOCK	58	/* File locking deadlock error */
+#define	EBFONT		59	/* Bad font file format */
+#define	ENOSTR		60	/* Device not a stream */
+#define	ENODATA		61	/* No data available */
+#define	ETIME		62	/* Timer expired */
+#define	ENOSR		63	/* Out of streams resources */
+#define	ENONET		64	/* Machine is not on the network */
+#define	ENOPKG		65	/* Package not installed */
+#define	EREMOTE		66	/* Object is remote */
+#define	ENOLINK		67	/* Link has been severed */
+#define	EADV		68	/* Advertise error */
+#define	ESRMNT		69	/* Srmount error */
+#define	ECOMM		70	/* Communication error on send */
+#define	EPROTO		71	/* Protocol error */
+#define	EMULTIHOP	72	/* Multihop attempted */
+#define	EDOTDOT		73	/* RFS specific error */
+#define	EBADMSG		74	/* Not a data message */
+#define	EOVERFLOW	75	/* Value too large for defined data type */
+#define	ENOTUNIQ	76	/* Name not unique on network */
+#define	EBADFD		77	/* File descriptor in bad state */
+#define	EREMCHG		78	/* Remote address changed */
+#define	ELIBACC		79	/* Can not access a needed shared library */
+#define	ELIBBAD		80	/* Accessing a corrupted shared library */
+#define	ELIBSCN		81	/* .lib section in a.out corrupted */
+#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
+#define	EILSEQ		84	/* Illegal byte sequence */
+#define	ERESTART	85	/* Interrupted system call should be restarted */
+#define	ESTRPIPE	86	/* Streams pipe error */
+#define	EUSERS		87	/* Too many users */
+#define	ENOTSOCK	88	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	89	/* Destination address required */
+#define	EMSGSIZE	90	/* Message too long */
+#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92	/* Protocol not available */
+#define	EPROTONOSUPPORT	93	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96	/* Protocol family not supported */
+#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
+#define	EADDRINUSE	98	/* Address already in use */
+#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define	ENETDOWN	100	/* Network is down */
+#define	ENETUNREACH	101	/* Network is unreachable */
+#define	ENETRESET	102	/* Network dropped connection because of reset */
+#define	ECONNABORTED	103	/* Software caused connection abort */
+#define	ECONNRESET	104	/* Connection reset by peer */
+#define	ENOBUFS		105	/* No buffer space available */
+#define	EISCONN		106	/* Transport endpoint is already connected */
+#define	ENOTCONN	107	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ECONNREFUSED	111	/* Connection refused */
+#define	EHOSTDOWN	112	/* Host is down */
+#define	EHOSTUNREACH	113	/* No route to host */
+#define	EALREADY	114	/* Operation already in progress */
+#define	EINPROGRESS	115	/* Operation now in progress */
+#define	ESTALE		116	/* Stale NFS file handle */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	ENOTNAM		118	/* Not a XENIX named type file */
+#define	ENAVAIL		119	/* No XENIX semaphores available */
+#define	EISNAM		120	/* Is a named type file */
+#define	EREMOTEIO	121	/* Remote I/O error */
+#define	EDQUOT		122	/* Quota exceeded */
+
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
+/* Should never be seen by user programs */
+#define ERESTARTSYS	512
+#define ERESTARTNOINTR	513
+#define ERESTARTNOHAND	514	/* restart if no handler.. */
+#define ENOIOCTLCMD	515	/* No ioctl command */
+
+#define _LAST_ERRNO	515
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/fcntl.h linux-2.4.19-pre5/include/asm-ppc64/fcntl.h
--- linux-2.4.19-pre4/include/asm-ppc64/fcntl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/fcntl.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,110 @@
+#ifndef _PPC64_FCNTL_H
+#define _PPC64_FCNTL_H
+
+/*
+ * 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.
+ */
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE	   0003
+#define O_RDONLY	     00
+#define O_WRONLY	     01
+#define O_RDWR		     02
+#define O_CREAT		   0100	/* not fcntl */
+#define O_EXCL		   0200	/* not fcntl */
+#define O_NOCTTY	   0400	/* not fcntl */
+#define O_TRUNC		  01000	/* not fcntl */
+#define O_APPEND	  02000
+#define O_NONBLOCK	  04000
+#define O_NDELAY	O_NONBLOCK
+#define O_SYNC		 010000
+#define FASYNC		 020000	/* fcntl, for BSD compatibility */
+#define O_DIRECTORY      040000	/* must be a directory */
+#define O_NOFOLLOW      0100000	/* don't follow links */
+#define O_LARGEFILE     0200000
+#define O_DIRECT	0400000	/* direct disk access hint - currently ignored */
+
+#define F_DUPFD		0	/* dup */
+#define F_GETFD		1	/* get close_on_exec */
+#define F_SETFD		2	/* set/clear close_on_exec */
+#define F_GETFL		3	/* get file->f_flags */
+#define F_SETFL		4	/* set file->f_flags */
+#define F_GETLK		5
+#define F_SETLK		6
+#define F_SETLKW	7
+
+#define F_SETOWN	8	/*  for sockets. */
+#define F_GETOWN	9	/*  for sockets. */
+#define F_SETSIG	10	/*  for sockets. */
+#define F_GETSIG	11	/*  for sockets. */
+
+#define F_GETLK64	12	/*  using 'struct flock64' */
+#define F_SETLK64	13
+#define F_SETLKW64	14
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC	1	/* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK		0
+#define F_WRLCK		1
+#define F_UNLCK		2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK		4	/* or 3 */
+#define F_SHLCK		8	/* or 4 */
+
+/* for leases */
+#define F_INPROGRESS	16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH		1	/* shared lock */
+#define LOCK_EX		2	/* exclusive lock */
+#define LOCK_NB		4	/* or'd with one of the above to prevent
+				   blocking */
+#define LOCK_UN		8	/* remove lock */
+
+#define LOCK_MAND	32	/* This is a mandatory flock */
+#define LOCK_READ	64	/* ... Which allows concurrent read operations */
+#define LOCK_WRITE	128	/* ... Which allows concurrent write operations */
+#define LOCK_RW		192	/* ... Which allows concurrent read & write ops */
+
+#ifdef __KERNEL__
+#define F_POSIX		1
+#define F_FLOCK		2
+#define F_BROKEN	4	/* broken flock() emulation */
+#endif /* __KERNEL__ */
+
+struct flock {
+	short l_type;
+	short l_whence;
+	off_t l_start;
+	off_t l_len;
+	pid_t l_pid;
+};
+
+#ifdef __KERNEL__
+struct flock32 {
+	short l_type;
+	short l_whence;
+	__kernel_off_t32 l_start;
+	__kernel_off_t32 l_len;
+	__kernel_pid_t32 l_pid;
+	short __unused;
+};
+#endif
+
+struct flock64 {
+	short  l_type;
+	short  l_whence;
+	loff_t l_start;
+	loff_t l_len;
+	pid_t  l_pid;
+};
+
+#define F_LINUX_SPECIFIC_BASE	1024
+#endif /* _PPC64_FCNTL_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/flight_recorder.h linux-2.4.19-pre5/include/asm-ppc64/flight_recorder.h
--- linux-2.4.19-pre4/include/asm-ppc64/flight_recorder.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/flight_recorder.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,55 @@
+/************************************************************************
+ * flight_recorder.h                                                    *
+ ************************************************************************
+ * This code supports the a generic flight recorder.                    *
+ * Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    * 
+ *                                                                      *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or    *
+ * (at your option) any later version.                                  *
+ *                                                                      *
+ * This program is distributed in the hope that it will be useful,      * 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
+ * GNU General Public License for more details.                         *
+ *                                                                      *
+ * You should have received a copy of the GNU General Public License    * 
+ * along with this program; if not, write to the:                       *
+ * Free Software Foundation, Inc.,                                      * 
+ * 59 Temple Place, Suite 330,                                          * 
+ * Boston, MA  02111-1307  USA                                          *
+ ************************************************************************
+ * See the fight_recorder.c file for useage deails.                     *
+ ************************************************************************/
+#include <linux/kernel.h>
+
+/************************************************************************
+ * Generic Flight Recorder Structure                                    *
+ ************************************************************************/
+struct flightRecorder {                 /* Structure Defination         */
+	char  Signature[8];                /* Eye Catcher                  */
+	int   Size;			            /* Size of Flight Recorder      */
+	int   Flags;                       /* Format Flags.                */				
+	char* StartPointer;                /* Buffer Starting Address      */
+	char* EndPointer;                  /* Buffer Ending Address        */
+	char* NextPointer;                 /* Next Entry Address           */
+	char* WrapPointer;                 /* Point at which buffer wraps  */
+	char* Buffer;                      /* Where the data log is.       */
+};
+typedef struct flightRecorder FlightRecorder;
+
+/************************************************************************
+ * Forware declares
+ ************************************************************************/
+FlightRecorder* alloc_Flight_Recorder(FlightRecorder* FrPtr, char* Signature, int SizeOfFr);
+void            fr_Log_Entry(FlightRecorder* LogFr, const char *fmt, ...);
+int             fr_Dump(FlightRecorder* Fr, char *Buffer, int BufferLen);
+
+/************************************************************************
+ * Sample Macro to make life easier using the flight_recorder. 
+ * TestFr is a global value.
+ * To use them: TESTFR("Test Loop value is &d",Loop");
+ ************************************************************************/
+#define LOGFR(...) (fr_Log_Entry(__VA_ARGS__))
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/floppy.h linux-2.4.19-pre5/include/asm-ppc64/floppy.h
--- linux-2.4.19-pre4/include/asm-ppc64/floppy.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/floppy.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,105 @@
+/*
+ * Architecture specific parts of the Floppy driver
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995
+ */
+#ifndef __ASM_PPC64_FLOPPY_H
+#define __ASM_PPC64_FLOPPY_H
+
+#include <linux/config.h>
+
+#define fd_inb(port)			inb_p(port)
+#define fd_outb(port,value)		outb_p(port,value)
+
+#define fd_enable_dma()         enable_dma(FLOPPY_DMA)
+#define fd_disable_dma()        disable_dma(FLOPPY_DMA)
+#define fd_request_dma()        request_dma(FLOPPY_DMA,"floppy")
+#define fd_free_dma()           free_dma(FLOPPY_DMA)
+#define fd_clear_dma_ff()       clear_dma_ff(FLOPPY_DMA)
+#define fd_set_dma_mode(mode)   set_dma_mode(FLOPPY_DMA,mode)
+#define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
+#define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
+#define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
+#define fd_cacheflush(addr,size) /* nothing */
+#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
+					    SA_INTERRUPT|SA_SAMPLE_RANDOM, \
+				            "floppy", NULL)
+#define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
+
+#ifdef CONFIG_PCI
+
+#include <linux/pci.h>
+
+#define fd_dma_setup(addr,size,mode,io) ppc64_fd_dma_setup(addr,size,mode,io)
+
+static __inline__ int 
+ppc64_fd_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	static unsigned long prev_size;
+	static dma_addr_t bus_addr = 0;
+	static char *prev_addr;
+	static int prev_dir;
+	int dir;
+
+	dir = (mode == DMA_MODE_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE;
+
+	if (bus_addr 
+	    && (addr != prev_addr || size != prev_size || dir != prev_dir)) {
+		/* different from last time -- unmap prev */
+		pci_unmap_single(NULL, bus_addr, prev_size, prev_dir);
+		bus_addr = 0;
+	}
+
+	if (!bus_addr)	/* need to map it */ {
+		bus_addr = pci_map_single(NULL, addr, size, dir);
+	}
+
+	/* remember this one as prev */
+	prev_addr = addr;
+	prev_size = size;
+	prev_dir = dir;
+
+	fd_clear_dma_ff();
+	fd_cacheflush(addr, size);
+	fd_set_dma_mode(mode);
+	set_dma_addr(FLOPPY_DMA, bus_addr);
+	fd_set_dma_count(size);
+	virtual_dma_port = io;
+	fd_enable_dma();
+
+	return 0;
+}
+
+#endif /* CONFIG_PCI */
+
+__inline__ void virtual_dma_init(void)
+{
+	/* Nothing to do on PowerPC */
+}
+
+static int FDC1 = 0x3f0;
+static int FDC2 = -1;
+
+/*
+ * Again, the CMOS information not available
+ */
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
+
+#define N_FDC 2			/* Don't change this! */
+#define N_DRIVE 8
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+/*
+ * The PowerPC has no problems with floppy DMA crossing 64k borders.
+ */
+#define CROSS_64KB(a,s)	(0)
+
+#define EXTRA_FLOPPY_PARAMS
+
+#endif /* __ASM_PPC64_FLOPPY_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/hardirq.h linux-2.4.19-pre5/include/asm-ppc64/hardirq.h
--- linux-2.4.19-pre4/include/asm-ppc64/hardirq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/hardirq.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,100 @@
+#ifdef __KERNEL__
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+/*
+ * Use a brlock for the global irq lock, based on sparc64.
+ * Anton Blanchard <anton@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/brlock.h>
+#include <linux/spinlock.h>
+
+
+typedef struct {
+	unsigned long __softirq_pending;
+#ifndef CONFIG_SMP
+	unsigned int __local_irq_count;
+#else
+	unsigned int __unused_on_SMP;		/* We use brlocks on SMP */
+#endif
+	unsigned int __local_bh_count;
+	unsigned int __syscall_count;
+	unsigned long __unused;
+	struct task_struct * __ksoftirqd_task;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+/* Note that local_irq_count() is replaced by ppc64 specific version for SMP */
+
+#ifndef CONFIG_SMP
+#define irq_enter(cpu)		(local_irq_count(cpu)++)
+#define irq_exit(cpu)		(local_irq_count(cpu)--)
+#else
+#undef local_irq_count
+#define local_irq_count(cpu)	(__brlock_array[cpu][BR_GLOBALIRQ_LOCK])
+#define irq_enter(cpu)		br_read_lock(BR_GLOBALIRQ_LOCK)
+#define irq_exit(cpu)		br_read_unlock(BR_GLOBALIRQ_LOCK)
+#endif
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+/* This tests only the local processors hw IRQ context disposition.  */
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
+#ifndef CONFIG_SMP
+
+#define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
+#define hardirq_endlock(cpu)	do { } while (0)
+
+#define synchronize_irq()	barrier()
+
+#else /* CONFIG_SMP */
+
+static __inline__ int irqs_running(void)
+{
+	int i;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		if (local_irq_count(cpu_logical_map(i)))
+			return 1;
+	return 0;
+}
+
+extern unsigned char global_irq_holder;
+
+static inline void release_irqlock(int cpu)
+{
+	/* if we didn't own the irq lock, just ignore... */
+	if(global_irq_holder == (unsigned char) cpu) {
+		global_irq_holder = NO_PROC_ID;
+		br_write_unlock(BR_GLOBALIRQ_LOCK);
+	}
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+	spinlock_t *lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock;
+
+	return (!local_irq_count(cpu) && !spin_is_locked(lock));
+}
+
+#define hardirq_endlock(cpu)    do { (void)(cpu); } while (0)
+
+extern void synchronize_irq(void);
+
+#endif /* CONFIG_SMP */
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_HARDIRQ_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/hdreg.h linux-2.4.19-pre5/include/asm-ppc64/hdreg.h
--- linux-2.4.19-pre4/include/asm-ppc64/hdreg.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/hdreg.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,22 @@
+/*
+ *  linux/include/asm-ppc/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ *
+ * 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 file contains the ppc architecture specific IDE code.
+ */
+
+#ifndef __ASMPPC64_HDREG_H
+#define __ASMPPC64_HDREG_H
+
+typedef unsigned long ide_ioreg_t;
+
+#endif /* __ASMPPC64_HDREG_H */
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/hw_irq.h linux-2.4.19-pre5/include/asm-ppc64/hw_irq.h
--- linux-2.4.19-pre4/include/asm-ppc64/hw_irq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/hw_irq.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
+ * Use inline IRQs where possible - Anton Blanchard <anton@au.ibm.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.
+ */
+#ifdef __KERNEL__
+#ifndef _PPC64_HW_IRQ_H
+#define _PPC64_HW_IRQ_H
+
+#include <linux/config.h>
+#include <asm/irq.h>
+
+int timer_interrupt(struct pt_regs *);
+
+#ifdef CONFIG_PPC_ISERIES
+
+extern void __no_use_sti(void);
+extern void __no_use_cli(void);
+extern void __no_use_restore_flags(unsigned long);
+extern unsigned long __no_use_save_flags(void);
+extern void __no_use_set_lost(unsigned long);
+extern void __no_lpq_restore_flags(unsigned long);
+
+#define __cli()			__no_use_cli()
+#define __sti()			__no_use_sti()
+#define __save_flags(flags)	((flags) = __no_use_save_flags())
+#define __restore_flags(flags)	__no_use_restore_flags((unsigned long)flags)
+#define __save_and_cli(flags)	({__save_flags(flags);__cli();})
+
+#else
+
+#define __save_flags(flags)	((flags) = mfmsr())
+#define __restore_flags(flags)	mtmsrd(flags)
+
+static inline void __cli(void)
+{
+	unsigned long msr;
+	msr = mfmsr();
+	mtmsrd(msr & ~MSR_EE);
+	__asm__ __volatile__("": : :"memory");
+}
+
+static inline void __sti(void)
+{
+	unsigned long msr;
+	__asm__ __volatile__("": : :"memory");
+	msr = mfmsr();
+	mtmsrd(msr | MSR_EE);
+}
+
+static inline void __do_save_and_cli(unsigned long *flags)
+{
+	unsigned long msr;
+	msr = mfmsr();
+	*flags = msr;
+	mtmsrd(msr & ~MSR_EE);
+	__asm__ __volatile__("": : :"memory");
+}
+
+#define __save_and_cli(flags)          __do_save_and_cli(&flags)
+
+#endif /* CONFIG_PPC_ISERIES */
+
+#define mask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->disable) irq_desc[irq].handler->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->enable) irq_desc[irq].handler->enable(irq);})
+#define ack_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->ack) irq_desc[irq].handler->ack(irq);})
+
+/* Should we handle this via lost interrupts and IPIs or should we don't care like
+ * we do now ? --BenH.
+ */
+struct hw_interrupt_type;
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
+
+#endif /* _PPC64_HW_IRQ_H */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCall.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCall.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCall.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCall.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,209 @@
+/*
+ * HvCall.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//===========================================================================
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from the OS.
+//
+//===========================================================================
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include "HvCallSc.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+#include <asm/Paca.h>
+
+//-------------------------------------------------------------------
+// Constants
+//-------------------------------------------------------------------
+#ifndef _HVCALL_H
+#define _HVCALL_H
+/*
+enum HvCall_ReturnCode
+{
+	HvCall_Good		= 0,
+	HvCall_Partial		= 1,
+	HvCall_NotOwned		= 2,
+	HvCall_NotFreed		= 3,
+	HvCall_UnspecifiedError	= 4
+};
+
+enum HvCall_TypeOfSIT
+{
+	HvCall_ReduceOnly	= 0,
+	HvCall_Unconditional	= 1
+};
+
+enum HvCall_TypeOfYield
+{
+	HvCall_YieldTimed	= 0,	// Yield until specified time
+	HvCall_YieldToActive	= 1,	// Yield until all active procs have run
+	HvCall_YieldToProc	= 2	// Yield until the specified processor has run
+};
+
+enum HvCall_InterruptMasks
+{
+	HvCall_MaskIPI		= 0x00000001,
+	HvCall_MaskLpEvent	= 0x00000002,
+	HvCall_MaskLpProd	= 0x00000004,
+	HvCall_MaskTimeout	= 0x00000008
+};
+
+enum HvCall_VaryOffChunkRc
+{
+	HvCall_VaryOffSucceeded		= 0,
+	HvCall_VaryOffWithdrawn		= 1,
+	HvCall_ChunkInLoadArea		= 2,
+	HvCall_ChunkInHPT		= 3,
+	HvCall_ChunkNotAccessible	= 4,
+	HvCall_ChunkInUse		= 5
+};
+*/
+
+/* Type of yield for HvCallBaseYieldProcessor */
+#define HvCall_YieldTimed 	0	// Yield until specified time (tb)
+#define HvCall_YieldToActive	1	// Yield until all active procs have run
+#define HvCall_YieldToProc	2	// Yield until the specified processor has run
+
+/* interrupt masks for setEnabledInterrupts */
+#define HvCall_MaskIPI		0x00000001
+#define HvCall_MaskLpEvent	0x00000002
+#define HvCall_MaskLpProd	0x00000004
+#define HvCall_MaskTimeout	0x00000008
+
+/* Log buffer formats                       */
+#define HvCall_LogBuffer_ASCII          0
+#define HvCall_LogBuffer_EBCDIC         1
+
+#define HvCallBaseAckDeferredInts			HvCallBase +  0
+#define HvCallBaseCpmPowerOff				HvCallBase +  1
+#define HvCallBaseGetHwPatch				HvCallBase +  2
+#define HvCallBaseReIplSpAttn				HvCallBase +  3
+#define HvCallBaseSetASR				HvCallBase +  4
+#define HvCallBaseSetASRAndRfi				HvCallBase +  5 
+#define HvCallBaseSetIMR				HvCallBase +  6
+#define HvCallBaseSendIPI				HvCallBase +  7
+#define HvCallBaseTerminateMachine			HvCallBase +  8
+#define HvCallBaseTerminateMachineSrc			HvCallBase +  9
+#define HvCallBaseProcessPlicInterrupts			HvCallBase + 10
+#define HvCallBaseIsPrimaryCpmOrMsdIpl			HvCallBase + 11
+#define HvCallBaseSetVirtualSIT				HvCallBase + 12
+#define HvCallBaseVaryOffThisProcessor			HvCallBase + 13
+#define HvCallBaseVaryOffMemoryChunk			HvCallBase + 14
+#define HvCallBaseVaryOffInteractivePercentage		HvCallBase + 15
+#define HvCallBaseSendLpProd				HvCallBase + 16
+#define HvCallBaseSetEnabledInterrupts			HvCallBase + 17
+#define HvCallBaseYieldProcessor			HvCallBase + 18
+#define HvCallBaseVaryOffSharedProcUnits		HvCallBase + 19
+#define HvCallBaseSetVirtualDecr			HvCallBase + 20
+#define HvCallBaseClearLogBuffer			HvCallBase + 21
+#define HvCallBaseGetLogBufferCodePage			HvCallBase + 22
+#define HvCallBaseGetLogBufferFormat			HvCallBase + 23
+#define HvCallBaseGetLogBufferLength			HvCallBase + 24
+#define HvCallBaseReadLogBuffer 			HvCallBase + 25
+#define HvCallBaseSetLogBufferFormatAndCodePage		HvCallBase + 26
+#define HvCallBaseWriteLogBuffer               		HvCallBase + 27
+#define HvCallBaseRouter28				HvCallBase + 28
+#define HvCallBaseRouter29				HvCallBase + 29
+#define HvCallBaseRouter30				HvCallBase + 30
+//=====================================================================================
+static inline void		HvCall_setVirtualDecr(void)
+{
+	// Ignore any error return codes - most likely means that the target value for the
+	// LP has been increased and this vary off would bring us below the new target.
+	HvCall0(HvCallBaseSetVirtualDecr);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//=====================================================================
+static inline void		HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
+{
+	HvCall2( HvCallBaseYieldProcessor, typeOfYield, yieldParm );
+}
+//=====================================================================
+static inline void		HvCall_setEnabledInterrupts(u64 enabledInterrupts)
+{
+	HvCall1(HvCallBaseSetEnabledInterrupts,enabledInterrupts);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+
+//=====================================================================
+static inline void		HvCall_clearLogBuffer(HvLpIndex lpindex)
+{
+	HvCall1(HvCallBaseClearLogBuffer,lpindex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+
+//=====================================================================
+static inline u32  		HvCall_getLogBufferCodePage(HvLpIndex lpindex)
+{
+	u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage,lpindex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+
+//=====================================================================
+static inline int  		HvCall_getLogBufferFormat(HvLpIndex lpindex)
+{
+	int retVal = HvCall1(HvCallBaseGetLogBufferFormat,lpindex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+
+//=====================================================================
+static inline u32  		HvCall_getLogBufferLength(HvLpIndex lpindex)
+{
+	u32 retVal = HvCall1(HvCallBaseGetLogBufferLength,lpindex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+
+//=====================================================================
+static inline void  		HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage)
+{
+	HvCall2(HvCallBaseSetLogBufferFormatAndCodePage,format, codePage);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+
+//=====================================================================
+int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen);
+void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
+
+//=====================================================================
+static inline void		HvCall_sendIPI(struct Paca * targetPaca)
+{
+	HvCall1( HvCallBaseSendIPI, targetPaca->xPacaIndex );
+}
+
+//=====================================================================
+static inline void		HvCall_terminateMachineSrc(void)
+{
+	HvCall0( HvCallBaseTerminateMachineSrc );
+}
+
+
+#endif // _HVCALL_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallCfg.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallCfg.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallCfg.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallCfg.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,219 @@
+/*
+ * HvCallCfg.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=====================================================================================
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from the OS.
+//
+//=====================================================================================
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include "HvCallSc.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+//-------------------------------------------------------------------------------------
+// Constants
+//-------------------------------------------------------------------------------------
+#ifndef _HVCALLCFG_H
+#define _HVCALLCFG_H
+
+enum HvCallCfg_ReqQual
+{
+	HvCallCfg_Cur	= 0,
+	HvCallCfg_Init	= 1,
+	HvCallCfg_Max	= 2,
+	HvCallCfg_Min	= 3
+};
+
+#define HvCallCfgGetLps					HvCallCfg +  0
+#define HvCallCfgGetActiveLpMap				HvCallCfg +  1
+#define HvCallCfgGetLpVrmIndex				HvCallCfg +  2
+#define HvCallCfgGetLpMinSupportedPlicVrmIndex		HvCallCfg +  3
+#define HvCallCfgGetLpMinCompatablePlicVrmIndex		HvCallCfg +  4
+#define HvCallCfgGetLpVrmName				HvCallCfg +  5 
+#define HvCallCfgGetSystemPhysicalProcessors		HvCallCfg +  6
+#define HvCallCfgGetPhysicalProcessors			HvCallCfg +  7
+#define HvCallCfgGetSystemMsChunks			HvCallCfg +  8
+#define HvCallCfgGetMsChunks				HvCallCfg +  9
+#define HvCallCfgGetInteractivePercentage		HvCallCfg + 10
+#define HvCallCfgIsBusDedicated				HvCallCfg + 11
+#define HvCallCfgGetBusOwner				HvCallCfg + 12
+#define HvCallCfgGetBusAllocation			HvCallCfg + 13
+#define HvCallCfgGetBusUnitOwner			HvCallCfg + 14
+#define HvCallCfgGetBusUnitAllocation			HvCallCfg + 15
+#define HvCallCfgGetVirtualBusPool			HvCallCfg + 16
+#define HvCallCfgGetBusUnitInterruptProc		HvCallCfg + 17
+#define HvCallCfgGetConfiguredBusUnitsForIntProc	HvCallCfg + 18
+#define HvCallCfgGetRioSanBusPool			HvCallCfg + 19
+#define HvCallCfgGetSharedPoolIndex			HvCallCfg + 20
+#define HvCallCfgGetSharedProcUnits			HvCallCfg + 21
+#define HvCallCfgGetNumProcsInSharedPool		HvCallCfg + 22
+#define HvCallCfgRouter23				HvCallCfg + 23
+#define HvCallCfgRouter24				HvCallCfg + 24
+#define HvCallCfgRouter25				HvCallCfg + 25
+#define HvCallCfgRouter26				HvCallCfg + 26
+#define HvCallCfgRouter27				HvCallCfg + 27
+#define HvCallCfgGetMinRuntimeMsChunks			HvCallCfg + 28
+#define HvCallCfgSetMinRuntimeMsChunks			HvCallCfg + 29
+#define HvCallCfgGetVirtualLanIndexMap			HvCallCfg + 30
+#define HvCallCfgGetLpExecutionMode			HvCallCfg + 31
+#define HvCallCfgGetHostingLpIndex 			HvCallCfg + 32
+
+//====================================================================
+static inline HvLpIndex	HvCallCfg_getLps(void)
+{
+	HvLpIndex retVal = HvCall0(HvCallCfgGetLps);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline int		HvCallCfg_isBusDedicated(u64 busIndex)
+{
+	int retVal = HvCall1(HvCallCfgIsBusDedicated,busIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline HvLpIndex	HvCallCfg_getBusOwner(u64 busIndex)
+{
+	HvLpIndex retVal = HvCall1(HvCallCfgGetBusOwner,busIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline HvLpIndexMap	HvCallCfg_getBusAllocation(u64 busIndex)
+{
+	HvLpIndexMap retVal = HvCall1(HvCallCfgGetBusAllocation,busIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline HvLpIndexMap	HvCallCfg_getActiveLpMap(void)
+{
+	HvLpIndexMap retVal = HvCall0(HvCallCfgGetActiveLpMap);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline HvLpVirtualLanIndexMap	HvCallCfg_getVirtualLanIndexMap(HvLpIndex lp)
+{
+	// This is a new function in V5R1 so calls to this on older 
+	// hypervisors will return -1
+	u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp);
+	if(retVal == -1)
+		retVal = 0;
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_getSystemMsChunks(void)
+{
+	u64 retVal = HvCall0(HvCallCfgGetSystemMsChunks);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_getMsChunks(HvLpIndex lp,enum HvCallCfg_ReqQual qual)
+{
+	u64 retVal = HvCall2(HvCallCfgGetMsChunks,lp,qual);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp)
+{
+	// NOTE: This function was added in v5r1 so older hypervisors will return a -1 value
+	u64 retVal = HvCall1(HvCallCfgGetMinRuntimeMsChunks,lp);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_setMinRuntimeMsChunks(u64 chunks)
+{
+	u64 retVal = HvCall1(HvCallCfgSetMinRuntimeMsChunks,chunks);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_getSystemPhysicalProcessors(void)
+{
+	u64 retVal = HvCall0(HvCallCfgGetSystemPhysicalProcessors);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_getPhysicalProcessors(HvLpIndex lp,enum HvCallCfg_ReqQual qual)
+{
+	u64 retVal = HvCall2(HvCallCfgGetPhysicalProcessors,lp,qual);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline u64		HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp,
+										u16 hvLogicalProcIndex)
+{
+	u64 retVal = HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc,lp,hvLogicalProcIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+
+}
+//==================================================================
+static inline HvLpSharedPoolIndex	HvCallCfg_getSharedPoolIndex(HvLpIndex lp)
+{
+	HvLpSharedPoolIndex retVal =
+		HvCall1(HvCallCfgGetSharedPoolIndex,lp);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+
+}
+//==================================================================
+static inline u64	HvCallCfg_getSharedProcUnits(HvLpIndex lp,enum HvCallCfg_ReqQual qual)
+{
+	u64 retVal = HvCall2(HvCallCfgGetSharedProcUnits,lp,qual);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+
+}
+//==================================================================
+static inline u64	HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
+{
+	u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool,sPI);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+
+}
+//==================================================================
+static inline HvLpIndex	HvCallCfg_getHostingLpIndex(HvLpIndex lp)
+{
+	u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex,lp);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+
+}
+
+#endif // _HVCALLCFG_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallEvent.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallEvent.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallEvent.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallEvent.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,335 @@
+/*
+ * HvCallEvent.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//==================================================================
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from the OS.
+//
+//==================================================================
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include <asm/iSeries/HvCallSc.h>
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+#include <asm/abs_addr.h>
+
+//-------------------------------------------------------------------
+// Other Includes
+//-------------------------------------------------------------------
+
+//-------------------------------------------------------------------
+// Constants
+//-------------------------------------------------------------------
+#ifndef _HVCALLEVENT_H
+#define _HVCALLEVENT_H
+
+struct HvLpEvent;
+
+typedef u8 HvLpEvent_Type;
+typedef u8 HvLpEvent_AckInd;
+typedef u8 HvLpEvent_AckType;
+
+struct	HvCallEvent_PackedParms
+{
+	u8		xAckType:1;
+	u8		xAckInd:1;
+	u8		xRsvd:1;
+	u8		xTargetLp:5;
+	u8		xType;
+	u16		xSubtype;
+	HvLpInstanceId	xSourceInstId;
+	HvLpInstanceId	xTargetInstId;
+};
+
+typedef u8 HvLpDma_Direction;
+typedef u8 HvLpDma_AddressType;
+
+struct	HvCallEvent_PackedDmaParms
+{
+	u8		xDirection:1;
+	u8		xLocalAddrType:1;
+	u8		xRemoteAddrType:1;
+	u8		xRsvd1:5;
+	HvLpIndex	xRemoteLp;
+	u8		xType;
+	u8		xRsvd2;
+	HvLpInstanceId	xLocalInstId;
+	HvLpInstanceId	xRemoteInstId;
+};
+
+typedef u64 HvLpEvent_Rc;
+typedef u64 HvLpDma_Rc;
+
+#define HvCallEventAckLpEvent				HvCallEvent +  0
+#define HvCallEventCancelLpEvent			HvCallEvent +  1
+#define HvCallEventCloseLpEventPath			HvCallEvent +  2
+#define HvCallEventDmaBufList				HvCallEvent +  3
+#define HvCallEventDmaSingle				HvCallEvent +  4
+#define HvCallEventDmaToSp				HvCallEvent +  5 
+#define HvCallEventGetOverflowLpEvents			HvCallEvent +  6
+#define HvCallEventGetSourceLpInstanceId		HvCallEvent +  7
+#define HvCallEventGetTargetLpInstanceId		HvCallEvent +  8
+#define HvCallEventOpenLpEventPath			HvCallEvent +  9
+#define HvCallEventSetLpEventStack			HvCallEvent + 10
+#define HvCallEventSignalLpEvent			HvCallEvent + 11
+#define HvCallEventSignalLpEventParms			HvCallEvent + 12
+#define HvCallEventSetInterLpQueueIndex			HvCallEvent + 13
+#define HvCallEventSetLpEventQueueInterruptProc		HvCallEvent + 14
+#define HvCallEventRouter15				HvCallEvent + 15
+
+//======================================================================
+static inline void		HvCallEvent_getOverflowLpEvents(u8 queueIndex)
+{
+	HvCall1(HvCallEventGetOverflowLpEvents,queueIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//======================================================================
+static inline void		HvCallEvent_setInterLpQueueIndex(u8 queueIndex)
+{
+	HvCall1(HvCallEventSetInterLpQueueIndex,queueIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//======================================================================
+static inline void		HvCallEvent_setLpEventStack(u8 queueIndex,
+					     char * eventStackAddr,
+					     u32 eventStackSize)
+{
+	u64 abs_addr;
+	abs_addr = virt_to_absolute( (unsigned long) eventStackAddr );
+
+	HvCall3(HvCallEventSetLpEventStack, queueIndex, abs_addr, eventStackSize);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//======================================================================
+static inline void		HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex,
+							  u16 lpLogicalProcIndex)
+{
+	HvCall2(HvCallEventSetLpEventQueueInterruptProc,queueIndex,lpLogicalProcIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//=====================================================================
+static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent* event)
+{
+	u64 abs_addr;
+	HvLpEvent_Rc retVal;
+#ifdef DEBUG_SENDEVENT
+	printk("HvCallEvent_signalLpEvent: *event = %016lx\n ", (unsigned long)event);
+#endif
+	abs_addr = virt_to_absolute( (unsigned long) event );
+	retVal = (HvLpEvent_Rc)HvCall1(HvCallEventSignalLpEvent, abs_addr);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=====================================================================
+static inline HvLpEvent_Rc  HvCallEvent_signalLpEventFast(HvLpIndex targetLp,
+					   HvLpEvent_Type type,
+					   u16 subtype,
+					   HvLpEvent_AckInd ackInd,
+					   HvLpEvent_AckType ackType,
+					   HvLpInstanceId sourceInstanceId,
+					   HvLpInstanceId targetInstanceId,
+					   u64 correlationToken,
+					   u64 eventData1,
+					   u64 eventData2,
+					   u64 eventData3,
+					   u64 eventData4,
+					   u64 eventData5)
+{
+	HvLpEvent_Rc retVal;
+
+	// Pack the misc bits into a single Dword to pass to PLIC
+	union
+	{
+		struct HvCallEvent_PackedParms	parms;
+		u64		dword;
+	} packed;
+	packed.parms.xAckType	= ackType;
+	packed.parms.xAckInd	= ackInd;
+	packed.parms.xRsvd	= 0;
+	packed.parms.xTargetLp	= targetLp;
+	packed.parms.xType	= type;
+	packed.parms.xSubtype	= subtype;
+	packed.parms.xSourceInstId	= sourceInstanceId;
+	packed.parms.xTargetInstId	= targetInstanceId;
+
+	retVal = (HvLpEvent_Rc)HvCall7(HvCallEventSignalLpEventParms,
+				       packed.dword,
+				       correlationToken,
+				       eventData1,eventData2,
+				       eventData3,eventData4,
+				       eventData5);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline HvLpEvent_Rc	HvCallEvent_ackLpEvent(struct HvLpEvent* event)
+{
+	u64 abs_addr;
+	HvLpEvent_Rc retVal;
+	abs_addr = virt_to_absolute( (unsigned long) event );
+
+	retVal = (HvLpEvent_Rc)HvCall1(HvCallEventAckLpEvent, abs_addr);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//====================================================================
+static inline HvLpEvent_Rc   HvCallEvent_cancelLpEvent(struct HvLpEvent* event)
+{
+	u64 abs_addr;
+	HvLpEvent_Rc retVal;
+	abs_addr = virt_to_absolute( (unsigned long) event );
+
+	retVal = (HvLpEvent_Rc)HvCall1(HvCallEventCancelLpEvent, abs_addr);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline HvLpInstanceId	HvCallEvent_getSourceLpInstanceId(HvLpIndex targetLp, HvLpEvent_Type type)
+{
+	HvLpInstanceId retVal;	
+	retVal = HvCall2(HvCallEventGetSourceLpInstanceId,targetLp,type);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline HvLpInstanceId	HvCallEvent_getTargetLpInstanceId(HvLpIndex targetLp, HvLpEvent_Type type)
+{
+	HvLpInstanceId retVal;	
+	retVal = HvCall2(HvCallEventGetTargetLpInstanceId,targetLp,type);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//===================================================================
+static inline void		HvCallEvent_openLpEventPath(HvLpIndex targetLp,
+					     HvLpEvent_Type type)
+{
+	HvCall2(HvCallEventOpenLpEventPath,targetLp,type);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//===================================================================
+static inline void		HvCallEvent_closeLpEventPath(HvLpIndex targetLp,
+					      HvLpEvent_Type type)
+{
+	HvCall2(HvCallEventCloseLpEventPath,targetLp,type);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//===================================================================
+static inline HvLpDma_Rc	HvCallEvent_dmaBufList(HvLpEvent_Type type,
+					HvLpIndex remoteLp,
+					HvLpDma_Direction direction,
+					HvLpInstanceId localInstanceId,
+					HvLpInstanceId remoteInstanceId,
+					HvLpDma_AddressType localAddressType,
+					HvLpDma_AddressType remoteAddressType,
+					// Do these need to be converted to
+					// absolute addresses?
+					u64 localBufList,
+					u64 remoteBufList,
+
+					u32 transferLength)
+{
+	HvLpDma_Rc retVal;	
+	// Pack the misc bits into a single Dword to pass to PLIC
+	union
+	{
+		struct HvCallEvent_PackedDmaParms	parms;
+		u64		dword;
+	} packed;
+	packed.parms.xDirection		= direction;
+	packed.parms.xLocalAddrType	= localAddressType;
+	packed.parms.xRemoteAddrType	= remoteAddressType;
+	packed.parms.xRsvd1		= 0;
+	packed.parms.xRemoteLp		= remoteLp;
+	packed.parms.xType		= type;
+	packed.parms.xRsvd2		= 0;
+	packed.parms.xLocalInstId	= localInstanceId;
+	packed.parms.xRemoteInstId	= remoteInstanceId;
+
+	retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaBufList,
+				     packed.dword,
+				     localBufList,
+				     remoteBufList,
+				     transferLength);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=================================================================
+static inline HvLpDma_Rc	HvCallEvent_dmaSingle(HvLpEvent_Type type,
+				       HvLpIndex remoteLp,
+				       HvLpDma_Direction direction,
+				       HvLpInstanceId localInstanceId,
+				       HvLpInstanceId remoteInstanceId,
+				       HvLpDma_AddressType localAddressType,
+				       HvLpDma_AddressType remoteAddressType,
+				       u64 localAddrOrTce,
+				       u64 remoteAddrOrTce,
+				       u32 transferLength)
+{
+	HvLpDma_Rc retVal;	
+	// Pack the misc bits into a single Dword to pass to PLIC
+	union
+	{
+		struct HvCallEvent_PackedDmaParms	parms;
+		u64		dword;
+	} packed;
+	packed.parms.xDirection		= direction;
+	packed.parms.xLocalAddrType	= localAddressType;
+	packed.parms.xRemoteAddrType	= remoteAddressType;
+	packed.parms.xRsvd1		= 0;
+	packed.parms.xRemoteLp		= remoteLp;
+	packed.parms.xType		= type;
+	packed.parms.xRsvd2		= 0;
+	packed.parms.xLocalInstId	= localInstanceId;
+	packed.parms.xRemoteInstId	= remoteInstanceId;
+
+	retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaSingle,
+				     packed.dword,
+				     localAddrOrTce,
+				     remoteAddrOrTce,
+				     transferLength);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=================================================================
+static inline HvLpDma_Rc	HvCallEvent_dmaToSp(void* local, u32 remote, u32 length, HvLpDma_Direction dir)
+{
+	u64 abs_addr;
+	HvLpDma_Rc retVal;
+	abs_addr = virt_to_absolute( (unsigned long) local );
+    
+	retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaToSp, 
+				     abs_addr,
+				     remote,
+				     length,
+				     dir);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//================================================================
+
+#endif // _HVCALLEVENT_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallHpt.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallHpt.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallHpt.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallHpt.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,143 @@
+/*
+ * HvCallHpt.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//============================================================================
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from the OS.
+//
+//============================================================================
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include "HvCallSc.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+//-------------------------------------------------------------------
+// Other Includes
+//-------------------------------------------------------------------
+
+#ifndef _PPC_MMU_H
+#include <asm/mmu.h>
+#endif
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+#ifndef _HVCALLHPT_H
+#define _HVCALLHPT_H
+
+#define HvCallHptGetHptAddress		HvCallHpt +  0
+#define HvCallHptGetHptPages		HvCallHpt +  1
+#define HvCallHptSetPp			HvCallHpt +  5
+#define HvCallHptSetSwBits		HvCallHpt +  6
+#define HvCallHptUpdate			HvCallHpt +  7
+#define HvCallHptInvalidateNoSyncICache	HvCallHpt +  8
+#define HvCallHptGet			HvCallHpt + 11
+#define HvCallHptFindNextValid		HvCallHpt + 12
+#define HvCallHptFindValid		HvCallHpt + 13
+#define HvCallHptAddValidate		HvCallHpt + 16
+#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18
+
+
+//============================================================================
+static inline u64		HvCallHpt_getHptAddress(void)
+{
+	u64 retval = HvCall0(HvCallHptGetHptAddress);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retval;
+}
+//============================================================================
+static inline u64		HvCallHpt_getHptPages(void)
+{	
+	u64 retval = HvCall0(HvCallHptGetHptPages);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retval;
+}
+//=============================================================================
+static inline void		HvCallHpt_setPp(u32 hpteIndex, u8 value)
+{
+	HvCall2( HvCallHptSetPp, hpteIndex, value );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//=============================================================================
+static inline void		HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff )
+{
+	HvCall3( HvCallHptSetSwBits, hpteIndex, bitson, bitsoff );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//=============================================================================
+static inline void		HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
+						
+{
+	HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//=============================================================================
+static inline u64		HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, u8 bitsoff )
+						
+{
+	u64 compressedStatus;
+	compressedStatus = HvCall4( HvCallHptInvalidateSetSwBitsGet, hpteIndex, bitson, bitsoff, 1 );
+	HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return compressedStatus;
+}
+//=============================================================================
+static inline u64		HvCallHpt_findValid( struct _HPTE *hpte, u64 vpn )
+{
+	u64 retIndex = HvCall3Ret16( HvCallHptFindValid, hpte, vpn, 0, 0 );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retIndex;
+}
+//=============================================================================
+static inline u64		HvCallHpt_findNextValid( struct _HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff )
+{
+	u64 retIndex = HvCall3Ret16( HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retIndex;
+}
+//=============================================================================
+static inline void		HvCallHpt_get( struct _HPTE *hpte, u32 hpteIndex )
+{
+	HvCall2Ret16( HvCallHptGet, hpte, hpteIndex, 0 );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//============================================================================
+static inline void		HvCallHpt_addValidate( u32 hpteIndex,
+						       u32 hBit,
+						       struct _HPTE *hpte )
+						
+{
+	HvCall4( HvCallHptAddValidate, hpteIndex,
+		 hBit, (*((u64 *)hpte)), (*(((u64 *)hpte)+1)) );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+
+
+//=============================================================================
+
+#endif // _HVCALLHPT_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallPci.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallPci.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallPci.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallPci.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,697 @@
+/************************************************************************/
+/* Provides the Hypervisor PCI calls for iSeries Linux Parition.        */
+/* Copyright (C) 20yy  <Wayne G Holm> <IBM Corporation>                 */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, Jan 9, 2001                                               */
+/************************************************************************/
+//============================================================================
+//							 Header File Id
+// Name______________:	HvCallPci.H
+//
+// Description_______:
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from SLIC.
+//
+//============================================================================
+
+//-------------------------------------------------------------------
+// Forward declarations 
+//-------------------------------------------------------------------
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include "HvCallSc.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+//-------------------------------------------------------------------
+// Other Includes
+//-------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+#ifndef _HVCALLPCI_H
+#define _HVCALLPCI_H
+
+struct HvCallPci_DsaAddr { // make sure this struct size is 64-bits total
+	u16		busNumber;
+	u8		subBusNumber; 
+	u8		deviceId;     
+	u8		barNumber;
+	u8		reserved[3];
+};
+union HvDsaMap {
+	u64	DsaAddr;
+	struct HvCallPci_DsaAddr Dsa;
+};
+
+struct HvCallPci_LoadReturn {
+	u64		rc;
+	u64		value;
+};
+
+enum HvCallPci_DeviceType {HvCallPci_NodeDevice	= 1,
+                        HvCallPci_SpDevice	= 2,	
+                        HvCallPci_IopDevice     = 3,	
+                        HvCallPci_BridgeDevice	= 4,	
+                        HvCallPci_MultiFunctionDevice = 5,	
+                        HvCallPci_IoaDevice	= 6	
+};
+
+
+struct HvCallPci_DeviceInfo {
+	u32	deviceType;		// See DeviceType enum for values
+};
+    
+struct HvCallPci_BusUnitInfo {
+	u32	sizeReturned;		// length of data returned
+	u32	deviceType;		// see DeviceType enum for values
+};
+
+struct HvCallPci_BridgeInfo {
+	struct HvCallPci_BusUnitInfo busUnitInfo;  // Generic bus unit info
+	u8		subBusNumber;		// Bus number of secondary bus
+	u8		maxAgents;		// Max idsels on secondary bus
+        u8              maxSubBusNumber;        // Max Sub Bus
+	u8		logicalSlotNumber;	// Logical Slot Number for IOA 
+};
+    
+
+//  Maximum BusUnitInfo buffer size.  Provided for clients so they can allocate
+//  a buffer big enough for any type of bus unit.  Increase as needed.
+enum {HvCallPci_MaxBusUnitInfoSize = 128};
+
+struct HvCallPci_BarParms {
+	u64		vaddr;
+	u64		raddr;
+	u64		size;
+	u64		protectStart;
+	u64		protectEnd;
+	u64		relocationOffset;
+	u64		pciAddress;		
+	u64		reserved[3];
+};					
+
+enum HvCallPci_VpdType {
+	HvCallPci_BusVpd		= 1,
+	HvCallPci_BusAdapterVpd	= 2
+};
+
+#define HvCallPciConfigLoad8		HvCallPci + 0
+#define HvCallPciConfigLoad16		HvCallPci + 1
+#define HvCallPciConfigLoad32		HvCallPci + 2
+#define HvCallPciConfigStore8		HvCallPci + 3
+#define HvCallPciConfigStore16		HvCallPci + 4
+#define HvCallPciConfigStore32		HvCallPci + 5
+#define HvCallPciEoi			HvCallPci + 16
+#define HvCallPciGetBarParms		HvCallPci + 18
+#define HvCallPciMaskFisr		HvCallPci + 20
+#define HvCallPciUnmaskFisr		HvCallPci + 21
+#define HvCallPciSetSlotReset		HvCallPci + 25
+#define HvCallPciGetDeviceInfo		HvCallPci + 27
+#define HvCallPciGetCardVpd		HvCallPci + 28
+#define HvCallPciBarLoad8		HvCallPci + 40
+#define HvCallPciBarLoad16		HvCallPci + 41
+#define HvCallPciBarLoad32		HvCallPci + 42
+#define HvCallPciBarLoad64		HvCallPci + 43
+#define HvCallPciBarStore8		HvCallPci + 44
+#define HvCallPciBarStore16		HvCallPci + 45
+#define HvCallPciBarStore32		HvCallPci + 46
+#define HvCallPciBarStore64		HvCallPci + 47
+#define HvCallPciMaskInterrupts		HvCallPci + 48
+#define HvCallPciUnmaskInterrupts	HvCallPci + 49
+#define HvCallPciGetBusUnitInfo		HvCallPci + 50
+
+//============================================================================
+static inline u64	HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber,
+					      u8 deviceId, u32 offset,
+					      u8 *value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	HvCall3Ret16(HvCallPciConfigLoad8, &retVal, *(u64 *)&dsa, offset, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*value = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
+					      u8 deviceId, u32 offset,
+					      u16 *value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*value = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
+					      u8 deviceId, u32 offset,
+					      u32 *value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*value = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
+					      u8 deviceId, u32 offset,
+					      u8  value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	retVal = HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_configStore16(u16 busNumber, u8 subBusNumber,
+					      u8 deviceId, u32 offset,
+					      u16  value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	retVal = HvCall4(HvCallPciConfigStore16, *(u64 *)&dsa, offset, value, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_configStore32(u16 busNumber, u8 subBusNumber,
+					      u8 deviceId, u32 offset,
+					      u32  value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	retVal = HvCall4(HvCallPciConfigStore32, *(u64 *)&dsa, offset, value, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_barLoad8(u16	busNumberParm,
+					   u8		subBusParm,
+					   u8		deviceIdParm,
+					   u8		barNumberParm,
+					   u64		offsetParm,
+					   u8*		valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	HvCall3Ret16(HvCallPciBarLoad8, &retVal, *(u64 *)&dsa, offsetParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*valueParm = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_barLoad16(u16	busNumberParm,
+					   u8		subBusParm,
+					   u8		deviceIdParm,
+					   u8		barNumberParm,
+					   u64		offsetParm,
+					   u16*		valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	HvCall3Ret16(HvCallPciBarLoad16, &retVal, *(u64 *)&dsa, offsetParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*valueParm = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_barLoad32(u16	busNumberParm,
+					   u8		subBusParm,
+					   u8		deviceIdParm,
+					   u8		barNumberParm,
+					   u64		offsetParm,
+					   u32*		valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	HvCall3Ret16(HvCallPciBarLoad32, &retVal, *(u64 *)&dsa, offsetParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*valueParm = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_barLoad64(u16	busNumberParm,
+					   u8		subBusParm,
+					   u8		deviceIdParm,
+					   u8		barNumberParm,
+					   u64		offsetParm,
+					   u64*		valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;				
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	HvCall3Ret16(HvCallPciBarLoad64, &retVal, *(u64 *)&dsa, offsetParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	*valueParm = retVal.value;
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_barStore8(u16	busNumberParm,
+					    u8		subBusParm,
+					    u8		deviceIdParm,
+					    u8		barNumberParm,
+					    u64		offsetParm,
+					    u8		valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+				
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	retVal = HvCall4(HvCallPciBarStore8, *(u64 *)&dsa, offsetParm, valueParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_barStore16(u16	busNumberParm,
+					     u8		subBusParm,
+					     u8		deviceIdParm,
+					     u8		barNumberParm,
+					     u64	offsetParm,
+					     u16	valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+				
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	retVal = HvCall4(HvCallPciBarStore16, *(u64 *)&dsa, offsetParm, valueParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_barStore32(u16	busNumberParm,
+					     u8		subBusParm,
+					     u8		deviceIdParm,
+					     u8		barNumberParm,
+					     u64	offsetParm,
+					     u32	valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+				
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	retVal = HvCall4(HvCallPciBarStore32, *(u64 *)&dsa, offsetParm, valueParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_barStore64(u16	busNumberParm,
+					     u8		subBusParm,
+					     u8		deviceIdParm,
+					     u8		barNumberParm,
+					     u64	offsetParm,
+					     u64	valueParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+				
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	retVal = HvCall4(HvCallPciBarStore64, *(u64 *)&dsa, offsetParm, valueParm, 0);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_eoi(u16	busNumberParm,
+				      u8	subBusParm,  
+				      u8	deviceIdParm)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal.rc;
+}
+//============================================================================
+static inline u64	HvCallPci_getBarParms(u16	busNumberParm,
+					      u8	subBusParm,  
+					      u8	deviceIdParm,
+					      u8	barNumberParm,
+					      u64	parms,
+					      u32	sizeofParms)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+	dsa.barNumber = barNumberParm;
+
+	retVal = HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_maskFisr(u16	busNumberParm,
+					   u8	subBusParm,  
+					   u8	deviceIdParm,
+					   u64	fisrMask)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;		
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	retVal = HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_unmaskFisr(u16	busNumberParm,
+					     u8		subBusParm,  
+					     u8		deviceIdParm,
+					     u64	fisrMask)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;		
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	retVal = HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_setSlotReset(u16		busNumberParm,
+					       u8		subBusParm,
+					       u8		deviceIdParm,
+					       u64		onNotOff)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	retVal = HvCall2(HvCallPciSetSlotReset, *(u64*)&dsa, onNotOff);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_getDeviceInfo(u16	busNumberParm,
+						u8	subBusParm,  
+						u8	deviceNumberParm,
+						u64     parms,
+						u32	sizeofParms)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceNumberParm << 4;
+
+	retVal = HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_maskInterrupts(u16	busNumberParm,
+						 u8	subBusParm,  
+						 u8	deviceIdParm,
+						 u64	interruptMask)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;		
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	retVal = HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+static inline u64	HvCallPci_unmaskInterrupts(u16	busNumberParm,
+						 u8		subBusParm,  
+						 u8		deviceIdParm,
+						 u64		interruptMask)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;		
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	retVal = HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+
+static inline u64	HvCallPci_getBusUnitInfo(u16		busNumberParm,
+						 u8		subBusParm,  
+						 u8		deviceIdParm,
+						 u64            parms,
+						 u32		sizeofParms)
+{
+	struct HvCallPci_DsaAddr dsa;
+	u64 retVal;
+
+	*((u64*)&dsa) = 0;		
+
+	dsa.busNumber = busNumberParm;
+	dsa.subBusNumber = subBusParm;
+	dsa.deviceId = deviceIdParm;
+
+	retVal = HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, sizeofParms);
+
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+
+	return retVal;
+}
+//============================================================================
+
+static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, u16 sizeParm)
+{
+	int xRetSize;
+	u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusVpd);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	if (xRc == -1)
+		xRetSize = -1;
+	else
+		xRetSize = xRc & 0xFFFF;
+	return xRetSize;
+}
+//============================================================================
+
+static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, u16 sizeParm)
+{
+	int xRetSize;
+	u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusAdapterVpd);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	if (xRc == -1)
+		xRetSize = -1;
+	else
+		xRetSize = xRc & 0xFFFF;
+	return xRetSize;
+}
+//============================================================================
+#endif // _HVCALLPCI_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallSc.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallSc.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallSc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallSc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,53 @@
+/*
+ * HvCallSc.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+#ifndef _HVCALLSC_H
+#define _HVCALLSC_H
+
+#define HvCallBase		0x8000000000000000
+#define HvCallCfg		0x8002000000000000
+#define HvCallEvent		0x8003000000000000
+#define HvCallHpt		0x8004000000000000
+#define HvCallPci		0x8005000000000000
+#define HvCallSm		0x8007000000000000
+#define HvCallXm		0x8009000000000000
+
+u64 HvCall0( u64 );
+u64 HvCall1( u64, u64 );
+u64 HvCall2( u64, u64, u64 );
+u64 HvCall3( u64, u64, u64, u64 );
+u64 HvCall4( u64, u64, u64, u64, u64 );
+u64 HvCall5( u64, u64, u64, u64, u64, u64 );
+u64 HvCall6( u64, u64, u64, u64, u64, u64, u64 );
+u64 HvCall7( u64, u64, u64, u64, u64, u64, u64, u64 );
+
+u64 HvCall0Ret16( u64, void * );
+u64 HvCall1Ret16( u64, void *, u64 );
+u64 HvCall2Ret16( u64, void *, u64, u64 );
+u64 HvCall3Ret16( u64, void *, u64, u64, u64 );
+u64 HvCall4Ret16( u64, void *, u64, u64, u64, u64 );
+u64 HvCall5Ret16( u64, void *, u64, u64, u64, u64, u64 );
+u64 HvCall6Ret16( u64, void *, u64, u64, u64, u64, u64, u64 );
+u64 HvCall7Ret16( u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64 );
+
+#endif /* _HVCALLSC_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallSm.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallSm.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallSm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallSm.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,58 @@
+/*
+ * HvCallSm.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//============================================================================
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from the OS.
+//
+//============================================================================
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include "HvCallSc.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+#ifndef _HVCALLSM_H
+#define _HVCALLSM_H
+
+#define HvCallSmGet64BitsOfAccessMap	HvCallSm  + 11
+
+
+//============================================================================
+static inline u64		HvCallSm_get64BitsOfAccessMap(
+					HvLpIndex lpIndex, u64 indexIntoBitMap )
+{
+	u64 retval = HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex,
+			     indexIntoBitMap );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retval;
+}
+//============================================================================
+#endif // _HVCALLSM_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallXm.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallXm.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvCallXm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvCallXm.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,106 @@
+//============================================================================
+//							 Header File Id
+// Name______________:	HvCallXm.H
+//
+// Description_______:
+//
+//	This file contains the "hypervisor call" interface which is used to
+//	drive the hypervisor from SLIC.
+//
+//============================================================================
+
+//-------------------------------------------------------------------
+// Forward declarations 
+//-------------------------------------------------------------------
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef  _HVCALLSC_H
+#include "HvCallSc.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+//-------------------------------------------------------------------
+// Other Includes
+//-------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+#ifndef _HVCALLXM_H
+#define _HVCALLXM_H
+
+#define HvCallXmGetTceTableParms	HvCallXm +  0
+#define HvCallXmTestBus			HvCallXm +  1
+#define HvCallXmConnectBusUnit		HvCallXm +  2
+#define HvCallXmLoadTod			HvCallXm +  8
+#define HvCallXmTestBusUnit		HvCallXm +  9
+#define HvCallXmSetTce			HvCallXm + 11
+#define HvCallXmSetTces			HvCallXm + 13
+
+
+
+//============================================================================
+static inline void		HvCallXm_getTceTableParms(u64 cb)
+{
+	HvCall1(HvCallXmGetTceTableParms, cb);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+}
+//============================================================================
+static inline u64		HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce)
+{	
+	u64 retval = HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retval;
+}
+//============================================================================
+static inline u64		HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4)
+{	
+	u64 retval = HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces,
+			     tce1, tce2, tce3, tce4 );
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retval;
+}
+//=============================================================================
+static inline u64	HvCallXm_testBus(u16 busNumber)
+{
+	u64 retVal = HvCall1(HvCallXmTestBus, busNumber);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=====================================================================================
+static inline u64	HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId)
+{
+	u64 busUnitNumber = (subBusNumber << 8) | deviceId;
+	u64 retVal = HvCall2(HvCallXmTestBusUnit, busNumber, busUnitNumber);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=====================================================================================
+static inline u64	HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId,
+						u64 interruptToken)
+{
+	u64 busUnitNumber = (subBusNumber << 8) | deviceId;
+	u64 queueIndex = 0; // HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard));  
+
+	u64 retVal = HvCall5(HvCallXmConnectBusUnit, busNumber, busUnitNumber,
+			     interruptToken, 0, queueIndex);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=====================================================================================
+static inline u64	HvCallXm_loadTod(void)
+{
+	u64 retVal = HvCall0(HvCallXmLoadTod);
+	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
+	return retVal;
+}
+//=====================================================================================
+
+#endif // _HVCALLXM_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvLpConfig.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvLpConfig.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvLpConfig.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvLpConfig.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,292 @@
+/*
+ * HvLpConfig.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//===========================================================================
+//
+//      This file contains the interface to the LPAR configuration data
+//  to determine which resources should be allocated to each partition.
+//
+//===========================================================================
+
+#ifndef  _HVCALLCFG_H
+#include "HvCallCfg.h"
+#endif
+
+#ifndef  _HVTYPES_H
+#include <asm/iSeries/HvTypes.h>
+#endif
+
+#ifndef  _ITLPNACA_H
+#include <asm/iSeries/ItLpNaca.h>
+#endif
+
+#ifndef  _LPARDATA_H
+#include <asm/iSeries/LparData.h>
+#endif
+
+#ifndef _HVLPCONFIG_H
+#define _HVLPCONFIG_H
+
+//-------------------------------------------------------------------
+// Constants
+//-------------------------------------------------------------------
+
+extern HvLpIndex HvLpConfig_getLpIndex_outline(void);
+
+//===================================================================
+static inline HvLpIndex	HvLpConfig_getLpIndex(void)
+{
+	return itLpNaca.xLpIndex;
+}
+//===================================================================
+static inline HvLpIndex	HvLpConfig_getPrimaryLpIndex(void)
+{
+	return itLpNaca.xPrimaryLpIndex;
+}
+//=================================================================
+static inline HvLpIndex	HvLpConfig_getLps(void)
+{
+	return HvCallCfg_getLps();
+}
+//=================================================================
+static inline HvLpIndexMap	HvLpConfig_getActiveLpMap(void)
+{
+	return HvCallCfg_getActiveLpMap();
+}
+//=================================================================
+static inline u64		HvLpConfig_getSystemMsMegs(void)
+{
+	return HvCallCfg_getSystemMsChunks() / HVCHUNKSPERMEG;
+}
+//=================================================================
+static inline u64		HvLpConfig_getSystemMsChunks(void)
+{
+	return HvCallCfg_getSystemMsChunks();
+}
+//=================================================================
+static inline u64		HvLpConfig_getSystemMsPages(void)
+{
+	return HvCallCfg_getSystemMsChunks() * HVPAGESPERCHUNK;
+}
+//================================================================
+static inline u64		HvLpConfig_getMsMegs(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur) / HVCHUNKSPERMEG;
+}
+//================================================================
+static inline u64		HvLpConfig_getMsChunks(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur);
+}
+//================================================================
+static inline u64		HvLpConfig_getMsPages(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur) * HVPAGESPERCHUNK;
+}
+//================================================================
+static inline u64		HvLpConfig_getMinMsMegs(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min) / HVCHUNKSPERMEG;
+}
+//================================================================
+static inline u64		HvLpConfig_getMinMsChunks(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min);
+}
+//================================================================
+static inline u64		HvLpConfig_getMinMsPages(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min) * HVPAGESPERCHUNK;
+}
+//================================================================
+static inline u64		HvLpConfig_getMinRuntimeMsMegs(void)
+{
+	return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) / HVCHUNKSPERMEG;
+}
+//===============================================================
+static inline u64		HvLpConfig_getMinRuntimeMsChunks(void)
+{
+	return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex());
+}
+//===============================================================
+static inline u64		HvLpConfig_getMinRuntimeMsPages(void)
+{
+	return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) * HVPAGESPERCHUNK;
+}
+//===============================================================
+static inline u64		HvLpConfig_getMaxMsMegs(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max) / HVCHUNKSPERMEG;
+}
+//===============================================================
+static inline u64		HvLpConfig_getMaxMsChunks(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMaxMsPages(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max) * HVPAGESPERCHUNK;
+}
+//===============================================================
+static inline u64		HvLpConfig_getInitMsMegs(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init) / HVCHUNKSPERMEG;
+}
+//===============================================================
+static inline u64		HvLpConfig_getInitMsChunks(void)
+{
+	return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init);
+}
+//===============================================================
+static inline u64		HvLpConfig_getInitMsPages(void)
+{    return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init) * HVPAGESPERCHUNK;
+}
+//===============================================================
+static inline u64		HvLpConfig_getSystemPhysicalProcessors(void)
+{
+	return HvCallCfg_getSystemPhysicalProcessors();
+}
+//===============================================================
+static inline u64		HvLpConfig_getSystemLogicalProcessors(void)
+{
+	return HvCallCfg_getSystemPhysicalProcessors() * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
+}
+//===============================================================
+static inline u64		HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
+{
+	return HvCallCfg_getNumProcsInSharedPool(sPI);
+}
+//===============================================================
+static inline u64		HvLpConfig_getPhysicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Cur);
+}
+//===============================================================
+static inline u64		HvLpConfig_getLogicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Cur) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
+}
+//===============================================================
+static inline HvLpSharedPoolIndex	HvLpConfig_getSharedPoolIndex(void)
+{
+	return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex());
+}
+//===============================================================
+static inline u64		HvLpConfig_getSharedProcUnits(void)
+{
+	return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Cur);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMinSharedProcUnits(void)
+{
+	return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Min);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMaxSharedProcUnits(void)
+{
+	return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Max);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMinPhysicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Min);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMinLogicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Min) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMaxPhysicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Max);
+}
+//===============================================================
+static inline u64		HvLpConfig_getMaxLogicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Max) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
+}
+//===============================================================
+static inline u64		HvLpConfig_getInitPhysicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Init);
+}
+//===============================================================
+static inline u64		HvLpConfig_getInitLogicalProcessors(void)
+{
+	return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Init) * (/*getPaca()->getSecondaryThreadCount() +*/ 1);
+}
+//================================================================
+static inline HvLpVirtualLanIndexMap	HvLpConfig_getVirtualLanIndexMap(void)
+{
+	return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline());
+}
+//===============================================================
+static inline HvLpVirtualLanIndexMap	HvLpConfig_getVirtualLanIndexMapForLp(HvLpIndex lp)
+{
+	return HvCallCfg_getVirtualLanIndexMap(lp);
+}
+//================================================================
+static inline HvLpIndex	HvLpConfig_getBusOwner(HvBusNumber busNumber)
+{
+	return HvCallCfg_getBusOwner(busNumber);
+}
+//===============================================================
+static inline int		HvLpConfig_isBusDedicated(HvBusNumber busNumber)
+{
+	return HvCallCfg_isBusDedicated(busNumber);
+}
+//================================================================
+static inline HvLpIndexMap	HvLpConfig_getBusAllocation(HvBusNumber busNumber)
+{
+	return HvCallCfg_getBusAllocation(busNumber);
+}
+//================================================================
+// returns the absolute real address of the load area
+static inline u64		HvLpConfig_getLoadAddress(void)
+{
+	return itLpNaca.xLoadAreaAddr & 0x7fffffffffffffff;
+}
+//================================================================
+static inline u64		HvLpConfig_getLoadPages(void)
+{
+	return itLpNaca.xLoadAreaChunks * HVPAGESPERCHUNK;
+}
+//================================================================
+static inline int		HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber)
+{
+	HvLpIndex busOwner = HvLpConfig_getBusOwner(busNumber);
+	return (busOwner == HvLpConfig_getLpIndex());
+}
+//================================================================
+static inline int         HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2)
+{
+	HvLpVirtualLanIndexMap virtualLanIndexMap1 = HvCallCfg_getVirtualLanIndexMap( lp1 );
+	HvLpVirtualLanIndexMap virtualLanIndexMap2 = HvCallCfg_getVirtualLanIndexMap( lp2 );
+	return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0);
+}
+//================================================================
+static inline HvLpIndex		HvLpConfig_getHostingLpIndex(HvLpIndex lp)
+{
+	return HvCallCfg_getHostingLpIndex(lp);
+}
+//================================================================
+
+#endif // _HVLPCONFIG_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvLpEvent.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvLpEvent.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvLpEvent.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvLpEvent.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,144 @@
+/*
+ * HvLpEvent.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//======================================================================
+//
+//	This file contains the class for HV events in the system.
+//
+//=====================================================================
+#ifndef _HVLPEVENT_H
+#define _HVLPEVENT_H
+
+#include <asm/types.h>
+#include <asm/ptrace.h>
+#include <asm/iSeries/HvTypes.h>
+#ifndef _HVCALLEVENT_H
+#include <asm/iSeries/HvCallEvent.h>
+#endif
+
+
+//=====================================================================
+//
+// HvLpEvent is the structure for Lp Event messages passed between
+// partitions through PLIC. 
+//
+//=====================================================================
+
+struct HvEventFlags
+{
+	u8	xValid:1;		// Indicates a valid request	x00-x00
+	u8	xRsvd1:4;		// Reserved			...
+	u8	xAckType:1;		// Immediate or deferred	...
+	u8	xAckInd:1;		// Indicates if ACK required	...
+	u8	xFunction:1;		// Interrupt or Acknowledge	...
+};
+
+
+struct HvLpEvent
+{
+	struct HvEventFlags xFlags;	// Event flags			x00-x00
+	u8	xType;			// Type of message		x01-x01
+	u16	xSubtype;		// Subtype for event		x02-x03
+	u8	xSourceLp;		// Source LP			x04-x04
+	u8	xTargetLp;		// Target LP			x05-x05
+	u8	xSizeMinus1;		// Size of Derived class - 1	x06-x06
+	u8	xRc;			// RC for Ack flows		x07-x07
+	u16	xSourceInstanceId;	// Source sides instance id	x08-x09
+	u16	xTargetInstanceId;	// Target sides instance id	x0A-x0B
+	union {
+		u32	xSubtypeData;	// Data usable by the subtype	x0C-x0F
+		u16	xSubtypeDataShort[2];	// Data as 2 shorts
+		u8	xSubtypeDataChar[4];	// Data as 4 chars
+	} x;
+
+	u64	xCorrelationToken;	// Unique value for source/type x10-x17
+};
+
+// Lp Event handler function
+typedef void (*LpEventHandler)(struct HvLpEvent *, struct pt_regs *);
+
+// Register a handler for an event type
+//  returns 0 on success
+extern int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler hdlr);
+
+// Unregister a handler for an event type
+//  returns 0 on success
+//  Unregister will fail if there are any paths open for the type
+extern int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType );
+
+// Open an Lp Event Path for an event type
+//  returns 0 on success
+//  openPath will fail if there is no handler registered for the event type.
+//  The lpIndex specified is the partition index for the target partition
+//  (for VirtualIo, VirtualLan and SessionMgr) other types specify zero) 
+extern int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex );
+
+
+// Close an Lp Event Path for a type and partition
+//  returns 0 on sucess
+extern int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex );
+
+#define HvLpEvent_Type_Hypervisor 0
+#define HvLpEvent_Type_MachineFac 1
+#define HvLpEvent_Type_SessionMgr 2
+#define HvLpEvent_Type_SpdIo      3
+#define HvLpEvent_Type_VirtualBus 4
+#define HvLpEvent_Type_PciIo      5
+#define HvLpEvent_Type_RioIo      6
+#define HvLpEvent_Type_VirtualLan 7
+#define HvLpEvent_Type_VirtualIo  8
+#define HvLpEvent_Type_NumTypes   9
+
+#define HvLpEvent_Rc_Good 0
+#define HvLpEvent_Rc_BufferNotAvailable 1
+#define HvLpEvent_Rc_Cancelled 2
+#define HvLpEvent_Rc_GenericError 3
+#define HvLpEvent_Rc_InvalidAddress 4
+#define HvLpEvent_Rc_InvalidPartition 5
+#define HvLpEvent_Rc_InvalidSize 6
+#define HvLpEvent_Rc_InvalidSubtype 7
+#define HvLpEvent_Rc_InvalidSubtypeData 8
+#define HvLpEvent_Rc_InvalidType 9
+#define HvLpEvent_Rc_PartitionDead 10
+#define HvLpEvent_Rc_PathClosed 11
+#define HvLpEvent_Rc_SubtypeError 12
+
+#define HvLpEvent_Function_Ack 0
+#define HvLpEvent_Function_Int 1
+
+#define HvLpEvent_AckInd_NoAck 0
+#define HvLpEvent_AckInd_DoAck 1
+
+#define HvLpEvent_AckType_ImmediateAck 0
+#define HvLpEvent_AckType_DeferredAck 1
+
+#define HvLpDma_Direction_LocalToRemote 0
+#define HvLpDma_Direction_RemoteToLocal 1
+
+#define HvLpDma_AddressType_TceIndex 0
+#define HvLpDma_AddressType_RealAddress 1
+
+#define HvLpDma_Rc_Good 0
+#define HvLpDma_Rc_Error 1
+#define HvLpDma_Rc_PartitionDead 2
+#define HvLpDma_Rc_PathClosed 3
+#define HvLpDma_Rc_InvalidAddress 4
+#define HvLpDma_Rc_InvalidLength 5
+
+#endif // _HVLPEVENT_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvReleaseData.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvReleaseData.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvReleaseData.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvReleaseData.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,70 @@
+/*
+ * HvReleaseData.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=============================================================================
+//
+//   This control block contains the critical information about the 
+//   release so that it can be changed in the future (ie, the virtual 
+//   address of the OS's NACA).
+//
+//-----------------------------------------------------------------------------
+// Standard Includes
+//-----------------------------------------------------------------------------
+#ifndef	_PPC64_TYPES_H
+#include	<asm/types.h>
+#endif
+
+#ifndef _HVRELEASEDATA_H
+#define _HVRELEASEDATA_H
+
+//=============================================================================
+//
+//	When we IPL a secondary partition, we will check if if the 
+//	secondary xMinPlicVrmIndex > the primary xVrmIndex.  
+//	If it is then this tells PLIC that this secondary is not 
+//	supported running on this "old" of a level of PLIC.
+//
+//	Likewise, we will compare the primary xMinSlicVrmIndex to 
+//	the secondary xVrmIndex. 
+//	If the primary xMinSlicVrmDelta > secondary xVrmDelta then we 
+//	know that this PLIC does not support running an OS "that old".
+//
+//=============================================================================
+
+struct	HvReleaseData
+{
+	u32	xDesc;			// Descriptor	"HvRD" ebcdic	x00-x03
+	u16	xSize;			// Size of this control block	x04-x05
+	u16	xVpdAreasPtrOffset;	// Offset in NACA of ItVpdAreas	x06-x07
+	struct Naca * xSlicNacaAddr;	// Virtual address of SLIC NACA x08-x0F
+	u32	xMsNucDataOffset;	// Offset of Linux Mapping Data x10-x13
+	u32	xRsvd1;			// Reserved			x14-x17
+	u16	xTagsMode:1;		// 0 == tags active, 1 == tags inactive
+	u16	xAddressSize:1;		// 0 == 64-bit, 1 == 32-bit
+	u16	xNoSharedProcs:1;	// 0 == shared procs, 1 == no shared
+	u16	xNoHMT:1;		// 0 == allow HMT, 1 == no HMT
+	u16	xRsvd2:12;		// Reserved			x18-x19
+	u16	xVrmIndex;		// VRM Index of OS image	x1A-x1B
+	u16	xMinSupportedPlicVrmIndex;// Min PLIC level  (soft)	x1C-x1D
+	u16	xMinCompatablePlicVrmIndex;// Min PLIC levelP (hard)	x1E-x1F
+	char	xVrmName[12];		// Displayable name  		x20-x2B
+	char	xRsvd3[20];		// Reserved			x2C-x3F
+};
+
+#endif // _HVRELEASEDATA_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvTypes.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvTypes.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/HvTypes.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/HvTypes.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,127 @@
+/*
+ * HvTypes.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//===========================================================================
+//                                                             Header File Id
+// Name______________:  HvTypes.H
+//
+// Description_______:
+//
+//	General typedefs for the hypervisor.
+//
+// Declared Class(es):
+//
+//===========================================================================
+
+#ifndef _PPC_TYPES_H
+#include        <asm/types.h>
+#endif
+
+
+#ifndef _HVTYPES_H
+#define _HVTYPES_H
+
+//-------------------------------------------------------------------
+// Typedefs
+//-------------------------------------------------------------------
+typedef u8	HvLpIndex;
+typedef u16	HvLpInstanceId;
+typedef u64     HvLpTOD;
+typedef u64     HvLpSystemSerialNum;
+typedef u8      HvLpDeviceSerialNum[12];
+typedef u16     HvLpSanHwSet;
+typedef u16     HvLpBus;
+typedef u16     HvLpBoard;
+typedef u16     HvLpCard;
+typedef u8      HvLpDeviceType[4];
+typedef u8      HvLpDeviceModel[3];
+typedef u64     HvIoToken;
+typedef u8      HvLpName[8];
+typedef u32	HvIoId;
+typedef u64	HvRealMemoryIndex;
+typedef u32     HvLpIndexMap;		// Must hold HvMaxArchitectedLps bits!!!
+typedef u16	HvLpVrmIndex;
+typedef u32	HvXmGenerationId;
+typedef u8	HvLpBusPool;			
+typedef u8	HvLpSharedPoolIndex;		
+typedef u16	HvLpSharedProcUnitsX100;
+typedef u8	HvLpVirtualLanIndex;
+typedef u16	HvLpVirtualLanIndexMap;	// Must hold HvMaxArchitectedVirtualLans bits!!!
+typedef u16	HvBusNumber;		// Hypervisor Bus Number
+typedef u8	HvSubBusNumber;		// Hypervisor SubBus Number
+typedef u8	HvAgentId;		// Hypervisor DevFn
+
+
+#define HVMAXARCHITECTEDLPS 32
+#define HVCHUNKSIZE 256 * 1024
+#define HVPAGESIZE 4 * 1024
+#define HVLPMINMEGSPRIMARY 256
+#define HVLPMINMEGSSECONDARY 64
+#define HVCHUNKSPERMEG 4
+#define HVPAGESPERMEG 256
+#define HVPAGESPERCHUNK 64
+ 
+#define HvMaxArchitectedLps 		((HvLpIndex)HVMAXARCHITECTEDLPS)
+#define HvMaxArchitectedVirtualLans	((HvLpVirtualLanIndex)16)
+#define HvLpIndexInvalid		((HvLpIndex)0xff)
+
+//--------------------------------------------------------------------
+// Enums for the sub-components under PLIC
+// Used in HvCall  and HvPrimaryCall
+//--------------------------------------------------------------------
+enum   HvCallCompIds
+{
+	HvCallCompId = 0,
+	HvCallCpuCtlsCompId = 1,
+	HvCallCfgCompId = 2,
+	HvCallEventCompId = 3,
+	HvCallHptCompId = 4,
+	HvCallPciCompId = 5,
+	HvCallSlmCompId = 6,
+	HvCallSmCompId = 7,
+	HvCallSpdCompId = 8,
+	HvCallXmCompId = 9,
+	HvCallRioCompId = 10, 
+	HvCallRsvd3CompId = 11,
+	HvCallRsvd2CompId = 12,
+	HvCallRsvd1CompId = 13,
+	HvCallMaxCompId = 14,
+	HvPrimaryCallCompId = 0,    
+	HvPrimaryCallCfgCompId = 1,
+	HvPrimaryCallPciCompId = 2,    
+	HvPrimaryCallSmCompId = 3,
+	HvPrimaryCallSpdCompId = 4,
+	HvPrimaryCallXmCompId = 5,
+	HvPrimaryCallRioCompId = 6, 
+	HvPrimaryCallRsvd7CompId = 7,
+	HvPrimaryCallRsvd6CompId = 8,
+	HvPrimaryCallRsvd5CompId = 9,
+	HvPrimaryCallRsvd4CompId = 10,
+	HvPrimaryCallRsvd3CompId = 11,
+	HvPrimaryCallRsvd2CompId = 12,
+	HvPrimaryCallRsvd1CompId = 13,
+	HvPrimaryCallMaxCompId = HvCallMaxCompId     
+};
+
+struct HvLpBufferList {
+	u64 addr;
+	u64 len;
+};
+
+#endif // _HVTYPES_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/IoHriMainStore.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/IoHriMainStore.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/IoHriMainStore.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/IoHriMainStore.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,167 @@
+/*
+ * IoHriMainStore.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _IOHRIMAINSTORE_H
+#define _IOHRIMAINSTORE_H
+
+/* Main Store Vpd for Condor,iStar,sStar */
+struct IoHriMainStoreSegment4 {    
+	u8	msArea0Exists:1;
+	u8	msArea1Exists:1;
+	u8	msArea2Exists:1;
+	u8	msArea3Exists:1;
+	u8	reserved1:4;
+	u8	reserved2;
+
+	u8	msArea0Functional:1;
+	u8	msArea1Functional:1;
+	u8	msArea2Functional:1;
+	u8	msArea3Functional:1;
+	u8	reserved3:4;
+	u8	reserved4;
+
+	u32	totalMainStore;
+
+	u64	msArea0Ptr;
+	u64	msArea1Ptr;
+	u64	msArea2Ptr;
+	u64	msArea3Ptr;
+
+	u32	cardProductionLevel;
+
+	u32	msAdrHole;
+
+	u8	msArea0HasRiserVpd:1;
+	u8	msArea1HasRiserVpd:1;
+	u8	msArea2HasRiserVpd:1;
+	u8	msArea3HasRiserVpd:1;
+	u8	reserved5:4;	
+	u8	reserved6;
+	u16	reserved7;
+
+	u8	reserved8[28];
+
+	u64	nonInterleavedBlocksStartAdr;
+	u64	nonInterleavedBlocksEndAdr;
+};
+
+/* Main Store VPD for Power4 */
+struct IoHriMainStoreChipInfo1 {
+	u32	chipMfgID	__attribute((packed));
+	char	chipECLevel[4]	__attribute((packed));
+};
+
+struct IoHriMainStoreVpdIdData {
+	char	typeNumber[4];
+	char	modelNumber[4];
+	char	partNumber[12];
+	char	serialNumber[12];
+};
+
+struct IoHriMainStoreVpdFruData {
+	char	fruLabel[8]	__attribute((packed));
+	u8	numberOfSlots	__attribute((packed));
+	u8	pluggingType	__attribute((packed));
+	u16	slotMapIndex	__attribute((packed));
+};
+
+struct IoHriMainStoreAdrRangeBlock {
+	void *	blockStart      __attribute((packed));
+	void *	blockEnd        __attribute((packed));
+	u32	blockProcChipId __attribute((packed));
+};
+
+#define MaxAreaAdrRangeBlocks 4
+
+struct IoHriMainStoreArea4 {
+	u32	msVpdFormat			__attribute((packed));
+	u8	containedVpdType		__attribute((packed));
+	u8	reserved1			__attribute((packed));
+	u16	reserved2			__attribute((packed));
+
+	u64	msExists			__attribute((packed));
+	u64	msFunctional			__attribute((packed));
+
+	u32	memorySize			__attribute((packed));
+	u32	procNodeId			__attribute((packed));
+
+	u32	numAdrRangeBlocks		__attribute((packed));
+	struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks] __attribute((packed));
+
+	struct IoHriMainStoreChipInfo1	chipInfo0	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo1	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo2	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo3	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo4	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo5	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo6	__attribute((packed));
+	struct IoHriMainStoreChipInfo1	chipInfo7	__attribute((packed));
+
+	void *   msRamAreaArray			__attribute((packed));
+	u32	msRamAreaArrayNumEntries	__attribute((packed));
+	u32	msRamAreaArrayEntrySize		__attribute((packed));
+
+	u32	numaDimmExists			__attribute((packed));
+	u32	numaDimmFunctional		__attribute((packed));
+	void *	numaDimmArray			__attribute((packed));
+	u32	numaDimmArrayNumEntries		__attribute((packed));
+	u32	numaDimmArrayEntrySize		__attribute((packed));
+
+	struct IoHriMainStoreVpdIdData  idData	__attribute((packed));
+
+	u64	powerData			__attribute((packed));
+	u64	cardAssemblyPartNum		__attribute((packed));
+	u64	chipSerialNum			__attribute((packed));
+
+	u64	reserved3			__attribute((packed));
+	char	reserved4[16]			__attribute((packed));
+
+	struct IoHriMainStoreVpdFruData fruData	__attribute((packed));
+
+	u8	vpdPortNum			__attribute((packed));
+	u8	reserved5			__attribute((packed));
+	u8	frameId				__attribute((packed));
+	u8	rackUnit			__attribute((packed));
+	char	asciiKeywordVpd[256]		__attribute((packed));
+	u32	reserved6			__attribute((packed));
+};
+
+
+struct IoHriMainStoreSegment5 {    
+	u16	reserved1;
+	u8	reserved2;
+	u8	msVpdFormat;
+
+	u32	totalMainStore;
+	u64	maxConfiguredMsAdr;
+
+	struct IoHriMainStoreArea4*	msAreaArray;
+	u32	msAreaArrayNumEntries;
+	u32	msAreaArrayEntrySize;
+
+	u32	msAreaExists;    
+	u32	msAreaFunctional;
+
+	u64	reserved3;
+};
+
+
+
+#endif // _IOHRIMAINSTORE_H
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/IoHriProcessorVpd.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/IoHriProcessorVpd.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/IoHriProcessorVpd.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/IoHriProcessorVpd.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,90 @@
+/*
+ * IoHriProcessorVpd.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//===================================================================
+//
+//	This struct maps Processor Vpd that is DMAd to SLIC by CSP 
+//
+
+#ifndef	_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifndef _IOHRIPROCESSORVPD_H
+#define _IOHRIPROCESSORVPD_H
+
+struct IoHriProcessorVpd
+{
+
+	u8	xFormat;		// VPD format indicator		x00-x00
+	u8	xProcStatus:8;		// Processor State		x01-x01
+	u8	xSecondaryThreadCount;	// Secondary thread cnt		x02-x02
+	u8	xSrcType:1;		// Src Type			x03-x03
+	u8	xSrcSoft:1;		// Src stay soft		...
+	u8	xSrcParable:1;		// Src parable			...
+	u8	xRsvd1:5;		// Reserved			...
+	u16	xHvPhysicalProcIndex;	// Hypervisor physical proc index04-x05
+	u16	xRsvd2;			// Reserved			x06-x07
+	u32	xHwNodeId;		// Hardware node id		x08-x0B
+	u32	xHwProcId;		// Hardware processor id	x0C-x0F
+	
+	u32	xTypeNum;		// Card Type/CCIN number	x10-x13
+	u32	xModelNum;		// Model/Feature number		x14-x17
+	u64	xSerialNum;		// Serial number		x18-x1F
+	char xPartNum[12];		// Book Part or FPU number	x20-x2B
+	char xMfgID[4];			// Manufacturing ID		x2C-x2F
+
+	u32	xProcFreq;		// Processor Frequency		x30-x33
+	u32	xTimeBaseFreq;		// Time Base Frequency		x34-x37
+
+	u32	xChipEcLevel;		// Chip EC Levels		x38-x3B
+	u32	xProcIdReg;		// PIR SPR value		x3C-x3F
+	u32	xPVR;			// PVR value			x40-x43
+	u8	xRsvd3[12];		// Reserved			x44-x4F
+
+	u32	xInstCacheSize;		// Instruction cache size in KB	x50-x53
+	u32	xInstBlockSize;		// Instruction cache block size	x54-x57
+	u32	xDataCacheOperandSize;	// Data cache operand size	x58-x5B
+	u32	xInstCacheOperandSize;	// Inst cache operand size	x5C-x5F
+
+	u32	xDataL1CacheSizeKB;	// L1 data cache size in KB	x60-x63
+	u32	xDataL1CacheLineSize;	// L1 data cache block size	x64-x67
+	u64	xRsvd4;			// Reserved			x68-x6F
+
+	u32	xDataL2CacheSizeKB;	// L2 data cache size in KB	x70-x73
+	u32	xDataL2CacheLineSize;	// L2 data cache block size	x74-x77
+	u64	xRsvd5;			// Reserved			x78-x7F
+
+	u32	xDataL3CacheSizeKB;	// L3 data cache size in KB	x80-x83
+	u32	xDataL3CacheLineSize;	// L3 data cache block size	x84-x87
+	u64	xRsvd6;			// Reserved			x88-x8F
+   
+	u64	xFruLabel;		// Card Location Label		x90-x97
+	u8	xSlotsOnCard;		// Slots on card (0=no slots)	x98-x98
+	u8	xPartLocFlag;		// Location flag (0-pluggable 1-imbedded) x99-x99
+	u16	xSlotMapIndex;		// Index in slot map table	x9A-x9B
+	u8	xSmartCardPortNo;	// Smart card port number	x9C-x9C
+	u8	xRsvd7;			// Reserved			x9D-x9D
+	u16	xFrameIdAndRackUnit;	// Frame ID and rack unit adr	x9E-x9F
+    
+	u8	xRsvd8[24];		// Reserved			xA0-xB7
+
+	char xProcSrc[72];		// CSP format SRC		xB8-xFF
+};
+#endif // _IOHRIPROCESSORVPD_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItIplParmsReal.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItIplParmsReal.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItIplParmsReal.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItIplParmsReal.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,78 @@
+/*
+ * ItIplParmsReal.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//==============================================================================
+//
+//	This struct maps the IPL Parameters DMA'd from the SP.                  
+//
+// Warning:
+//	This data must map in exactly 64 bytes and match the architecture for
+//	the IPL parms
+//
+//=============================================================================
+
+
+//-------------------------------------------------------------------
+// Standard Includes
+//-------------------------------------------------------------------
+#ifndef	_PPC_TYPES_H
+#include	<asm/types.h>
+#endif
+
+#ifndef _ITIPLPARMSREAL_H
+#define _ITIPLPARMSREAL_H
+
+struct ItIplParmsReal
+{
+	u8	xFormat;		// Defines format of IplParms		x00-x00
+	u8	xRsvd01:6;		// Reserved				x01-x01
+	u8	xAlternateSearch:1;	// Alternate search indicator		...
+	u8	xUaSupplied:1;		// UA Supplied on programmed IPL	...
+	u8	xLsUaFormat;		// Format byte for UA			x02-x02
+	u8	xRsvd02;		// Reserved				x03-x03
+	u32	xLsUa;			// LS UA				x04-x07
+	u32	xUnusedLsLid;		// First OS LID to load			x08-x0B
+	u16	xLsBusNumber;		// LS Bus Number			x0C-x0D
+	u8	xLsCardAdr;		// LS Card Address			x0E-x0E
+	u8	xLsBoardAdr;		// LS Board Address			x0F-x0F
+	u32	xRsvd03;		// Reserved				x10-x13
+	u8	xSpcnPresent:1;		// SPCN present				x14-x14
+	u8	xCpmPresent:1;		// CPM present				...
+	u8	xRsvd04:6;		// Reserved				...
+	u8	xRsvd05:4;		// Reserved				x15-x15
+	u8	xKeyLock:4;		// Keylock setting			...
+	u8	xRsvd06:6;		// Reserved				x16-x16
+	u8	xIplMode:2;		// Ipl mode (A|B|C|D)			...
+	u8	xHwIplType;		// Fast v slow v slow EC HW IPL		x17-x17
+	u16	xCpmEnabledIpl:1;	// CPM in effect when IPL initiated	x18-x19
+	u16	xPowerOnResetIpl:1;	// Indicate POR condition		...
+	u16	xMainStorePreserved:1;	// Main Storage is preserved		...
+	u16	xRsvd07:13;		// Reserved				...
+	u16	xIplSource:16;		// Ipl source				x1A-x1B
+	u8	xIplReason:8;		// Reason for this IPL			x1C-x1C
+	u8	xRsvd08;		// Reserved				x1D-x1D
+	u16	xRsvd09;		// Reserved				x1E-x1F
+	u16	xSysBoxType;		// System Box Type			x20-x21
+	u16	xSysProcType;		// System Processor Type		x22-x23
+	u32	xRsvd10;		// Reserved				x24-x27
+	u64	xRsvd11;		// Reserved				x28-x2F
+	u64	xRsvd12;		// Reserved				x30-x37
+	u64	xRsvd13;		// Reserved				x38-x3F
+};
+#endif // _ITIPLPARMSREAL_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpNaca.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpNaca.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpNaca.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpNaca.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,90 @@
+/*
+ * ItLpNaca.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=============================================================================
+//
+//	This control block contains the data that is shared between the
+//	hypervisor (PLIC) and the OS.
+//
+//=============================================================================
+
+
+#ifndef _ITLPNACA_H
+#define _ITLPNACA_H
+
+struct ItLpNaca
+{
+//=============================================================================
+// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
+//=============================================================================
+	u32	xDesc;			// Eye catcher			x00-x03
+	u16	xSize;			// Size of this class		x04-x05
+	u16	xIntHdlrOffset;		// Offset to IntHdlr array	x06-x07
+	u8	xMaxIntHdlrEntries;	// Number of entries in array	x08-x08
+	u8	xPrimaryLpIndex;	// LP Index of Primary		x09-x09
+	u8	xServiceLpIndex;	// LP Ind of Service Focal Pointx0A-x0A
+	u8	xLpIndex;		// LP Index			x0B-x0B
+	u16	xMaxLpQueues;		// Number of allocated queues	x0C-x0D
+	u16	xLpQueueOffset;		// Offset to start of LP queues	x0E-x0F
+	u8	xPirEnvironMode:8;	// Piranha or hardware		x10-x10
+	u8	xPirConsoleMode:8;	// Piranha console indicator	x11-x11
+	u8	xPirDasdMode:8;		// Piranha dasd indicator	x12-x12
+	u8	xRsvd1_0[5];		// Reserved for Piranha related	x13-x17
+	u8	xLparInstalled:1;	// Is LPAR installed on system	x18-x1F
+	u8	xSysPartitioned:1;	// Is the system partitioned	...
+	u8	xHwSyncedTBs:1;		// Hardware synced TBs		...
+	u8	xIntProcUtilHmt:1;	// Utilize HMT for interrupts	...
+	u8	xRsvd1_1:4;		// Reserved			...
+	u8	xSpVpdFormat:8;		// VPD areas are in CSP format	...
+	u8	xIntProcRatio:8;	// Ratio of int procs to procs	...
+	u8	xRsvd1_2[5];		// Reserved			...
+	u16	xRsvd1_3;		// Reserved			x20-x21
+	u16	xPlicVrmIndex;		// VRM index of PLIC		x22-x23
+	u16	xMinSupportedSlicVrmInd;// Min supported OS VRM index	x24-x25
+	u16	xMinCompatableSlicVrmInd;// Min compatable OS VRM index x26-x27
+	u64	xLoadAreaAddr;		// ER address of load area	x28-x2F
+	u32	xLoadAreaChunks;	// Chunks for the load area	x30-x33
+	u32	xPaseSysCallCRMask;	// Mask used to test CR before  x34-x37
+	// doing an ASR switch on PASE
+	// system call.
+	u64	xSlicSegmentTablePtr;   // Pointer to Slic seg table.   x38-x3f
+	u8	xRsvd1_4[64];		//         			x40-x7F 
+   
+//=============================================================================
+// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
+//=============================================================================
+	u8	xRsvd2_0[128];		// Reserved			x00-x7F
+
+//=============================================================================
+// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
+// NB: Padding required to keep xInterrruptHdlr at x300 which is required 
+// for v4r4 PLIC.
+//=============================================================================
+	u8	xOldLpQueue[128];	// LP Queue needed for v4r4	100-17F
+	u8	xRsvd3_0[384];		// Reserved			180-2FF
+//=============================================================================
+// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
+//  handlers
+//=============================================================================
+	u64	xInterruptHdlr[32];	// Interrupt handlers		300-x3FF
+};
+
+//=============================================================================
+
+#endif // _ITLPNACA_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpPaca.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpPaca.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpPaca.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpPaca.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,134 @@
+/*
+ * ItLpPaca.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=============================================================================
+//                                   
+//	This control block contains the data that is shared between the 
+//	hypervisor (PLIC) and the OS.
+//    
+//
+//----------------------------------------------------------------------------
+#ifndef  _PPC_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifndef _ITLPPACA_H
+#define _ITLPPACA_H
+
+
+struct ItLpPaca
+{
+//=============================================================================
+// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
+// NOTE: The xDynXyz fields are fields that will be dynamically changed by 
+// PLIC when preparing to bring a processor online or when dispatching a 
+// virtual processor!
+//=============================================================================
+	u32	xDesc;			// Eye catcher 0xD397D781	x00-x03
+	u16	xSize;			// Size of this struct		x04-x05
+	u16	xRsvd1_0;		// Reserved			x06-x07
+	u16	xRsvd1_1:14;		// Reserved			x08-x09
+	u8	xSharedProc:1;		// Shared processor indicator	...
+	u8	xSecondaryThread:1;	// Secondary thread indicator	...
+	volatile u8 xDynProcStatus:8;	// Dynamic Status of this proc	x0A-x0A
+	u8	xSecondaryThreadCnt;	// Secondary thread count	x0B-x0B
+	volatile u16 xDynHvPhysicalProcIndex;// Dynamic HV Physical Proc Index0C-x0D
+	volatile u16 xDynHvLogicalProcIndex;// Dynamic HV Logical Proc Indexx0E-x0F
+	u32	xDecrVal;   		// Value for Decr programming 	x10-x13
+	u32	xPMCVal;       		// Value for PMC regs         	x14-x17
+	volatile u32 xDynHwNodeId;	// Dynamic Hardware Node id	x18-x1B
+	volatile u32 xDynHwProcId;	// Dynamic Hardware Proc Id	x1C-x1F
+	volatile u32 xDynPIR;		// Dynamic ProcIdReg value	x20-x23
+	u32	xDseiData;           	// DSEI data                  	x24-x27
+	u64	xSPRG3;               	// SPRG3 value                	x28-x2F
+	u8	xRsvd1_3[80];		// Reserved			x30-x7F
+   
+//=============================================================================
+// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
+//=============================================================================
+	// This Dword contains a byte for each type of interrupt that can occur.  
+	// The IPI is a count while the others are just a binary 1 or 0.
+	union {
+		u64	xAnyInt;
+		struct {
+			u16	xRsvd;		// Reserved - cleared by #mpasmbl
+			u8	xXirrInt;	// Indicates xXirrValue is valid or Immed IO
+			u8	xIpiCnt;	// IPI Count
+			u8	xDecrInt;	// DECR interrupt occurred
+			u8	xPdcInt;	// PDC interrupt occurred
+			u8	xQuantumInt;	// Interrupt quantum reached
+			u8	xOldPlicDeferredExtInt;	// Old PLIC has a deferred XIRR pending
+		} xFields;
+	} xIntDword;
+
+	// Whenever any fields in this Dword are set then PLIC will defer the 
+	// processing of external interrupts.  Note that PLIC will store the 
+	// XIRR directly into the xXirrValue field so that another XIRR will 
+	// not be presented until this one clears.  The layout of the low 
+	// 4-bytes of this Dword is upto SLIC - PLIC just checks whether the 
+	// entire Dword is zero or not.  A non-zero value in the low order 
+	// 2-bytes will result in SLIC being granted the highest thread 
+	// priority upon return.  A 0 will return to SLIC as medium priority.
+	u64	xPlicDeferIntsArea;	// Entire Dword
+
+	// Used to pass the real SRR0/1 from PLIC to SLIC as well as to 
+	// pass the target SRR0/1 from SLIC to PLIC on a SetAsrAndRfid.
+	u64     xSavedSrr0;             // Saved SRR0                   x10-x17
+	u64     xSavedSrr1;             // Saved SRR1                   x18-x1F
+
+	// Used to pass parms from the OS to PLIC for SetAsrAndRfid
+	u64     xSavedGpr3;             // Saved GPR3                   x20-x27
+	u64     xSavedGpr4;             // Saved GPR4                   x28-x2F
+	u64     xSavedGpr5;             // Saved GPR5                   x30-x37
+
+	u8	xRsvd2_1;		// Reserved			x38-x38
+	u8      xCpuCtlsTaskAttributes; // Task attributes for cpuctls  x39-x39
+	u8      xFPRegsInUse;           // FP regs in use               x3A-x3A
+	u8      xPMCRegsInUse;          // PMC regs in use              x3B-x3B
+	volatile u32  xSavedDecr;	// Saved Decr Value             x3C-x3F
+	volatile u64  xEmulatedTimeBase;// Emulated TB for this thread  x40-x47
+	volatile u64  xCurPLICLatency;	// Unaccounted PLIC latency     x48-x4F
+	u64     xTotPLICLatency;        // Accumulated PLIC latency     x50-x57   
+	u64     xWaitStateCycles;       // Wait cycles for this proc    x58-x5F
+	u64     xEndOfQuantum;          // TB at end of quantum         x60-x67
+	u64     xPDCSavedSPRG1;         // Saved SPRG1 for PMC int      x68-x6F
+	u64     xPDCSavedSRR0;          // Saved SRR0 for PMC int       x70-x77
+	volatile u32 xVirtualDecr;	// Virtual DECR for shared procsx78-x7B
+	u32	    xRsvd2_2;		// Reserved			x7C-x7F
+
+//=============================================================================
+// CACHE_LINE_3 0x0100 - 0x007F: This line is shared with other processors
+//=============================================================================
+	// This is the xYieldCount.  An "odd" value (low bit on) means that 
+	// the processor is yielded (either because of an OS yield or a PLIC 
+	// preempt).  An even value implies that the processor is currently 
+	// executing.
+	// NOTE: This value will ALWAYS be zero for dedicated processors and 
+	// will NEVER be zero for shared processors (ie, initialized to a 1).
+	volatile u32 xYieldCount;	// PLIC increments each dispatchx00-x03
+	u8	xRsvd3_0[124];		// Reserved                     x04-x7F         
+
+//=============================================================================
+// CACHE_LINE_4-5 0x0100 - 0x01FF Contains PMC interrupt data
+//=============================================================================
+	u8      xPmcSaveArea[256];	// PMC interrupt Area           x00-xFF
+
+
+};
+#endif // _ITLPPACA_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpQueue.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpQueue.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpQueue.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpQueue.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,99 @@
+/*
+ * ItLpQueue.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=============================================================================
+//
+//	This control block defines the simple LP queue structure that is 
+//	shared between the hypervisor (PLIC) and the OS in order to send 
+//	events to an LP.  
+//    
+
+#ifndef _PPC_TYPES_H
+#include <asm/types.h>
+#endif
+#include <asm/ptrace.h>
+
+
+struct HvLpEvent;
+
+
+#ifndef _ITLPQUEUE_H
+#define _ITLPQUEUE_H
+
+#define ITMaxLpQueues 8
+
+#define NotUsed		0	// Queue will not be used by PLIC
+#define DedicatedIo	1	// Queue dedicated to IO processor specified
+#define DedicatedLp	2	// Queue dedicated to LP specified
+#define Shared		3	// Queue shared for both IO and LP
+
+#define LpEventStackSize 4096
+#define LpEventMaxSize   256
+#define LpEventAlign	 64
+
+struct ItLpQueue
+{
+//
+//  The xSlicCurEventPtr is the pointer to the next event stack entry that will
+//  become valid.  The OS must peek at this entry to determine if it is valid.
+//  PLIC will set the valid indicator as the very last store into that entry.
+//
+//  When the OS has completed processing of the event then it will mark the event
+//  as invalid so that PLIC knows it can store into that event location again.
+//
+// If the event stack fills and there are overflow events, then PLIC will set 
+// the xPlicOverflowIntPending flag in which case the OS will have to fetch the 
+// additional LP events once they have drained the event stack.
+//
+// The first 16-bytes are known by both the OS and PLIC.  The remainder of the
+// cache line is for use by the OS.
+//
+//=============================================================================
+	u8	xPlicOverflowIntPending;// 0x00 Overflow events are pending
+	u8	xPlicStatus;		// 0x01 DedicatedIo or DedicatedLp or NotUsed
+	u16	xSlicLogicalProcIndex;	// 0x02 Logical Proc Index for correlation
+	u8	xPlicRsvd[12];		// 0x04
+	char*	xSlicCurEventPtr;	// 0x10
+	char*	xSlicLastValidEventPtr;	// 0x18
+	char*	xSlicEventStackPtr;	// 0x20
+	u8	xIndex;			// 0x28 unique sequential index.
+	u8	xSlicRsvd[3];		// 0x29-2b
+	u32	xInUseWord;		// 0x2C
+	u64	xLpIntCount;		// 0x30 Total Lp Int msgs processed
+	u64	xLpIntCountByType[9];	// 0x38-0x7F Event counts by type
+};
+
+extern struct ItLpQueue xItLpQueue;
+
+extern struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * );
+extern int ItLpQueue_isLpIntPending( struct ItLpQueue * ); 
+extern unsigned ItLpQueue_process( struct ItLpQueue *, struct pt_regs * );
+extern void ItLpQueue_clearValid( struct HvLpEvent * );
+
+static __inline__ void process_iSeries_events( void )
+{
+	__asm__ __volatile__ (
+	"	li	0,0x5555	\n\
+		sc"
+	: : : "r0", "r3" );	
+}
+
+
+//=============================================================================
+#endif // _ITLPQUEUE_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpRegSave.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpRegSave.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItLpRegSave.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItLpRegSave.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,87 @@
+/*
+ * ItLpRegSave.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=====================================================================================
+//
+//	This control block contains the data that is shared between PLIC
+//	and the OS
+//    
+//
+
+#ifndef _ITLPREGSAVE_H
+#define _ITLPREGSAVE_H
+
+struct ItLpRegSave
+{
+	u32	xDesc;		// Eye catcher  "LpRS" ebcdic	000-003
+	u16	xSize;		// Size of this class		004-005
+	u8	xInUse;         // Area is live                 006-007
+	u8	xRsvd1[9]; 	// Reserved			007-00F
+
+	u8      xFixedRegSave[352]; // Fixed Register Save Area 010-16F 
+	u32	xCTRL;		// Control Register		170-173
+	u32	xDEC;		// Decrementer			174-177    
+	u32	xFPSCR;		// FP Status and Control Reg	178-17B
+	u32	xPVR;		// Processor Version Number	17C-17F
+    
+	u64	xMMCR0;		// Monitor Mode Control Reg 0	180-187
+	u32	xPMC1;		// Perf Monitor Counter 1	188-18B
+	u32	xPMC2;		// Perf Monitor Counter 2	18C-18F
+	u32	xPMC3;		// Perf Monitor Counter 3	190-193
+	u32	xPMC4;		// Perf Monitor Counter 4	194-197
+	u32	xPIR;		// Processor ID Reg		198-19B
+    
+	u32	xMMCR1;		// Monitor Mode Control Reg 1	19C-19F
+	u32	xMMCRA;		// Monitor Mode Control Reg A	1A0-1A3
+	u32	xPMC5;		// Perf Monitor Counter 5	1A4-1A7
+	u32	xPMC6;		// Perf Monitor Counter 6	1A8-1AB
+	u32	xPMC7;		// Perf Monitor Counter 7	1AC-1AF
+	u32	xPMC8;		// Perf Monitor Counter 8	1B0-1B3
+	u32	xTSC;		// Thread Switch Control	1B4-1B7
+	u32	xTST;		// Thread Switch Timeout	1B8-1BB
+	u32	xRsvd;          // Reserved                     1BC-1BF
+
+	u64	xACCR;		// Address Compare Control Reg	1C0-1C7
+	u64	xIMR;		// Instruction Match Register	1C8-1CF    
+	u64	xSDR1;		// Storage Description Reg 1	1D0-1D7    
+	u64	xSPRG0;		// Special Purpose Reg General0	1D8-1DF
+	u64	xSPRG1;		// Special Purpose Reg General1	1E0-1E7
+	u64	xSPRG2;		// Special Purpose Reg General2	1E8-1EF
+	u64	xSPRG3;		// Special Purpose Reg General3	1F0-1F7
+	u64	xTB;		// Time Base Register		1F8-1FF
+   
+	u64	xFPR[32];	// Floating Point Registers	200-2FF
+
+	u64	xMSR;		// Machine State Register  	300-307
+	u64	xNIA;		// Next Instruction Address	308-30F
+
+	u64	xDABR;		// Data Address Breakpoint Reg	310-317
+	u64	xIABR;		// Inst Address Breakpoint Reg	318-31F
+
+	u64	xHID0;		// HW Implementation Dependent0	320-327
+
+	u64	xHID4;		// HW Implementation Dependent4	328-32F
+	u64	xSCOMd;		// SCON Data Reg (SPRG4)       	330-337
+	u64	xSCOMc;		// SCON Command Reg (SPRG5)    	338-33F
+	u64	xSDAR;		// Sample Data Address Register	340-347
+	u64	xSIAR;		// Sample Inst Address Register	348-34F
+
+	u8	xRsvd3[176];	// Reserved			350-3FF
+};
+#endif // _ITLPREGSAVE_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItSpCommArea.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItSpCommArea.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItSpCommArea.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItSpCommArea.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,39 @@
+/*
+ * ItSpCommArea.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+#ifndef _ITSPCOMMAREA_H
+#define _ITSPCOMMAREA_H
+
+
+struct SpCommArea
+{
+	u32	xDesc;			// Descriptor (only in new formats)	000-003
+	u8	xFormat;		// Format (only in new formats)		004-004
+	u8	xRsvd1[11];		// Reserved				005-00F
+	u64	xRawTbAtIplStart;	// Raw HW TB value when IPL is started	010-017
+	u64	xRawTodAtIplStart;	// Raw HW TOD value when IPL is started	018-01F
+	u64	xBcdTimeAtIplStart;	// BCD time when IPL is started		020-027
+	u64	xBcdTimeAtOsStart;	// BCD time when OS passed control	028-02F
+	u8	xRsvd2[80];		// Reserved				030-07F
+};
+
+extern struct SpCommArea xSpCommArea;
+
+#endif /* _ITSPCOMMAREA_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItVpdAreas.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItVpdAreas.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/ItVpdAreas.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/ItVpdAreas.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,100 @@
+/*
+ * ItVpdAreas.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+//=====================================================================================
+//
+//      This file defines the address and length of all of the VPD area passed to
+//	the OS from PLIC (most of which start from the SP).
+//
+
+#ifndef _PPC_TYPES_H
+#include        <asm/types.h>
+#endif
+
+
+#ifndef _ITVPDAREAS_H
+#define _ITVPDAREAS_H
+
+// VPD Entry index is carved in stone - cannot be changed (easily).
+#define ItVpdCecVpd				   0
+#define ItVpdDynamicSpace			   1
+#define ItVpdExtVpd				   2
+#define ItVpdExtVpdOnPanel			   3
+#define ItVpdFirstPaca				   4
+#define ItVpdIoVpd				   5
+#define ItVpdIplParms				   6
+#define ItVpdMsVpd				   7
+#define ItVpdPanelVpd				   8
+#define ItVpdLpNaca				   9
+#define ItVpdBackplaneAndMaybeClockCardVpd        10 
+#define ItVpdRecoveryLogBuffer		          11
+#define ItVpdSpCommArea				  12
+#define ItVpdSpLogBuffer			  13
+#define ItVpdSpLogBufferSave			  14
+#define ItVpdSpCardVpd				  15
+#define ItVpdFirstProcVpd			  16	
+#define ItVpdApModelVpd				  17
+#define ItVpdClockCardVpd			  18
+#define ItVpdBusExtCardVpd			  19
+#define ItVpdProcCapacityVpd			  20
+#define ItVpdInteractiveCapacityVpd		  21
+#define ItVpdFirstSlotLabel			  22
+#define ItVpdFirstLpQueue			  23
+#define ItVpdFirstL3CacheVpd			  24	
+#define ItVpdFirstProcFruVpd			  25
+
+#define ItVpdMaxEntries				  26
+
+
+#define ItDmaMaxEntries				  10
+
+#define ItVpdAreasMaxSlotLabels		 192 
+
+
+struct SlicVpdAdrs {
+	u32	pad1;
+	void *  vpdAddr;
+};
+
+
+struct	ItVpdAreas
+{
+	u32	xSlicDesc;		// Descriptor				000-003
+	u16	xSlicSize;		// Size of this control block		004-005
+	u16	xPlicAdjustVpdLens:1;	// Flag to indicate new interface 	006-007
+	u16	xRsvd1:15;		// Reserved bits			...
+	u16	xSlicVpdEntries;	// Number of VPD entries		008-009
+	u16	xSlicDmaEntries;	// Number of DMA entries		00A-00B
+	u16	xSlicMaxLogicalProcs;	// Maximum logical processors		00C-00D
+	u16	xSlicMaxPhysicalProcs;	// Maximum physical processors		00E-00F
+	u16	xSlicDmaToksOffset;	// Offset into this of array		010-011
+	u16	xSlicVpdAdrsOffset;	// Offset into this of array		012-013
+	u16	xSlicDmaLensOffset;	// Offset into this of array		014-015
+	u16	xSlicVpdLensOffset;	// Offset into this of array		016-017
+	u16	xSlicMaxSlotLabels;	// Maximum number of slot labels	018-019
+	u16	xSlicMaxLpQueues;	// Maximum number of LP Queues		01A-01B
+	u8	xRsvd2[4];		// Reserved				01C-01F
+	u64	xRsvd3[12];		// Reserved				020-07F
+	u32	xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths		080-0A7
+	u32	xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens		0A8-0CF
+	u32	xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths		0D0-12F
+	void * xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers	130-1EF
+};
+
+#endif // _ITVPDAREAS_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/LparData.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/LparData.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/LparData.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/LparData.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,57 @@
+/*
+ * LparData.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef	_PPC_TYPES_H
+#include	<asm/types.h>
+#endif
+
+#ifndef _LPARDATA_H
+#define _LPARDATA_H
+
+#include <asm/types.h>
+#include <asm/page.h>
+#include <asm/abs_addr.h>
+
+#include <asm/Naca.h>
+#include <asm/iSeries/ItLpNaca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpRegSave.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/HvReleaseData.h>
+#include <asm/iSeries/LparMap.h>
+#include <asm/iSeries/ItVpdAreas.h>
+#include <asm/iSeries/ItIplParmsReal.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/IoHriProcessorVpd.h>
+#include <asm/page.h>
+
+extern struct LparMap	xLparMap;
+extern struct Naca	xNaca;
+extern struct Paca	xPaca[];
+extern struct HvReleaseData hvReleaseData;
+extern struct ItLpNaca	itLpNaca;
+extern struct ItIplParmsReal xItIplParmsReal;
+extern struct IoHriProcessorVpd xIoHriProcessorVpd[];
+extern struct ItLpQueue xItLpQueue;
+extern struct ItVpdAreas itVpdAreas;
+extern u64    xMsVpd[];
+extern struct msChunks msChunks;
+
+
+#endif /* _LPARDATA_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/LparMap.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/LparMap.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/LparMap.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/LparMap.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,70 @@
+/*
+ * LparMap.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef	_PPC_TYPES_H
+#include	<asm/types.h>
+#endif
+
+#ifndef _LPARMAP_H
+#define _LPARMAP_H
+
+/* The iSeries hypervisor will set up mapping for one or more 
+ * ESID/VSID pairs (in SLB/segment registers) and will set up
+ * mappings of one or more ranges of pages to VAs.
+ * We will have the hypervisor set up the ESID->VSID mapping
+ * for the four kernel segments (C-F).  With shared processors,
+ * the hypervisor will clear all segment registers and reload
+ * these four whenever the processor is switched from one 
+ * partition to another.
+ */
+
+/* The Vsid and Esid identified below will be used by the hypervisor
+ * to set up a memory mapping for part of the load area before giving
+ * control to the Linux kernel.  The load area is 64 MB, but this must
+ * not attempt to map the whole load area.  The Hashed Page Table may
+ * need to be located within the load area (if the total partition size
+ * is 64 MB), but cannot be mapped.  Typically, this should specify
+ * to map half (32 MB) of the load area.
+ * 
+ * The hypervisor will set up page table entries for the number of 
+ * pages specified.
+ *
+ * In 32-bit mode, the hypervisor will load all four of the
+ * segment registers (identified by the low-order four bits of the 
+ * Esid field.  In 64-bit mode, the hypervisor will load one SLB
+ * entry to map the Esid to the Vsid.
+*/
+
+// Hypervisor initially maps 32MB of the load area 
+#define HvPagesToMap 8192
+
+struct LparMap
+{
+	u64	  xNumberEsids;		// Number of ESID/VSID pairs (1)
+	u64	  xNumberRanges;	// Number of VA ranges to map (1)
+	u64	  xSegmentTableOffs;	// Page number within load area of seg table (0)
+	u64	  xRsvd[5];		// Reserved (0)
+	u64	  xKernelEsid;  	// Esid used to map kernel load (0x0C00000000)	
+	u64	  xKernelVsid;		// Vsid used to map kernel load (0x0C00000000)
+	u64	  xPages;		// Number of pages to be mapped	(8192)
+	u64	  xOffset;		// Offset from start of load area (0)
+	u64	  xVPN;			// Virtual Page Number (0x000C000000000000)
+};
+
+#endif /* _LPARMAP_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/XmPciLpEvent.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/XmPciLpEvent.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/XmPciLpEvent.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/XmPciLpEvent.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,18 @@
+
+#ifndef	__XMPCILPEVENT_H__
+#define	__XMPCILPEVENT_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int XmPciLpEvent_init(void);
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XMPCILPEVENT_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_FlightRecorder.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_FlightRecorder.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_FlightRecorder.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_FlightRecorder.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,85 @@
+#ifndef _ISERIES_FLIGHTRECORDER_H
+#define _ISERIES_FLIGHTRECORDER_H
+/************************************************************************/
+/* File iSeries_FlightRecorder.h created by Allan Trautman Jan 22 2001. */
+/************************************************************************/
+/* This code supports the pci interface on the IBM iSeries systems.     */
+/* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, Jan 22, 2001                                              */
+/*   Added Time stamp methods. Apr 12, 2001                             */
+/* End Change Activity                                                  */
+/************************************************************************/
+/* This is a generic Flight Recorder, simply stuffs line entries into a */
+/* buffer for debug purposes.                                           */
+/*                                                                      */
+/* To use,                                                              */ 
+/* 1. Create one, make it global so it isn't on the stack.              */
+/*     FlightRecorder  PciFlightRecorder;                               */
+/*                                                                      */
+/* 2. Optionally create a pointer to it, just makes it easier to use.   */
+/*     FlightRecorder* PciFr = &PciFlightRecorder;                      */
+/*                                                                      */
+/* 3. Initialize with you signature.                                    */
+/*          iSeries_Fr_Initialize(PciFr, "Pci Flight Recorder");        */
+/*                                                                      */
+/* 4. Log entries.                                                      */ 
+/*          PciFr->logEntry(PciFr,"In Main");                           */
+/*                                                                      */
+/* 5. Later, you can find the Flight Recorder by looking in the         */
+/*    System.map                                                        */
+/************************************************************************/
+struct iSeries_FlightRecorder;          /* Forward declares             */
+struct rtc_time;
+void   logEntry(struct iSeries_FlightRecorder*, char* Text);
+void   logTime( struct iSeries_FlightRecorder*, char* Text);
+void   logDate( struct iSeries_FlightRecorder*, char* Text);
+#define FlightRecorderSize 4096 
+
+/************************************************************************/
+/* Generic Flight Recorder Structure                                    */
+/************************************************************************/
+struct iSeries_FlightRecorder {         /* Structure Defination         */
+	char  Signature[16];                /* Eye Catcher                  */
+	char* StartingPointer;              /* Buffer Starting Address      */
+	char* CurrentPointer;               /* Next Entry Address           */
+	int   WrapCount;                    /* Number of Buffer Wraps       */
+	void  (*logEntry)(struct iSeries_FlightRecorder*,char*);
+	void  (*logTime) (struct iSeries_FlightRecorder*,char*);
+	void  (*logDate) (struct iSeries_FlightRecorder*,char*);
+	char  Buffer[FlightRecorderSize];
+};
+
+typedef struct iSeries_FlightRecorder FlightRecorder;	/* Short Name   */
+extern void iSeries_Fr_Initialize(FlightRecorder*, char* Signature);
+/************************************************************************/
+/* extern void iSeries_LogFr_Entry(  FlightRecorder*, char* Text);      */
+/* extern void iSeries_LogFr_Date(   FlightRecorder*, char* Text);      */
+/* extern void iSeries_LogFr_Time(   FlightRecorder*, char* Text);      */
+/************************************************************************/
+/* PCI Flight Recorder Helpers                                          */
+/************************************************************************/
+extern FlightRecorder* PciFr;            /* Ptr to Pci Fr               */
+extern char*           PciFrBuffer;      /* Ptr to Fr Work Buffer       */
+#define ISERIES_PCI_FR(buffer)      PciFr->logEntry(PciFr,buffer);
+#define ISERIES_PCI_FR_TIME(buffer) PciFr->logTime(PciFr,buffer);
+#define ISERIES_PCI_FR_DATE(buffer) PciFr->logDate(PciFr,buffer);
+
+#endif /* _ISERIES_FLIGHTRECORDER_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_VpdInfo.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_VpdInfo.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_VpdInfo.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_VpdInfo.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,56 @@
+#ifndef _ISERIES_VPDINFO_H
+#define _ISERIES_VPDINFO_H
+/************************************************************************/
+/* File iSeries_VpdInfo.h created by Allan Trautman Feb 08 2001.        */
+/************************************************************************/
+/* This code supports the location data fon on the IBM iSeries systems. */
+/* Copyright (C) 20yy  <Allan H Trautman> <IBM Corp>                    */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created, Feg  8, 2001                                              */
+/*   Reformated for Card, March 8, 2001                                 */
+/* End Change Activity                                                  */
+/************************************************************************/
+
+struct pci_dev; 		/* Forward Declare                      */
+/************************************************************************/
+/* Location Data extracted from the VPD list and device info.           */
+/************************************************************************/
+struct LocationDataStruct {	/* Location data structure for device   */
+	u16  Bus;		/* iSeries Bus Number		    0x00*/
+	u16  Board;		/* iSeries Board                    0x02*/
+	u8   FrameId;		/* iSeries spcn Frame Id            0x04*/
+	u8   PhbId;		/* iSeries Phb Location             0x05*/
+	u16  Card;		/* iSeries Card Slot                0x06*/
+	char CardLocation[4];	/* Char format of planar vpd        0x08*/
+	u8   AgentId;		/* iSeries AgentId                  0x0C*/
+	u8   SecondaryAgentId;	/* iSeries Secondary Agent Id       0x0D*/
+	u8   LinuxBus;		/* Linux Bus Number                 0x0E*/
+	u8   LinuxDevFn;	/* Linux Device Function            0x0F*/
+};
+typedef struct LocationDataStruct  LocationData;
+#define LOCATION_DATA_SIZE      16
+
+/************************************************************************/
+/* Protypes                                                             */
+/************************************************************************/
+extern LocationData* iSeries_GetLocationData(struct pci_dev* PciDev);
+extern int           iSeries_Device_Information(struct pci_dev*,char*, int);
+
+#endif /* _ISERIES_VPDINFO_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_dma.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_dma.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_dma.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_dma.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,97 @@
+/*
+ * iSeries_dma.h
+ * Copyright (C) 2001  Mike Corrigan IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _ISERIES_DMA_H
+#define _ISERIES_DMA_H
+
+#include <asm/types.h>
+#ifndef __LINUX_SPINLOCK_H
+#include <linux/spinlock.h>
+#endif
+
+// NUM_TCE_LEVELS defines the largest contiguous block
+// of dma (tce) space we can get.  NUM_TCE_LEVELS = 10 
+// allows up to 2**9 pages (512 * 4096) = 2 MB
+#define NUM_TCE_LEVELS 10
+
+#define NO_TCE ((dma_addr_t)-1)
+
+// Tces come in two formats, one for the virtual bus and a different
+// format for PCI
+#define TCE_VB  0
+#define TCE_PCI 1
+
+
+union Tce {
+   	u64	wholeTce;
+	struct {
+		u64	cacheBits	:6;	/* Cache hash bits - not used */
+		u64	rsvd		:6;	
+		u64	rpn		:40;	/* Absolute page number */
+		u64	valid		:1;	/* Tce is valid (vb only) */
+		u64	allIo		:1;	/* Tce is valid for all lps (vb only) */
+		u64	lpIndex		:8;	/* LpIndex for user of TCE (vb only) */
+		u64	pciWrite	:1;	/* Write allowed (pci only) */
+		u64	readWrite	:1;	/* Read allowed (pci), Write allowed
+						   (vb) */
+	} tceBits;
+};
+
+struct Bitmap {
+	unsigned long	numBits;
+	unsigned long	numBytes;
+	unsigned char * map;
+};
+
+struct MultiLevelBitmap {
+	unsigned long 	maxLevel;
+	struct Bitmap 	level[NUM_TCE_LEVELS];
+};
+
+struct TceTable {
+	u64	busNumber;
+	u64	size;
+	u64	startOffset;
+	u64	index;
+	spinlock_t	lock;
+	struct MultiLevelBitmap mlbm;
+};
+
+struct HvTceTableManagerCB {
+	u64	busNumber;		/* Bus number for this tce table */
+	u64	start;			/* Will be NULL for secondary */
+	u64	totalSize;		/* Size (in pages) of whole table */
+	u64	startOffset;		/* Index into real tce table of the
+					   start of our section */
+	u64	size;			/* Size (in pages) of our section */
+	u64	index;			/* Index of this tce table (token?) */
+	u16	maxTceTableIndex;	/* Max number of tables for partition */
+	u8	virtualBusFlag;		/* Flag to indicate virtual bus */
+	u8	rsvd[5];
+};
+
+extern struct TceTable virtBusTceTable;	/* Tce table for virtual bus */
+
+extern struct TceTable * build_tce_table( struct HvTceTableManagerCB *,
+					  struct TceTable *);
+extern void              create_virtual_bus_tce_table( void );
+
+extern void		 create_pci_bus_tce_table( unsigned busNumber );
+
+#endif // _ISERIES_DMA_H
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_fixup.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_fixup.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_fixup.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_fixup.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,25 @@
+
+#ifndef	__ISERIES_FIXUP_H__
+#define	__ISERIES_FIXUP_H__
+#include <linux/pci.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void iSeries_fixup (void);
+void iSeries_fixup_bus (struct pci_bus*);
+unsigned int iSeries_scan_slot (struct pci_dev*, u16, u8, u8);
+
+
+/* Need to store information related to the PHB bucc and make it accessible to the hose */
+struct iSeries_hose_arch_data {
+	u32 hvBusNumber;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ISERIES_FIXUP_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_io.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_io.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_io.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_io.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,46 @@
+#include <linux/config.h>
+
+#ifdef CONFIG_PPC_ISERIES
+#ifndef _ISERIES_IO_H
+#define _ISERIES_IO_H
+#include <linux/types.h>
+/************************************************************************/
+/* File iSeries_io.h created by Allan Trautman on Thu Dec 28 2000.      */
+/************************************************************************/
+/* Remaps the io.h for the iSeries Io                                   */
+/* Copyright (C) 20yy  Allan H Trautman, IBM Corporation                */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created December 28, 2000                                          */
+/* End Change Activity                                                  */
+/************************************************************************/
+extern u8   iSeries_Read_Byte(void* IoAddress);
+extern u16  iSeries_Read_Word(void* IoAddress);
+extern u32  iSeries_Read_Long(void* IoAddress);
+extern void iSeries_Write_Byte(u8  IoData,void* IoAddress);
+extern void iSeries_Write_Word(u16 IoData,void* IoAddress);
+extern void iSeries_Write_Long(u32 IoData,void* IoAddress);
+
+extern void* iSeries_memset_io(void *dest, char x, size_t n);
+extern void* iSeries_memcpy_toio(void *dest, void *source, size_t n);
+extern void* iSeries_memcpy_fromio(void *dest, void *source, size_t n);
+
+#endif /*  _ISERIES_IO_H         */
+#endif /*  CONFIG_PPC_ISERIES  */
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_irq.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_irq.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_irq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_irq.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,27 @@
+
+#ifndef	__ISERIES_IRQ_H__
+#define	__ISERIES_IRQ_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned int iSeries_startup_IRQ(unsigned int);
+void iSeries_shutdown_IRQ(unsigned int);
+void iSeries_enable_IRQ(unsigned int);
+void iSeries_disable_IRQ(unsigned int);
+void iSeries_end_IRQ(unsigned int);
+void iSeries_init_IRQ(void);
+void iSeries_init_irqMap(int);
+int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
+int  iSeries_assign_IRQ(int, HvBusNumber, HvSubBusNumber, HvAgentId);
+void iSeries_activate_IRQs(void);
+
+int XmPciLpEvent_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ISERIES_IRQ_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_pci.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_pci.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_pci.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_pci.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,127 @@
+#ifndef _ISERIES_64_PCI_H
+#define _ISERIES_64_PCI_H
+/************************************************************************/
+/* File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001.    */
+/************************************************************************/
+/* Define some useful macros for the iSeries pci routines.              */
+/* Copyright (C) 20yy  Allan H Trautman, IBM Corporation                */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or    */
+/* (at your option) any later version.                                  */
+/*                                                                      */
+/* This program is distributed in the hope that it will be useful,      */ 
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
+/* GNU General Public License for more details.                         */
+/*                                                                      */
+/* You should have received a copy of the GNU General Public License    */ 
+/* along with this program; if not, write to the:                       */
+/* Free Software Foundation, Inc.,                                      */ 
+/* 59 Temple Place, Suite 330,                                          */ 
+/* Boston, MA  02111-1307  USA                                          */
+/************************************************************************/
+/* Change Activity:                                                     */
+/*   Created Feb 20, 2001                                               */
+/*   Added device reset, March 22, 2001                                 */
+/*   Ported to ppc64, May 25, 2001                                      */
+/* End Change Activity                                                  */
+/************************************************************************/
+#include <asm/iSeries/HvCallPci.h>
+
+struct pci_dev;				/* For Forward Reference        */
+struct iSeries_Device_Node;
+/************************************************************************/
+/* Gets iSeries Bus, SubBus, of DevFn using pci_dev* structure          */
+/************************************************************************/
+#define ISERIES_BUS(DevPtr)    DevPtr->DsaAddr.busNumber
+#define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.subBusNumber
+#define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.deviceId
+#define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn
+#define ISERIES_DSA(DevPtr)   (*(u64*)&DevPtr->DsaAddr)
+#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata)
+
+#define EADsMaxAgents 7
+/************************************************************************************/
+/* Decodes Linux DevFn to iSeries DevFn, bridge device, or function.                */
+/* For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h                      */
+/************************************************************************************/
+#define ISERIES_DECODE_DEVFN(linuxdevfn)  (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07))
+#define ISERIES_DECODE_DEVICE(linuxdevfn) (((linuxdevfn & 0x38) >> 3) |(((linuxdevfn & 0x40) >> 2) + 0x10))
+#define ISERIES_DECODE_FUNCTION(linuxdevfn) (linuxdevfn & 0x07)
+#define ISERIES_PCI_AGENTID(idsel,func)	((idsel & 0x0F) << 4) | (func  & 0x07)
+
+#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus)   ((subbus >> 5) & 0x7)
+#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
+
+#define ISERIES_ENCODE_DEVICE(agentid)	((0x10) | ((agentid&0x20)>>2) | (agentid&07))
+/************************************************************************************/
+/* Converts Virtual Address to Real Address for Hypervisor calls                    */
+/************************************************************************************/
+#define REALADDR(virtaddr)  (0x8000000000000000 | (virt_to_absolute((u64)virtaddr) ))
+
+/************************************************************************************/
+/* Define TRUE and FALSE Values for Al                                              */
+/************************************************************************************/
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/************************************************************************/
+/* iSeries Device Information                                           */
+/************************************************************************/
+struct iSeries_Device_Node {
+	struct list_head Device_List;    /* Must be first for cast to wo*/
+	struct pci_dev*  PciDev;         /* Pointer to pci_dev structure*/
+        struct HvCallPci_DsaAddr DsaAddr;/* Direct Select Address       */
+                                         /* busNumber,subBusNumber,     */ 
+	                                 /* deviceId, barNumber         */
+	HvAgentId        AgentId;	 /* Hypervisor DevFn            */
+	int              DevFn;          /* Linux devfn                 */
+	int              BarOffset;
+	int              Irq;            /* Assigned IRQ                */
+	int              ReturnCode;	 /* Return Code Holder          */
+	int              IoRetry;        /* Current Retry Count         */
+	int              Flags;          /* Possible flags(disable/bist)*/
+	u16              Vendor;         /* Vendor ID                   */
+	u8               LogicalSlot;    /* Hv Slot Index for Tces      */
+	struct TceTable* DevTceTable;    /* Device TCE Table            */ 
+	u8               PhbId;          /* Phb Card is on.             */
+	u16              Board;          /* Board Number                */
+	u8               FrameId;	 /* iSeries spcn Frame Id       */
+	char             CardLocation[4];/* Char format of planar vpd   */
+	char             Location[20];   /* Frame  1, Card C10          */
+};
+/************************************************************************/
+/* Location Data extracted from the VPD list and device info.           */
+/************************************************************************/
+struct LocationDataStruct { 	/* Location data structure for device  */
+	u16  Bus;               /* iSeries Bus Number              0x00*/
+	u16  Board;             /* iSeries Board                   0x02*/
+	u8   FrameId;           /* iSeries spcn Frame Id           0x04*/
+	u8   PhbId;             /* iSeries Phb Location            0x05*/
+	u8   AgentId;           /* iSeries AgentId                 0x06*/
+	u8   Card;
+	char CardLocation[4];      
+};
+typedef struct LocationDataStruct  LocationData;
+#define LOCATION_DATA_SIZE      48
+/************************************************************************/
+/* Flight Recorder tracing                                              */
+/************************************************************************/
+extern int  iSeries_Set_PciTraceFlag(int TraceFlag);
+extern int  iSeries_Get_PciTraceFlag(void);
+
+/************************************************************************/
+/* Functions                                                            */
+/************************************************************************/
+extern LocationData* iSeries_GetLocationData(struct pci_dev* PciDev);
+extern int           iSeries_Device_Information(struct pci_dev*,char*, int);
+extern void          iSeries_Get_Location_Code(struct iSeries_Device_Node*);
+extern int           iSeries_Device_ToggleReset(struct pci_dev* PciDev, int AssertTime, int DelayTime);
+
+#endif /* _ISERIES_64_PCI_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_proc.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_proc.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/iSeries_proc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/iSeries_proc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,37 @@
+/*
+ * iSeries_proc.h
+ * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _ISERIES_PROC_H
+#define _ISERIES_PROC_H
+
+#include <linux/proc_fs.h>
+
+extern void iSeries_proc_early_init(void);
+extern void iSeries_proc_create(void);
+
+typedef void (*iSeriesProcFunction)(struct proc_dir_entry *iSeries_proc);
+
+extern void iSeries_proc_callback(iSeriesProcFunction initFunction);
+
+#endif /* _iSeries_PROC_H */
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/mf.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/mf.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/mf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/mf.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,83 @@
+/*
+ * mf.h
+ * Copyright (C) 2001  Troy D. Armstrong IBM Corporation
+ *
+ * This modules exists as an interface between a Linux secondary partition
+ * running on an iSeries and the primary partition's Virtual Service
+ * Processor (VSP) object.  The VSP has final authority over powering on/off
+ * all partitions in the iSeries.  It also provides miscellaneous low-level
+ * machine facility type operations.
+ *
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef MF_H_INCLUDED
+#define MF_H_INCLUDED
+
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpEvent.h>
+
+struct rtc_time;
+
+typedef void (*MFCompleteHandler)( void * clientToken, int returnCode );
+
+extern void mf_allocateLpEvents( HvLpIndex targetLp,
+				 HvLpEvent_Type type,
+				 unsigned size,
+				 unsigned amount,
+				 MFCompleteHandler hdlr,
+				 void * userToken );
+
+extern void mf_deallocateLpEvents( HvLpIndex targetLp,
+				   HvLpEvent_Type type,
+				   unsigned count,
+				   MFCompleteHandler hdlr,
+				   void * userToken );
+
+extern void mf_powerOff( void );
+
+extern void mf_reboot( void );
+
+extern void mf_displaySrc( u32 word );
+extern void mf_displayProgress( u16 value );
+
+extern void mf_clearSrc( void );
+
+extern void mf_init( void );
+
+extern void mf_setSide(char side);
+
+extern char mf_getSide(void);
+
+extern void mf_setCmdLine(const char *cmdline, int size, u64 side);
+
+extern int  mf_getCmdLine(char *cmdline, int *size, u64 side);
+
+extern void mf_getSrcHistory(char *buffer, int size);
+
+extern int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side);
+
+extern int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side);
+
+extern int mf_setRtcTime(unsigned long time);
+
+extern int mf_getRtcTime(unsigned long *time);
+
+extern int mf_getRtc( struct rtc_time * tm );
+
+extern int mf_setRtc( struct rtc_time * tm );
+
+#endif /* MF_H_INCLUDED */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/mf_proc.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/mf_proc.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/mf_proc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/mf_proc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,33 @@
+/*
+ * mf_proc.h
+ * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _MF_PROC_H
+#define _MF_PROC_H
+
+#include <linux/proc_fs.h>
+
+void mf_proc_init(struct proc_dir_entry *iSeries_proc);
+
+
+#endif /* _MF_PROC_H */
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/iSeries/veth-proc.h linux-2.4.19-pre5/include/asm-ppc64/iSeries/veth-proc.h
--- linux-2.4.19-pre4/include/asm-ppc64/iSeries/veth-proc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/iSeries/veth-proc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,32 @@
+/*
+ * veth-proc.h
+ * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _VETH_PROC_H
+#define _VETH_PROC_H
+
+#include <linux/proc_fs.h>
+
+void veth_proc_init(struct proc_dir_entry *iSeries_proc);
+
+#endif /* _VETH-PROC_H */
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ide.h linux-2.4.19-pre5/include/asm-ppc64/ide.h
--- linux-2.4.19-pre4/include/asm-ppc64/ide.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ide.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,82 @@
+/*
+ *  linux/include/asm-ppc/ide.h
+ *
+ *  Copyright (C) 1994-1996 Linus Torvalds & authors
+ *
+ * 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 file contains the ppc64 architecture specific IDE code.
+ */
+
+#ifndef __ASMPPC64_IDE_H
+#define __ASMPPC64_IDE_H
+
+#ifdef __KERNEL__
+
+#ifndef MAX_HWIFS
+#define MAX_HWIFS	4
+#endif
+
+#define ide__sti()	__sti()
+
+void ppc64_ide_fix_driveid(struct hd_driveid *id);
+#define ide_fix_driveid(id)	ppc64_ide_fix_driveid((id))
+
+static __inline__ int ide_default_irq(ide_ioreg_t base) { return 0; }
+static __inline__ ide_ioreg_t ide_default_io_base(int index) { return 0; }
+
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+	hw->io_ports[IDE_IRQ_OFFSET] = 0;
+}
+
+static __inline__ void ide_init_default_hwifs(void)
+{
+}
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned head		: 4;	/* always zeros here */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit7		: 1;	/* always 1 */
+	} b;
+	} select_t;
+
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMPPC64_IDE_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/init.h linux-2.4.19-pre5/include/asm-ppc64/init.h
--- linux-2.4.19-pre4/include/asm-ppc64/init.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/init.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,29 @@
+#ifndef _PPC64_INIT_H
+#define _PPC64_INIT_H
+
+#include <linux/init.h>
+
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 90 /* egcs */
+/* DRENG add back in when we get section attribute support */
+#define __chrp __attribute__ ((__section__ (".text.chrp")))
+#define __chrpdata __attribute__ ((__section__ (".data.chrp")))
+#define __chrpfunc(__argchrp) \
+	__argchrp __chrp; \
+	__argchrp
+
+/* this is actually just common chrp/pmac code, not OF code -- Cort */
+#define __openfirmware __attribute__ ((__section__ (".text.openfirmware")))
+#define __openfirmwaredata __attribute__ ((__section__ (".data.openfirmware")))
+#define __openfirmwarefunc(__argopenfirmware) \
+	__argopenfirmware __openfirmware; \
+	__argopenfirmware
+	
+#else /* not egcs */
+
+#define __openfirmware
+#define __openfirmwaredata
+#define __openfirmwarefunc(x) x
+
+#endif /* egcs */
+
+#endif /* _PPC64_INIT_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/io.h linux-2.4.19-pre5/include/asm-ppc64/io.h
--- linux-2.4.19-pre4/include/asm-ppc64/io.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/io.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,329 @@
+#ifndef _PPC64_IO_H
+#define _PPC64_IO_H
+
+/* 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/page.h>
+#include <asm/byteorder.h>
+#ifdef CONFIG_PPC_ISERIES 
+#include <asm/iSeries/iSeries_io.h>
+#endif  
+#include <asm/memory.h>
+#include <asm/delay.h>
+
+#define SIO_CONFIG_RA	0x398
+#define SIO_CONFIG_RD	0x399
+
+#define SLOW_DOWN_IO
+/* Define this if you want to see virt_to_* messages */
+#undef __IO_DEBUG
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_io_base;
+extern unsigned long pci_dram_offset;
+extern int have_print;
+#define _IO_BASE	isa_io_base
+#define _ISA_MEM_BASE	isa_mem_base
+#define PCI_DRAM_OFFSET	pci_dram_offset
+
+#ifdef CONFIG_PPC_ISERIES
+#define readb(addr)		iSeries_Read_Byte((void*)(addr))  
+#define readw(addr)		iSeries_Read_Word((void*)(addr))  
+#define readl(addr)		iSeries_Read_Long((void*)(addr))
+#define writeb(data, addr)	iSeries_Write_Byte(data,((void*)(addr)))
+#define writew(data, addr)	iSeries_Write_Word(data,((void*)(addr)))
+#define writel(data, addr)	iSeries_Write_Long(data,((void*)(addr)))
+#define memset_io(a,b,c)	iSeries_memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)	iSeries_memcpy_fromio((void *)(a), (void *)(b), (c))
+#define memcpy_toio(a,b,c)	iSeries_memcpy_toio((void *)(a), (void *)(b), (c))
+#define inb(addr)		readb(((unsigned long)(addr)))  
+#define inw(addr)		readw(((unsigned long)(addr)))  
+#define inl(addr)		readl(((unsigned long)(addr)))
+#define outb(data,addr)		writeb(data,((unsigned long)(addr)))  
+#define outw(data,addr)		writew(data,((unsigned long)(addr)))  
+#define outl(data,addr)		writel(data,((unsigned long)(addr)))
+#else
+#define IS_MAPPED_VADDR(port)	((unsigned long)(port) >> 60UL)
+#ifdef CONFIG_PPC_EEH
+#define readb(addr)		eeh_readb((void*)(addr))  
+#define readw(addr)		eeh_readw((void*)(addr))  
+#define readl(addr)		eeh_readl((void*)(addr))
+#define writeb(data, addr)	eeh_writeb((data), ((void*)(addr)))
+#define writew(data, addr)	eeh_writew((data), ((void*)(addr)))
+#define writel(data, addr)	eeh_writel((data), ((void*)(addr)))
+#define memset_io(a,b,c)	eeh_memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)	eeh_memcpy_fromio((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	eeh_memcpy_toio((void *)(a),(b),(c))
+#else
+#define readb(addr)		in_8((volatile u8 *)(addr))
+#define writeb(b,addr)		out_8((volatile u8 *)(addr), (b))
+#define readw(addr)		in_le16((volatile u16 *)(addr))
+#define readl(addr)		in_le32((volatile u32 *)(addr))
+#define writew(b,addr)		out_le16((volatile u16 *)(addr),(b))
+#define writel(b,addr)		out_le32((volatile u32 *)(addr),(b))
+#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+#endif
+#define inb(port)		_inb((unsigned long)port)
+#define outb(val, port)		_outb(val, (unsigned long)port)
+#define inw(port)		_inw((unsigned long)port)
+#define outw(val, port)		_outw(val, (unsigned long)port)
+#define inl(port)		_inl((unsigned long)port)
+#define outl(val, port)		_outl(val, (unsigned long)port)
+#endif
+
+
+/*
+ * output pause versions need a delay at least for the
+ * w83c105 ide controller in a p610.
+ */
+#define inb_p(port)             inb(port)
+#define outb_p(val, port)       (udelay(1), outb((val), (port)))
+#define inw_p(port)             inw(port)
+#define outw_p(val, port)       (udelay(1), outw((val), (port)))
+#define inl_p(port)             inl(port)
+#define outl_p(val, port)       (udelay(1), outl((val, (port)))
+
+/*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+ * They are only used in practice for transferring buffers which
+ * are arrays of bytes, and byte-swapping is not appropriate in
+ * that case.  - paulus */
+#define _IOMAP_VADDR(port) (IS_MAPPED_VADDR(port) ? (port) : (port)+_IO_BASE)
+#define insb(port, buf, ns)	_insb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
+#define outsb(port, buf, ns)	_outsb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
+#define insw(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
+#define insl(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+
+extern void _insb(volatile u8 *port, void *buf, int ns);
+extern void _outsb(volatile u8 *port, const void *buf, int ns);
+extern void _insw(volatile u16 *port, void *buf, int ns);
+extern void _outsw(volatile u16 *port, const void *buf, int ns);
+extern void _insl(volatile u32 *port, void *buf, int nl);
+extern void _outsl(volatile u32 *port, const void *buf, int nl);
+extern void _insw_ns(volatile u16 *port, void *buf, int ns);
+extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
+extern void _insl_ns(volatile u32 *port, void *buf, int nl);
+extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
+
+/*
+ * The *_ns versions below don't do byte-swapping.
+ * Neither do the standard versions now, these are just here
+ * for older code.
+ */
+#define insw_ns(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
+#define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
+#define insl_ns(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+#define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+
+
+#define IO_SPACE_LIMIT ~(0UL)
+#define MEM_SPACE_LIMIT ~(0UL)
+
+
+#ifdef __KERNEL__
+/*
+ * Map in an area of physical address space, for accessing
+ * I/O devices etc.
+ */
+extern void *__ioremap(unsigned long address, unsigned long size,
+		       unsigned long flags);
+extern void *ioremap(unsigned long address, unsigned long size);
+#define ioremap_nocache(addr, size)	ioremap((addr), (size))
+extern void iounmap(void *addr);
+
+/*
+ * Change virtual addresses to physical addresses and vv, for
+ * addresses in the area where the kernel has the RAM mapped.
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+#ifdef __IO_DEBUG
+	printk("virt_to_phys: 0x%08lx -> 0x%08lx\n", 
+			(unsigned long) address,
+			__pa((unsigned long)address));
+#endif
+	return __pa((unsigned long)address);
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+#ifdef __IO_DEBUG
+	printk("phys_to_virt: 0x%08lx -> 0x%08lx\n", address, __va(address));
+#endif
+	return (void *) __va(address);
+}
+
+#endif /* __KERNEL__ */
+
+extern inline void iosync(void)
+{
+        __asm__ __volatile__ ("sync" : : : "memory");
+}
+
+/* Enforce in-order execution of data I/O. 
+ * No distinction between read/write on PPC; use eieio for all three.
+ */
+#define iobarrier_rw() eieio()
+#define iobarrier_r()  eieio()
+#define iobarrier_w()  eieio()
+
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ */
+extern inline int in_8(volatile unsigned char *addr)
+{
+	int ret;
+
+	__asm__ __volatile__("eieio; lbz%U1%X1 %0,%1" : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+extern inline void out_8(volatile unsigned char *addr, int val)
+{
+	__asm__ __volatile__("stb%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
+}
+
+extern inline int in_le16(volatile unsigned short *addr)
+{
+	int ret;
+
+	__asm__ __volatile__("eieio; lhbrx %0,0,%1" : "=r" (ret) :
+			      "r" (addr), "m" (*addr));
+	return ret;
+}
+
+extern inline int in_be16(volatile unsigned short *addr)
+{
+	int ret;
+
+	__asm__ __volatile__("eieio; lhz%U1%X1 %0,%1" : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+extern inline void out_le16(volatile unsigned short *addr, int val)
+{
+	__asm__ __volatile__("sthbrx %1,0,%2" : "=m" (*addr) :
+			      "r" (val), "r" (addr));
+}
+
+extern inline void out_be16(volatile unsigned short *addr, int val)
+{
+	__asm__ __volatile__("sth%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
+}
+
+extern inline unsigned in_le32(volatile unsigned *addr)
+{
+	unsigned ret;
+
+	__asm__ __volatile__("eieio; lwbrx %0,0,%1" : "=r" (ret) :
+			     "r" (addr), "m" (*addr));
+	return ret;
+}
+
+extern inline unsigned in_be32(volatile unsigned *addr)
+{
+	unsigned ret;
+
+	__asm__ __volatile__("eieio; lwz%U1%X1 %0,%1" : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+extern inline void out_le32(volatile unsigned *addr, int val)
+{
+	__asm__ __volatile__("stwbrx %1,0,%2" : "=m" (*addr) :
+			     "r" (val), "r" (addr));
+}
+
+extern inline void out_be32(volatile unsigned *addr, int val)
+{
+	__asm__ __volatile__("stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
+}
+
+#ifdef CONFIG_PPC_EEH
+#include <asm/eeh.h>
+#endif
+
+#ifndef CONFIG_PPC_ISERIES 
+static inline u8 _inb(unsigned long port) {
+	if (IS_MAPPED_VADDR(port))
+		return readb((void *)port);
+	else if (_IO_BASE)
+		return in_8((u8 *)((port)+_IO_BASE));
+	else
+		return 0xff;
+}
+static inline void _outb(u8 val, unsigned long port) {
+	if (IS_MAPPED_VADDR(port))
+		return writeb(val, (void *)port);
+	else if (_IO_BASE)
+		out_8((u8 *)((port)+_IO_BASE), val);
+}
+static inline u16 _inw(unsigned long port) {
+	if (IS_MAPPED_VADDR(port))
+		return readw((void *)port);
+	else if (_IO_BASE)
+		return in_le16((u16 *)((port)+_IO_BASE));
+	else
+		return 0xffff;
+}
+static inline void _outw(u16 val, unsigned long port) {
+	if (IS_MAPPED_VADDR(port))
+		return writew(val, (void *)port);
+	else if (_IO_BASE)
+		out_le16((u16 *)((port)+_IO_BASE), val);
+}
+static inline u32 _inl(unsigned long port) {
+	if (IS_MAPPED_VADDR(port))
+		return readl((void *)port);
+	else if (_IO_BASE)
+		return in_le32((u32 *)((port)+_IO_BASE));
+	else
+		return 0xffffffff;
+}
+static inline void _outl(u32 val, unsigned long port) {
+	if (IS_MAPPED_VADDR(port))
+		return writel(val, (void *)port);
+	else if (_IO_BASE)
+		out_le32((u32 *)((port)+_IO_BASE), val);
+}
+#endif
+
+#ifdef __KERNEL__
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+#ifndef CONFIG_PPC_ISERIES 
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+#endif
+	return retval;
+}
+
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)		do { } while (0)
+#define dma_cache_wback(_start,_size)		do { } while (0)
+#define dma_cache_wback_inv(_start,_size)	do { } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _PPC64_IO_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ioctl.h linux-2.4.19-pre5/include/asm-ppc64/ioctl.h
--- linux-2.4.19-pre4/include/asm-ppc64/ioctl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ioctl.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,64 @@
+#ifndef _PPC64_IOCTL_H
+#define _PPC64_IOCTL_H
+
+
+/*
+ * This was copied from the alpha as it's a bit cleaner there.
+ *                         -- Cort
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define _IOC_NRBITS	8
+#define _IOC_TYPEBITS	8
+#define _IOC_SIZEBITS	13
+#define _IOC_DIRBITS	3
+
+#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT	0
+#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit.
+ * And this turns out useful to catch old ioctl numbers in header
+ * files for us.
+ */
+#define _IOC_NONE	1U
+#define _IOC_READ	2U
+#define _IOC_WRITE	4U
+
+#define _IOC(dir,type,nr,size) \
+	(((dir)  << _IOC_DIRSHIFT) | \
+	 ((type) << _IOC_TYPESHIFT) | \
+	 ((nr)   << _IOC_NRSHIFT) | \
+	 ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode them.. */
+#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* various drivers, such as the pcmcia stuff, need these... */
+#define IOC_IN		(_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT		(_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT	(_IOC_SIZESHIFT)
+
+#endif /* _PPC64_IOCTL_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ioctls.h linux-2.4.19-pre5/include/asm-ppc64/ioctls.h
--- linux-2.4.19-pre4/include/asm-ppc64/ioctls.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ioctls.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,115 @@
+#ifndef _ASM_PPC64_IOCTLS_H
+#define _ASM_PPC64_IOCTLS_H
+
+/*
+ * 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 <asm/ioctl.h>
+
+#define FIOCLEX		_IO('f', 1)
+#define FIONCLEX	_IO('f', 2)
+#define FIOASYNC	_IOW('f', 125, int)
+#define FIONBIO		_IOW('f', 126, int)
+#define FIONREAD	_IOR('f', 127, int)
+#define TIOCINQ		FIONREAD
+#define FIOQSIZE        _IOR('f', 128, loff_t)
+
+#define TIOCGETP	_IOR('t', 8, struct sgttyb)
+#define TIOCSETP	_IOW('t', 9, struct sgttyb)
+#define TIOCSETN	_IOW('t', 10, struct sgttyb)	/* TIOCSETP wo flush */
+
+#define TIOCSETC	_IOW('t', 17, struct tchars)
+#define TIOCGETC	_IOR('t', 18, struct tchars)
+#define TCGETS		_IOR('t', 19, struct termios)
+#define TCSETS		_IOW('t', 20, struct termios)
+#define TCSETSW		_IOW('t', 21, struct termios)
+#define TCSETSF		_IOW('t', 22, struct termios)
+
+#define TCGETA		_IOR('t', 23, struct termio)
+#define TCSETA		_IOW('t', 24, struct termio)
+#define TCSETAW		_IOW('t', 25, struct termio)
+#define TCSETAF		_IOW('t', 28, struct termio)
+
+#define TCSBRK		_IO('t', 29)
+#define TCXONC		_IO('t', 30)
+#define TCFLSH		_IO('t', 31)
+
+#define TIOCSWINSZ	_IOW('t', 103, struct winsize)
+#define TIOCGWINSZ	_IOR('t', 104, struct winsize)
+#define	TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
+#define	TIOCSTOP	_IO('t', 111)		/* stop output, like ^S */
+#define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
+
+#define TIOCGLTC	_IOR('t', 116, struct ltchars)
+#define TIOCSLTC	_IOW('t', 117, struct ltchars)
+#define TIOCSPGRP	_IOW('t', 118, int)
+#define TIOCGPGRP	_IOR('t', 119, int)
+
+#define TIOCEXCL	0x540C
+#define TIOCNXCL	0x540D
+#define TIOCSCTTY	0x540E
+
+#define TIOCSTI		0x5412
+#define TIOCMGET	0x5415
+#define TIOCMBIS	0x5416
+#define TIOCMBIC	0x5417
+#define TIOCMSET	0x5418
+# define TIOCM_LE	0x001
+# define TIOCM_DTR	0x002
+# define TIOCM_RTS	0x004
+# define TIOCM_ST	0x008
+# define TIOCM_SR	0x010
+# define TIOCM_CTS	0x020
+# define TIOCM_CAR	0x040
+# define TIOCM_RNG	0x080
+# define TIOCM_DSR	0x100
+# define TIOCM_CD	TIOCM_CAR
+# define TIOCM_RI	TIOCM_RNG
+
+#define TIOCGSOFTCAR	0x5419
+#define TIOCSSOFTCAR	0x541A
+#define TIOCLINUX	0x541C
+#define TIOCCONS	0x541D
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TIOCPKT		0x5420
+# define TIOCPKT_DATA		 0
+# define TIOCPKT_FLUSHREAD	 1
+# define TIOCPKT_FLUSHWRITE	 2
+# define TIOCPKT_STOP		 4
+# define TIOCPKT_START		 8
+# define TIOCPKT_NOSTOP		16
+# define TIOCPKT_DOSTOP		32
+
+
+#define TIOCNOTTY	0x5422
+#define TIOCSETD	0x5423
+#define TIOCGETD	0x5424
+#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TIOCSBRK	0x5427  /* BSD compatibility */
+#define TIOCCBRK	0x5428  /* BSD compatibility */
+#define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TIOCSERCONFIG	0x5453
+#define TIOCSERGWILD	0x5454
+#define TIOCSERSWILD	0x5455
+#define TIOCGLCKTRMIOS	0x5456
+#define TIOCSLCKTRMIOS	0x5457
+#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+
+#endif /* _ASM_PPC64_IOCTLS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ipc.h linux-2.4.19-pre5/include/asm-ppc64/ipc.h
--- linux-2.4.19-pre4/include/asm-ppc64/ipc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ipc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,33 @@
+#ifndef __PPC64_IPC_H__
+#define __PPC64_IPC_H__
+
+/* 
+ * These are used to wrap system calls on PowerPC.
+ *
+ * See arch/ppc/kernel/syscalls.c for ugly details..
+ *
+ * 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.
+ */
+struct ipc_kludge {
+	u32 msgp;
+	s32 msgtyp;
+};
+
+#define SEMOP		 1
+#define SEMGET		 2
+#define SEMCTL		 3
+#define MSGSND		11
+#define MSGRCV		12
+#define MSGGET		13
+#define MSGCTL		14
+#define SHMAT		21
+#define SHMDT		22
+#define SHMGET		23
+#define SHMCTL		24
+
+#define IPCCALL(version,op)	((version)<<16 | (op))
+
+#endif /* __PPC64_IPC_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ipcbuf.h linux-2.4.19-pre5/include/asm-ppc64/ipcbuf.h
--- linux-2.4.19-pre4/include/asm-ppc64/ipcbuf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ipcbuf.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,28 @@
+#ifndef __PPC64_IPCBUF_H__
+#define __PPC64_IPCBUF_H__
+
+/*
+ * The ipc64_perm structure for the PPC is identical to kern_ipc_perm
+ * as we have always had 32-bit UIDs and GIDs in the kernel.
+ *
+ * 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.
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t	key;
+	__kernel_uid_t	uid;
+	__kernel_gid_t	gid;
+	__kernel_uid_t	cuid;
+	__kernel_gid_t	cgid;
+	__kernel_mode_t	mode;
+	unsigned int	seq;
+	unsigned int	__pad1;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
+
+#endif /* __PPC64_IPCBUF_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/irq.h linux-2.4.19-pre5/include/asm-ppc64/irq.h
--- linux-2.4.19-pre4/include/asm-ppc64/irq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/irq.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,55 @@
+#ifdef __KERNEL__
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+/*
+ * 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 <asm/atomic.h>
+
+extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
+extern void enable_irq(unsigned int);
+
+/*
+ * this is the maximum number of virtual irqs we will use.
+ */
+#define NR_IRQS			512
+
+#define NUM_8259_INTERRUPTS	16
+
+/* Interrupt numbers are virtual in case they are sparsely
+ * distributed by the hardware.
+ */
+#define NR_HW_IRQS		8192
+extern unsigned short real_irq_to_virt_map[NR_HW_IRQS];
+extern unsigned short virt_irq_to_real_map[NR_IRQS];
+/* Create a mapping for a real_irq if it doesn't already exist.
+ * Return the virtual irq as a convenience.
+ */
+unsigned long virt_irq_create_mapping(unsigned long real_irq);
+
+/* These funcs map irqs between real and virtual */
+static inline unsigned long real_irq_to_virt(unsigned long real_irq) {
+	return real_irq_to_virt_map[real_irq];
+}
+static inline unsigned long virt_irq_to_real(unsigned long virt_irq) {
+	return virt_irq_to_real_map[virt_irq];
+}
+
+/*
+ * This gets called from serial.c, which is now used on
+ * powermacs as well as prep/chrp boxes.
+ * Prep and chrp both have cascaded 8259 PICs.
+ */
+static __inline__ int irq_cannonicalize(int irq)
+{
+	return irq;
+}
+
+#endif /* _ASM_IRQ_H */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/keyboard.h linux-2.4.19-pre5/include/asm-ppc64/keyboard.h
--- linux-2.4.19-pre4/include/asm-ppc64/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/keyboard.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,115 @@
+/*
+ *  linux/include/asm-ppc/keyboard.h
+ *
+ *  Created 3 Nov 1996 by Geert Uytterhoeven
+ *  Modified for Power Macintosh by Paul Mackerras
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * This file contains the ppc architecture specific keyboard definitions -
+ * like the intel pc for prep systems, different for power macs.
+ */
+
+#ifndef __ASMPPC64_KEYBOARD_H
+#define __ASMPPC64_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#include <linux/adb.h>
+#include <asm/machdep.h>
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/kd.h>
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ			1
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+#define INIT_KBD
+
+static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	if ( ppc_md.kbd_setkeycode )
+		return ppc_md.kbd_setkeycode(scancode, keycode);
+	else
+		return 0;
+}
+  
+static inline int kbd_getkeycode(unsigned int scancode)
+{
+	if ( ppc_md.kbd_getkeycode )
+		return ppc_md.kbd_getkeycode(scancode);
+	else
+		return 0;
+}
+  
+static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
+				char raw_mode)
+{
+	if ( ppc_md.kbd_translate )
+		return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+	else
+		return 0;
+}
+  
+static inline int kbd_unexpected_up(unsigned char keycode)
+{
+	if ( ppc_md.kbd_unexpected_up )
+		return ppc_md.kbd_unexpected_up(keycode);
+	else
+		return 0;
+}
+  
+static inline void kbd_leds(unsigned char leds)
+{
+	if ( ppc_md.kbd_leds )
+		ppc_md.kbd_leds(leds);
+}
+
+static inline void kbd_init_hw(void)
+{
+	if ( ppc_md.kbd_init_hw )
+		ppc_md.kbd_init_hw();
+}
+
+#define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
+
+extern unsigned long SYSRQ_KEY;
+#define E1_PAUSE	119		/* PAUSE key */
+
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+static inline int kbd_read_status(void) {
+	int ret = inb(0x64);
+	return (ret == 0xff) ? 0 : ret;	/* translate float to bad status. */
+}
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define aux_request_irq(hand, dev_id)					\
+	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMPPC64_KEYBOARD_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/kgdb.h linux-2.4.19-pre5/include/asm-ppc64/kgdb.h
--- linux-2.4.19-pre4/include/asm-ppc64/kgdb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/kgdb.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,53 @@
+/* 
+ * kgdb.h: Defines and declarations for serial line source level
+ *         remote debugging of the Linux kernel using gdb.
+ *
+ * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.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.
+ */
+#ifndef _PPC64_KGDB_H
+#define _PPC64_KGDB_H
+
+#ifndef __ASSEMBLY__
+/* To initialize the serial, first thing called */
+extern void zs_kgdb_hook(int tty_num);
+/* To init the kgdb engine. (called by serial hook)*/
+extern void set_debug_traps(void);
+
+/* To enter the debugger explicitly. */
+extern void breakpoint(void);
+
+/* For taking exceptions
+ * these are defined in traps.c
+ */
+extern void (*debugger)(struct pt_regs *regs);
+extern int (*debugger_bpt)(struct pt_regs *regs);
+extern int (*debugger_sstep)(struct pt_regs *regs);
+extern int (*debugger_iabr_match)(struct pt_regs *regs);
+extern int (*debugger_dabr_match)(struct pt_regs *regs);
+extern void (*debugger_fault_handler)(struct pt_regs *regs);
+
+/* What we bring to the party */
+int kgdb_bpt(struct pt_regs *regs);
+int kgdb_sstep(struct pt_regs *regs);
+void kgdb(struct pt_regs *regs);
+int kgdb_iabr_match(struct pt_regs *regs);
+int kgdb_dabr_match(struct pt_regs *regs);
+static void kgdb_fault_handler(struct pt_regs *regs);
+static void handle_exception (struct pt_regs *regs);
+
+/*
+ * external low-level support routines (ie macserial.c)
+ */
+extern void kgdb_interruptible(int); /* control interrupts from serial */
+extern void putDebugChar(char);   /* write a single character      */
+extern char getDebugChar(void);   /* read and return a single char */
+
+#endif /* !(__ASSEMBLY__) */
+#endif /* !(_PPC64_KGDB_H) */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/linux_logo.h linux-2.4.19-pre5/include/asm-ppc64/linux_logo.h
--- linux-2.4.19-pre4/include/asm-ppc64/linux_logo.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/linux_logo.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,46 @@
+/*
+ * include/asm-ppc64/linux_logo.h: A linux logo to be displayed on boot
+ * (pinched from the sparc port).
+ *
+ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * values have to start from 0x20
+ * (i.e. linux_logo_{red,green,blue}[0] is color 0x20)
+ *
+ * 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/init.h>
+
+#define linux_logo_banner "Linux/PPC-64 version " UTS_RELEASE
+
+#define LINUX_LOGO_HEIGHT	80
+#define LINUX_LOGO_WIDTH	80
+#define LINUX_LOGO_COLORS	214
+
+#ifdef INCLUDE_LINUX_LOGO_DATA
+
+#define INCLUDE_LINUX_LOGOBW
+#define INCLUDE_LINUX_LOGO16
+#include <linux/linux_logo.h>
+
+#else
+
+/* prototypes only */
+extern unsigned char linux_logo_red[];
+extern unsigned char linux_logo_green[];
+extern unsigned char linux_logo_blue[];
+extern unsigned char linux_logo[];
+extern unsigned char linux_logo_bw[];
+extern unsigned char linux_logo16_red[];
+extern unsigned char linux_logo16_green[];
+extern unsigned char linux_logo16_blue[];
+extern unsigned char linux_logo16[];
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/lmb.h linux-2.4.19-pre5/include/asm-ppc64/lmb.h
--- linux-2.4.19-pre4/include/asm-ppc64/lmb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/lmb.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,107 @@
+#ifndef _PPC64_LMB_H
+#define _PPC64_LMB_H
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 2001 Peter Bergner, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/prom.h>
+
+extern unsigned long reloc_offset(void);
+
+#define MAX_LMB_REGIONS 32
+
+union lmb_reg_property { 
+	struct reg_property32 addr32[MAX_LMB_REGIONS];
+	struct reg_property64 addr64[MAX_LMB_REGIONS];
+};
+
+#define LMB_MEMORY_AREA	1
+#define LMB_IO_AREA	2
+
+struct lmb_property {
+	unsigned long base;
+	unsigned long physbase;
+	unsigned long size;
+	unsigned long type;
+};
+
+struct lmb_region {
+	unsigned long cnt;
+	unsigned long size;
+	unsigned long iosize;
+	unsigned long lcd_size;		/* Least Common Denominator */
+	struct lmb_property region[MAX_LMB_REGIONS+1];
+};
+
+struct lmb {
+	unsigned long debug;
+	struct lmb_region memory;
+	struct lmb_region reserved;
+};
+
+extern struct lmb lmb;
+
+extern void lmb_init(void);
+extern void lmb_analyze(void);
+extern long lmb_add(unsigned long, unsigned long);
+extern long lmb_add_io(unsigned long base, unsigned long size);
+extern long lmb_reserve(unsigned long, unsigned long);
+extern unsigned long lmb_alloc(unsigned long, unsigned long);
+extern unsigned long lmb_phys_mem_size(void);
+extern unsigned long lmb_end_of_DRAM(void);
+extern unsigned long lmb_abs_to_phys(unsigned long);
+extern void lmb_dump(char *);
+
+static inline unsigned long
+lmb_addrs_overlap(unsigned long base1, unsigned long size1,
+                  unsigned long base2, unsigned long size2)
+{
+        return ((base1 < (base2+size2)) && (base2 < (base1+size1)));
+}
+
+static inline long
+lmb_regions_overlap(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
+{
+	unsigned long base1 = rgn->region[r1].base;
+        unsigned long size1 = rgn->region[r1].size;
+	unsigned long base2 = rgn->region[r2].base;
+        unsigned long size2 = rgn->region[r2].size;
+
+	return lmb_addrs_overlap(base1,size1,base2,size2);
+}
+
+static inline long
+lmb_addrs_adjacent(unsigned long base1, unsigned long size1,
+		   unsigned long base2, unsigned long size2)
+{
+	if ( base2 == base1 + size1 ) {
+		return 1;
+	} else if ( base1 == base2 + size2 ) {
+		return -1;
+	}
+	return 0;
+}
+
+static inline long
+lmb_regions_adjacent(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
+{
+	unsigned long base1 = rgn->region[r1].base;
+        unsigned long size1 = rgn->region[r1].size;
+        unsigned long type1 = rgn->region[r1].type;
+	unsigned long base2 = rgn->region[r2].base;
+        unsigned long size2 = rgn->region[r2].size;
+        unsigned long type2 = rgn->region[r2].type;
+
+	return (type1 == type2) && lmb_addrs_adjacent(base1,size1,base2,size2);
+}
+
+#endif /* _PPC64_LMB_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/machdep.h linux-2.4.19-pre5/include/asm-ppc64/machdep.h
--- linux-2.4.19-pre4/include/asm-ppc64/machdep.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/machdep.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,164 @@
+#ifdef __KERNEL__
+#ifndef _PPC_MACHDEP_H
+#define _PPC_MACHDEP_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/seq_file.h>
+
+struct pt_regs;
+struct pci_bus;	
+struct pci_dev;
+struct kbd_repeat;
+struct device_node;
+struct TceTable;
+struct rtc_time;
+
+struct machdep_calls {
+	/* High use functions in the first cachelines, low use functions
+	 * follow.  DRENG collect profile data.
+	 */
+	void            (*hpte_invalidate)(unsigned long slot);
+
+	void            (*hpte_updatepp)(long slot, 
+					 unsigned long newpp, 
+					 unsigned long va);
+	void            (*hpte_updateboltedpp)(unsigned long newpp, 
+					       unsigned long ea);
+	unsigned long	(*hpte_getword0)(unsigned long slot);
+
+	long		(*hpte_find)( unsigned long vpn );
+
+	long		(*hpte_selectslot)(unsigned long vpn); 
+
+	void		(*hpte_create_valid)(unsigned long slot,
+					     unsigned long vpn,
+					     unsigned long prpn,
+					     unsigned hash, 
+					     void * ptep,
+					     unsigned hpteflags, 
+					     unsigned bolted);
+	void		(*tce_build)(struct TceTable * tbl,
+				     long tcenum,
+				     unsigned long uaddr,
+				     int direction);
+	void		(*tce_free)(struct TceTable *tbl,
+				    dma_addr_t dma_addr, 
+				    unsigned order,
+				    unsigned numPages);
+
+	void		(*smp_message_pass)(int target,
+					    int msg, 
+					    unsigned long data,
+					    int wait);
+	int		(*smp_probe)(void);
+	void		(*smp_kick_cpu)(int nr);
+	void		(*smp_setup_cpu)(int nr);
+
+	void		(*setup_arch)(void);
+	/* Optional, may be NULL. */
+	void		(*setup_residual)(struct seq_file *m, int cpu_id);
+	/* Optional, may be NULL. */
+	void		(*get_cpuinfo)(struct seq_file *m);
+	/* Optional, may be NULL. */
+	unsigned int	(*irq_cannonicalize)(unsigned int irq);
+	void		(*init_IRQ)(void);
+	void		(*init_ras_IRQ)(void);
+	int		(*get_irq)(struct pt_regs *);
+	void		(*post_irq)( struct pt_regs *, int );
+	
+	/* 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);
+
+	long		(*time_init)(void); /* Optional, may be NULL */
+	int		(*set_rtc_time)(struct rtc_time *);
+	void		(*get_rtc_time)(struct rtc_time *);
+	void		(*get_boot_time)(struct rtc_time *);
+	void		(*calibrate_decr)(void);
+
+  	void		(*progress)(char *, unsigned short);
+
+	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 	*ppc_kbd_sysrq_xlate;
+#endif
+
+	/* Debug interface.  Low level I/O to some terminal device */
+	void		(*udbg_putc)(unsigned char c);
+	unsigned char	(*udbg_getc)(void);
+	int		(*udbg_getc_poll)(void);
+
+	/* PCI interfaces */
+	int (*pcibios_read_config_byte)(struct device_node *dn, int offset, u8 *val);
+	int (*pcibios_read_config_word)(struct device_node *dn, int offset, u16 *val);
+	int (*pcibios_read_config_dword)(struct device_node *dn, int offset, u32 *val);
+	int (*pcibios_write_config_byte)(struct device_node *dn, int offset, u8 val);
+	int (*pcibios_write_config_word)(struct device_node *dn, int offset, u16 val);
+	int (*pcibios_write_config_dword)(struct device_node *dn, int offset, u32 val);
+
+	/* Called after scanning the bus, before allocating
+	 * resources
+	 */
+	void (*pcibios_fixup)(void);
+
+       /* Called for each PCI bus in the system
+        * when it's probed
+        */
+	void (*pcibios_fixup_bus)(struct pci_bus *);
+
+       /* Called when pci_enable_device() is called (initial=0) or
+        * when a device with no assigned resource is found (initial=1).
+        * Returns 0 to allow assignement/enabling of the device
+        */
+        int  (*pcibios_enable_device_hook)(struct pci_dev *, int initial);
+
+	void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical);
+	void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn);
+	int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn);
+
+	/* this is for modules, since _machine can be a define -- Cort */
+	int ppc_machine;
+};
+
+extern struct machdep_calls ppc_md;
+extern char cmd_line[512];
+
+extern void setup_pci_ptrs(void);
+
+/*
+ * Power macintoshes have either a CUDA or a PMU controlling
+ * system reset, power, NVRAM, RTC.
+ */
+typedef enum sys_ctrler_kind {
+	SYS_CTRLER_UNKNOWN = 0,
+	SYS_CTRLER_CUDA = 1,
+	SYS_CTRLER_PMU = 2,
+} sys_ctrler_t;
+
+extern sys_ctrler_t sys_ctrler;
+
+#endif /* _PPC_MACHDEP_H */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/mc146818rtc.h linux-2.4.19-pre5/include/asm-ppc64/mc146818rtc.h
--- linux-2.4.19-pre4/include/asm-ppc64/mc146818rtc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/mc146818rtc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,32 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ *
+ * 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.
+ */
+#ifndef __ASM_PPC64_MC146818RTC_H
+#define __ASM_PPC64_MC146818RTC_H
+
+#include <asm/io.h>
+
+#ifndef RTC_PORT
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_ALWAYS_BCD	1	/* RTC operates in binary mode */
+#endif
+
+/*
+ * The yet supported machines all access the RTC index register via
+ * an ISA port access but the way to access the date register differs ...
+ */
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+
+#endif /* __ASM_PPC64_MC146818RTC_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/md.h linux-2.4.19-pre5/include/asm-ppc64/md.h
--- linux-2.4.19-pre4/include/asm-ppc64/md.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/md.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,17 @@
+/* 
+ * md.h: High speed xor_block operation for RAID4/5 
+ *
+ * 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.
+ */
+ 
+#ifndef __ASM_MD_H
+#define __ASM_MD_H
+
+/* #define HAVE_ARCH_XORBLOCK */
+
+#define MD_XORBLOCK_ALIGNMENT	sizeof(long)
+
+#endif /* __ASM_MD_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/memory.h linux-2.4.19-pre5/include/asm-ppc64/memory.h
--- linux-2.4.19-pre4/include/asm-ppc64/memory.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/memory.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,44 @@
+#ifndef _ASM_PPC64_MEMORY_H_ 
+#define _ASM_PPC64_MEMORY_H_ 
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+
+/*
+ * Arguably the bitops and *xchg operations don't imply any memory barrier
+ * or SMP ordering, but in fact a lot of drivers expect them to imply
+ * both, since they do on x86 cpus.
+ */
+#ifdef CONFIG_SMP
+#define EIEIO_ON_SMP	"eieio\n"
+#define ISYNC_ON_SMP	"\n\tisync"
+#else
+#define EIEIO_ON_SMP
+#define ISYNC_ON_SMP
+#endif
+
+static inline void eieio(void)
+{
+	__asm__ __volatile__ ("eieio" : : : "memory");
+}
+
+static inline void isync(void)
+{
+	__asm__ __volatile__ ("isync" : : : "memory");
+}
+
+#ifdef CONFIG_SMP
+#define eieio_on_smp()	eieio()
+#define isync_on_smp()	isync()
+#else
+#define eieio_on_smp()	__asm__ __volatile__("": : :"memory")
+#define isync_on_smp()	__asm__ __volatile__("": : :"memory")
+#endif
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/mman.h linux-2.4.19-pre5/include/asm-ppc64/mman.h
--- linux-2.4.19-pre4/include/asm-ppc64/mman.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/mman.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,45 @@
+#ifndef __PPC64_MMAN_H__
+#define __PPC64_MMAN_H__
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define PROT_READ	0x1		/* page can be read */
+#define PROT_WRITE	0x2		/* page can be written */
+#define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_NONE	0x0		/* page can not be accessed */
+
+#define MAP_SHARED	0x01		/* Share changes */
+#define MAP_PRIVATE	0x02		/* Changes are private */
+#define MAP_TYPE	0x0f		/* Mask for type of mapping */
+#define MAP_FIXED	0x10		/* Interpret addr exactly */
+#define MAP_ANONYMOUS	0x20		/* don't use a file */
+#define MAP_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
+#define MAP_NORESERVE   0x40            /* don't reserve swap pages */
+
+#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+
+#define MS_ASYNC	1		/* sync memory asynchronously */
+#define MS_INVALIDATE	2		/* invalidate the caches */
+#define MS_SYNC		4		/* synchronous memory sync */
+
+#define MCL_CURRENT     0x2000          /* lock all currently mapped pages */
+#define MCL_FUTURE      0x4000          /* lock all additions to address space */
+
+#define MADV_NORMAL	0x0		/* default page-in behavior */
+#define MADV_RANDOM	0x1		/* page-in minimum required */
+#define MADV_SEQUENTIAL	0x2		/* read-ahead aggressively */
+#define MADV_WILLNEED	0x3		/* pre-fault pages */
+#define MADV_DONTNEED	0x4		/* discard these pages */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
+
+#endif /* __PPC64_MMAN_H__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/mmu.h linux-2.4.19-pre5/include/asm-ppc64/mmu.h
--- linux-2.4.19-pre4/include/asm-ppc64/mmu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/mmu.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,384 @@
+/*
+ * PowerPC memory management structures
+ *
+ * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
+ *   PPC64 rework.
+ *
+ * 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.
+ */
+
+#ifndef _PPC64_MMU_H_
+#define _PPC64_MMU_H_
+
+#ifndef __ASSEMBLY__
+
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
+
+/*
+ * Define the size of the cache used for segment table entries.  The first
+ * entry is used as a cache pointer, therefore the actual number of entries
+ * stored is one less than defined here.  Do not change this value without
+ * considering the impact it will have on the layout of the paca in Paca.h.
+ */
+#define STAB_CACHE_SIZE 16
+
+/*
+ * Hardware Segment Lookaside Buffer Entry
+ * This structure has been padded out to two 64b doublewords (actual SLBE's are
+ * 94 bits).  This padding facilites use by the segment management
+ * instructions.
+ */
+typedef struct {
+	unsigned long esid: 36; /* Effective segment ID */
+	unsigned long resv0:20; /* Reserved */
+	unsigned long v:     1; /* Entry valid (v=1) or invalid */
+	unsigned long resv1: 1; /* Reserved */
+	unsigned long ks:    1; /* Supervisor (privileged) state storage key */
+	unsigned long kp:    1; /* Problem state storage key */
+	unsigned long n:     1; /* No-execute if n=1 */
+	unsigned long resv2: 3; /* padding to a 64b boundary */
+} ste_dword0;
+
+typedef struct {
+	unsigned long vsid: 52; /* Virtual segment ID */
+	unsigned long resv0:12; /* Padding to a 64b boundary */
+} ste_dword1;
+
+typedef struct _STE {
+	union {
+		unsigned long dword0;
+		ste_dword0    dw0;
+	} dw0;
+
+	union {
+		unsigned long dword1;
+		ste_dword1    dw1;
+	} dw1;
+} STE;
+
+typedef struct {
+	unsigned long esid: 36; /* Effective segment ID */
+	unsigned long v:     1; /* Entry valid (v=1) or invalid */
+	unsigned long null1:15; /* padding to a 64b boundary */
+	unsigned long index:12; /* Index to select SLB entry. Used by slbmte */
+} slb_dword0;
+
+typedef struct {
+	unsigned long vsid: 52; /* Virtual segment ID */
+	unsigned long ks:    1; /* Supervisor (privileged) state storage key */
+	unsigned long kp:    1; /* Problem state storage key */
+	unsigned long n:     1; /* No-execute if n=1 */
+	unsigned long l:     1; /* Virt pages are large (l=1) or 4KB (l=0) */
+	unsigned long c:     1; /* Class */
+	unsigned long resv0: 7; /* Padding to a 64b boundary */
+} slb_dword1;
+
+typedef struct _SLBE {
+	union {
+		unsigned long dword0;
+		slb_dword0    dw0;
+	} dw0;
+
+	union {
+		unsigned long dword1;
+		slb_dword1    dw1;
+	} dw1;
+} SLBE;
+
+/*
+ * This structure is used in Paca.h where the layout depends on the 
+ * size being 24B.
+ */
+typedef struct {
+        unsigned long   real;
+        unsigned long   virt;
+        unsigned long   next_round_robin;
+} STAB;
+
+/* Hardware Page Table Entry */
+
+#define HPTES_PER_GROUP 8
+
+typedef struct {
+	unsigned long avpn:57; /* vsid | api == avpn  */
+	unsigned long :     2; /* Software use */
+	unsigned long bolted: 1; /* HPTE is "bolted" */
+	unsigned long :     1; /* Software use */
+  unsigned long l:    1; /* Virtual page is large (L=1) or 4 KB (L=0) */
+	unsigned long h:    1; /* Hash function identifier */
+	unsigned long v:    1; /* Valid (v=1) or invalid (v=0) */
+} Hpte_dword0;
+
+typedef struct {
+	unsigned long :     6; /* unused - padding */
+	unsigned long ac:   1; /* Address compare */
+	unsigned long r:    1; /* Referenced */
+	unsigned long c:    1; /* Changed */
+	unsigned long w:	1; /* Write-thru cache mode */
+	unsigned long i:	1; /* Cache inhibited */
+	unsigned long m:	1; /* Memory coherence required */
+	unsigned long g:	1; /* Guarded */
+	unsigned long n:	1; /* No-execute */
+	unsigned long pp:   2; /* Page protection bits 1:2 */
+} Hpte_flags;
+
+typedef struct {
+	unsigned long pp0:  1; /* Page protection bit 0 */
+	unsigned long :     1; /* Reserved */
+	unsigned long rpn: 50; /* Real page number */
+	unsigned long :     2; /* Reserved */
+	unsigned long ac:   1; /* Address compare */ 
+	unsigned long r:    1; /* Referenced */
+	unsigned long c:    1; /* Changed */
+	unsigned long w:	1; /* Write-thru cache mode */
+	unsigned long i:	1; /* Cache inhibited */
+	unsigned long m:	1; /* Memory coherence required */
+	unsigned long g:	1; /* Guarded */
+	unsigned long n:	1; /* No-execute */
+	unsigned long pp:	2; /* Page protection bits 1:2 */
+} Hpte_dword1;
+
+typedef struct {
+	char padding[6];	   	/* padding */
+	unsigned long :       6;	/* padding */ 
+	unsigned long flags: 10;	/* HPTE flags */
+} Hpte_dword1_flags;
+
+typedef struct _HPTE {
+	union {
+		unsigned long dword0;
+		Hpte_dword0   dw0;
+	} dw0;
+
+	union {
+		unsigned long dword1;
+		struct {
+			unsigned long pp0:  1; /* Page protection bit 0 */
+			unsigned long ts:   1; /* Tag set bit */ 
+			unsigned long rpn: 50; /* Real page number */
+			unsigned long :     2; /* Unused */
+			unsigned long ac:   1; /* Address compare bit */
+			unsigned long r:    1; /* Referenced */
+			unsigned long c:    1; /* Changed */
+			unsigned long w:    1; /* Write-thru cache mode */
+			unsigned long i:    1; /* Cache inhibited */
+			unsigned long m:    1; /* Memory coherence */
+			unsigned long g:    1; /* Guarded */
+			unsigned long n:    1; /* No-execute page if N=1 */
+			unsigned long pp:   2; /* Page protection bit 1:2 */
+		} dw1;
+	} dw1;
+} HPTE; 
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+/* pp0 will always be 0 for linux     */
+#define PP_RWXX	0	/* Supervisor read/write, User none */
+#define PP_RWRX 1	/* Supervisor read/write, User read */
+#define PP_RWRW 2	/* Supervisor read/write, User read/write */
+#define PP_RXRX 3	/* Supervisor read,       User read */
+
+
+typedef struct {
+	HPTE *		htab;
+	unsigned long	htab_num_ptegs;
+	unsigned long	htab_hash_mask;
+	unsigned long	next_round_robin;
+	unsigned long   last_kernel_address;
+} HTAB;
+
+extern HTAB htab_data;
+
+void invalidate_hpte( unsigned long slot );
+long select_hpte_slot( unsigned long vpn );
+void create_valid_hpte( unsigned long slot, unsigned long vpn,
+			unsigned long prpn, unsigned hash,
+			void * ptep, unsigned hpteflags,
+			unsigned bolted );
+
+#define PD_SHIFT (10+12)		/* Page directory */
+#define PD_MASK  0x02FF
+#define PT_SHIFT (12)			/* Page Table */
+#define PT_MASK  0x02FF
+
+static inline unsigned long hpt_hash(unsigned long vpn, int large)
+{
+	unsigned long vsid;
+	unsigned long page;
+
+	if (large) {
+		vsid = vpn >> 4;
+		page = vpn & 0xf;
+	} else {
+		vsid = vpn >> 16;
+		page = vpn & 0xffff;
+	}
+
+	return (vsid & 0x7fffffffff) ^ page;
+}
+
+#define PG_SHIFT (12)			/* Page Entry */
+
+extern __inline__ void _tlbie( unsigned long va )
+{
+	__asm__ __volatile__ ( " \n\
+		clrldi	%0,%0,16 \n\
+		ptesync		 \n\
+		tlbie	%0	 \n\
+		eieio		 \n\
+		tlbsync		 \n\
+		ptesync"
+		: : "r" (va) : "memory" );
+}
+ 
+#endif /* __ASSEMBLY__ */
+
+/* Block size masks */
+#define BL_128K	0x000
+#define BL_256K 0x001
+#define BL_512K 0x003
+#define BL_1M   0x007
+#define BL_2M   0x00F
+#define BL_4M   0x01F
+#define BL_8M   0x03F
+#define BL_16M  0x07F
+#define BL_32M  0x0FF
+#define BL_64M  0x1FF
+#define BL_128M 0x3FF
+#define BL_256M 0x7FF
+
+/* Used to set up SDR1 register */
+#define HASH_TABLE_SIZE_64K	0x00010000
+#define HASH_TABLE_SIZE_128K	0x00020000
+#define HASH_TABLE_SIZE_256K	0x00040000
+#define HASH_TABLE_SIZE_512K	0x00080000
+#define HASH_TABLE_SIZE_1M	0x00100000
+#define HASH_TABLE_SIZE_2M	0x00200000
+#define HASH_TABLE_SIZE_4M	0x00400000
+#define HASH_TABLE_MASK_64K	0x000   
+#define HASH_TABLE_MASK_128K	0x001   
+#define HASH_TABLE_MASK_256K	0x003   
+#define HASH_TABLE_MASK_512K	0x007
+#define HASH_TABLE_MASK_1M	0x00F   
+#define HASH_TABLE_MASK_2M	0x01F   
+#define HASH_TABLE_MASK_4M	0x03F   
+
+/* These are the Ks and Kp from the PowerPC books.  For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define MI_AP		786
+#define MI_Ks		0x80000000	/* Should not be set */
+#define MI_Kp		0x40000000	/* Should always be set */
+
+/* The effective page number register.  When read, contains the information
+ * about the last instruction TLB miss.  When MI_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define MI_EPN		787
+#define MI_EPNMASK	0xfffff000	/* Effective page number for entry */
+#define MI_EVALID	0x00000200	/* Entry is valid */
+#define MI_ASIDMASK	0x0000000f	/* ASID match value */
+					/* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the instruction TLB, it contains bits that get loaded into the
+ * TLB entry when the MI_RPN is written.
+ */
+#define MI_TWC		789
+#define MI_APG		0x000001e0	/* Access protection group (0) */
+#define MI_GUARDED	0x00000010	/* Guarded storage */
+#define MI_PSMASK	0x0000000c	/* Mask of page size bits */
+#define MI_PS8MEG	0x0000000c	/* 8M page size */
+#define MI_PS512K	0x00000004	/* 512K page size */
+#define MI_PS4K_16K	0x00000000	/* 4K or 16K page size */
+#define MI_SVALID	0x00000001	/* Segment entry is valid */
+					/* Reset value is undefined */
+
+/* Real page number.  Defined by the pte.  Writing this register
+ * causes a TLB entry to be created for the instruction TLB, using
+ * additional information from the MI_EPN, and MI_TWC registers.
+ */
+#define MI_RPN		790
+
+/* Define an RPN value for mapping kernel memory to large virtual
+ * pages for boot initialization.  This has real page number of 0,
+ * large page size, shared page, cache enabled, and valid.
+ * Also mark all subpages valid and write access.
+ */
+#define MI_BOOTINIT	0x000001fd
+
+#define MD_CTR		792	/* Data TLB control register */
+#define MD_GPM		0x80000000	/* Set domain manager mode */
+#define MD_PPM		0x40000000	/* Set subpage protection */
+#define MD_CIDEF	0x20000000	/* Set cache inhibit when MMU dis */
+#define MD_WTDEF	0x10000000	/* Set writethrough when MMU dis */
+#define MD_RSV4I	0x08000000	/* Reserve 4 TLB entries */
+#define MD_TWAM		0x04000000	/* Use 4K page hardware assist */
+#define MD_PPCS		0x02000000	/* Use MI_RPN prob/priv state */
+#define MD_IDXMASK	0x00001f00	/* TLB index to be loaded */
+#define MD_RESETVAL	0x04000000	/* Value of register at reset */
+
+#define M_CASID		793	/* Address space ID (context) to match */
+#define MC_ASIDMASK	0x0000000f	/* Bits used for ASID value */
+
+
+/* These are the Ks and Kp from the PowerPC books.  For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define MD_AP		794
+#define MD_Ks		0x80000000	/* Should not be set */
+#define MD_Kp		0x40000000	/* Should always be set */
+
+/* The effective page number register.  When read, contains the information
+ * about the last instruction TLB miss.  When MD_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define MD_EPN		795
+#define MD_EPNMASK	0xfffff000	/* Effective page number for entry */
+#define MD_EVALID	0x00000200	/* Entry is valid */
+#define MD_ASIDMASK	0x0000000f	/* ASID match value */
+					/* Reset value is undefined */
+
+/* The pointer to the base address of the first level page table.
+ * During a software tablewalk, reading this register provides the address
+ * of the entry associated with MD_EPN.
+ */
+#define M_TWB		796
+#define	M_L1TB		0xfffff000	/* Level 1 table base address */
+#define M_L1INDX	0x00000ffc	/* Level 1 index, when read */
+					/* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the data TLB, it contains bits that get loaded into the TLB entry
+ * when the MD_RPN is written.  It is also provides the hardware assist
+ * for finding the PTE address during software tablewalk.
+ */
+#define MD_TWC		797
+#define MD_L2TB		0xfffff000	/* Level 2 table base address */
+#define MD_L2INDX	0xfffffe00	/* Level 2 index (*pte), when read */
+#define MD_APG		0x000001e0	/* Access protection group (0) */
+#define MD_GUARDED	0x00000010	/* Guarded storage */
+#define MD_PSMASK	0x0000000c	/* Mask of page size bits */
+#define MD_PS8MEG	0x0000000c	/* 8M page size */
+#define MD_PS512K	0x00000004	/* 512K page size */
+#define MD_PS4K_16K	0x00000000	/* 4K or 16K page size */
+#define MD_WT		0x00000002	/* Use writethrough page attribute */
+#define MD_SVALID	0x00000001	/* Segment entry is valid */
+					/* Reset value is undefined */
+
+
+/* Real page number.  Defined by the pte.  Writing this register
+ * causes a TLB entry to be created for the data TLB, using
+ * additional information from the MD_EPN, and MD_TWC registers.
+ */
+#define MD_RPN		798
+
+/* This is a temporary storage register that could be used to save
+ * a processor working register during a tablewalk.
+ */
+#define M_TW		799
+
+#endif /* _PPC64_MMU_H_ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/mmu_context.h linux-2.4.19-pre5/include/asm-ppc64/mmu_context.h
--- linux-2.4.19-pre4/include/asm-ppc64/mmu_context.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/mmu_context.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,193 @@
+#ifndef __PPC64_MMU_CONTEXT_H
+#define __PPC64_MMU_CONTEXT_H
+
+#include <linux/spinlock.h>	
+#include <linux/kernel.h>	
+#include <linux/mm.h>	
+#include <asm/mmu.h>	
+#include <asm/ppcdebug.h>	
+
+/*
+ * Copyright (C) 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define NO_CONTEXT		0
+#define FIRST_USER_CONTEXT	0x10    /* First 16 reserved for kernel */
+#define LAST_USER_CONTEXT	0x8000  /* Same as PID_MAX for now... */
+#define NUM_USER_CONTEXT	(LAST_USER_CONTEXT-FIRST_USER_CONTEXT)
+
+/* Choose whether we want to implement our context
+ * number allocator as a LIFO or FIFO queue.
+ */
+#if 1
+#define MMU_CONTEXT_LIFO
+#else
+#define MMU_CONTEXT_FIFO
+#endif
+
+struct mmu_context_queue_t {
+	spinlock_t lock;
+	long head;
+	long tail;
+	long size;
+	mm_context_t elements[LAST_USER_CONTEXT];
+};
+
+extern struct mmu_context_queue_t mmu_context_queue;
+
+static inline void
+enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+
+extern void flush_stab(void);
+
+/*
+ * The context number queue has underflowed.
+ * Meaning: we tried to push a context number that was freed
+ * back onto the context queue and the queue was already full.
+ */
+static inline void
+mmu_context_underflow(void)
+{
+	printk(KERN_DEBUG "mmu_context_underflow\n");
+	panic("mmu_context_underflow");
+}
+
+
+/*
+ * Set up the context for a new address space.
+ */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	long head, size;
+
+	spin_lock( &mmu_context_queue.lock );
+
+	if ( (size = mmu_context_queue.size) <= 0 ) {
+		spin_unlock( &mmu_context_queue.lock );
+		return -ENOMEM;
+	}
+
+	head = mmu_context_queue.head;
+	mm->context = mmu_context_queue.elements[head];
+
+	head = (head < LAST_USER_CONTEXT-1) ? head+1 : 0;
+	mmu_context_queue.head = head;
+	mmu_context_queue.size = size-1;
+
+	spin_unlock( &mmu_context_queue.lock );
+
+	return 0;
+}
+
+/*
+ * We're finished using the context for an address space.
+ */
+static inline void
+destroy_context(struct mm_struct *mm)
+{
+	long index, size = mmu_context_queue.size;
+
+	spin_lock( &mmu_context_queue.lock );
+
+	if ( (size = mmu_context_queue.size) >= NUM_USER_CONTEXT ) {
+		spin_unlock( &mmu_context_queue.lock );
+		mmu_context_underflow();
+	}
+
+#ifdef MMU_CONTEXT_LIFO
+	index = mmu_context_queue.head;
+	index = (index > 0) ? index-1 : LAST_USER_CONTEXT-1;
+	mmu_context_queue.head = index;
+#else
+	index = mmu_context_queue.tail;
+	index = (index < LAST_USER_CONTEXT-1) ? index+1 : 0;
+	mmu_context_queue.tail = index;
+#endif
+
+	mmu_context_queue.size = size+1;
+	mmu_context_queue.elements[index] = mm->context;
+
+	spin_unlock( &mmu_context_queue.lock );
+}
+
+
+/*
+ * switch_mm is the entry point called from the architecture independent
+ * code in kernel/sched.c
+ */
+static inline void
+switch_mm(struct mm_struct *prev, struct mm_struct *next,
+	  struct task_struct *tsk, int cpu)
+{
+	tsk->thread.pgdir = next->pgd;	/* cache the pgdir in the thread 
+					   maybe not needed any more */
+	flush_stab();
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static inline void
+activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
+{
+	current->thread.pgdir = mm->pgd;
+	flush_stab();
+}
+
+
+#define VSID_RANDOMIZER 42470972311
+#define VSID_MASK	0xfffffffff
+
+
+/* This is only valid for kernel (including vmalloc, imalloc and bolted) EA's
+ */
+static inline unsigned long
+get_kernel_vsid( unsigned long ea )
+{
+	unsigned long ordinal, vsid;
+	
+	ordinal = (((ea >> 28) & 0x1fffff) * LAST_USER_CONTEXT) | (ea >> 60);
+	vsid = (ordinal * VSID_RANDOMIZER) & VSID_MASK;
+
+	ifppcdebug(PPCDBG_HTABSTRESS) {
+		/* For debug, this path creates a very poor vsid distribuition.
+		 * A user program can access virtual addresses in the form
+		 * 0x0yyyyxxxx000 where yyyy = xxxx to cause multiple mappings
+		 * to hash to the same page table group.
+		 */ 
+		ordinal = ((ea >> 28) & 0x1fff) | (ea >> 44);
+		vsid = ordinal & VSID_MASK;
+	}
+
+	return vsid;
+} 
+
+/* This is only valid for user EA's (user EA's do not exceed 2^41 (EADDR_SIZE))
+ */
+static inline unsigned long
+get_vsid( unsigned long context, unsigned long ea )
+{
+	unsigned long ordinal, vsid;
+
+	ordinal = (((ea >> 28) & 0x1fffff) * LAST_USER_CONTEXT) | context;
+	vsid = (ordinal * VSID_RANDOMIZER) & VSID_MASK;
+
+	ifppcdebug(PPCDBG_HTABSTRESS) {
+		/* See comment above. */
+		ordinal = ((ea >> 28) & 0x1fff) | (context << 16);
+		vsid = ordinal & VSID_MASK;
+	}
+
+	return vsid;
+}
+
+#endif /* __PPC64_MMU_CONTEXT_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/module.h linux-2.4.19-pre5/include/asm-ppc64/module.h
--- linux-2.4.19-pre4/include/asm-ppc64/module.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/module.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,18 @@
+#ifndef _ASM_PPC64_MODULE_H
+#define _ASM_PPC64_MODULE_H
+/*
+ * This file contains the PPC architecture specific module code.
+ *
+ * Copyright (C) 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define module_map(x)		vmalloc(x)
+#define module_unmap(x)		vfree(x)
+#define arch_init_modules(x)	do { } while (0)
+#define module_arch_init(x)  (0)
+#endif /* _ASM_PPC64_MODULE_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/msgbuf.h linux-2.4.19-pre5/include/asm-ppc64/msgbuf.h
--- linux-2.4.19-pre4/include/asm-ppc64/msgbuf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/msgbuf.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,27 @@
+#ifndef _PPC64_MSGBUF_H
+#define _PPC64_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for the PPC architecture.
+ *
+ * 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.
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused1;
+	unsigned long  __unused2;
+};
+
+#endif /* _PPC64_MSGBUF_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/namei.h linux-2.4.19-pre5/include/asm-ppc64/namei.h
--- linux-2.4.19-pre4/include/asm-ppc64/namei.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/namei.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,23 @@
+/* 
+ * linux/include/asm-ppc/namei.h
+ * Adapted from linux/include/asm-alpha/namei.h
+ *
+ * Included from linux/fs/namei.c
+ *
+ * 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.
+ */
+
+#ifndef __PPC64_NAMEI_H
+#define __PPC64_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif /* __PPC64_NAMEI_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/nvram.h linux-2.4.19-pre5/include/asm-ppc64/nvram.h
--- linux-2.4.19-pre4/include/asm-ppc64/nvram.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/nvram.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,68 @@
+/*
+ * PreP compliant NVRAM access
+ * This needs to be updated for PPC64
+ *
+ * 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.
+ */
+
+#ifndef _PPC64_NVRAM_H
+#define _PPC64_NVRAM_H
+
+#define NVRAM_AS0  0x74
+#define NVRAM_AS1  0x75
+#define NVRAM_DATA 0x77
+
+
+/* RTC Offsets */
+
+#define MOTO_RTC_SECONDS	0x1FF9
+#define MOTO_RTC_MINUTES	0x1FFA
+#define MOTO_RTC_HOURS		0x1FFB
+#define MOTO_RTC_DAY_OF_WEEK	0x1FFC
+#define MOTO_RTC_DAY_OF_MONTH	0x1FFD
+#define MOTO_RTC_MONTH		0x1FFE
+#define MOTO_RTC_YEAR		0x1FFF
+#define MOTO_RTC_CONTROLA       0x1FF8
+#define MOTO_RTC_CONTROLB       0x1FF9
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+/* PowerMac specific nvram stuffs */
+
+enum {
+	pmac_nvram_OF,		/* Open Firmware partition */
+	pmac_nvram_XPRAM,	/* MacOS XPRAM partition */
+	pmac_nvram_NR		/* MacOS Name Registry partition */
+};
+
+/* Return partition offset in nvram */
+extern int	pmac_get_partition(int partition);
+
+/* Direct access to XPRAM */
+extern u8	pmac_xpram_read(int xpaddr);
+extern void	pmac_xpram_write(int xpaddr, u8 data);
+
+/* Some offsets in XPRAM */
+#define PMAC_XPRAM_MACHINE_LOC	0xe4
+#define PMAC_XPRAM_SOUND_VOLUME	0x08
+
+/* Machine location structure in XPRAM */
+struct pmac_machine_location {
+	u32	latitude;	/* 2+30 bit Fractional number */
+	u32	longitude;	/* 2+30 bit Fractional number */
+	u32	delta;		/* mix of GMT delta and DLS */
+};
+
+/* /dev/nvram ioctls */
+#define PMAC_NVRAM_GET_OFFSET   _IOWR('p', 0x40, int) /* Get NVRAM partition offset */
+
+#endif /* _PPC64_NVRAM_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/page.h linux-2.4.19-pre5/include/asm-ppc64/page.h
--- linux-2.4.19-pre4/include/asm-ppc64/page.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/page.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,225 @@
+#ifndef _PPC64_PAGE_H
+#define _PPC64_PAGE_H
+
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+#define PAGE_OFFSET_MASK (PAGE_SIZE-1)
+
+#define SID_SHIFT       28
+#define SID_MASK        0xfffffffff
+#define GET_ESID(x)     (((x) >> SID_SHIFT) & SID_MASK)
+
+/* Define an illegal instr to trap on the bug.
+ * We don't use 0 because that marks the end of a function
+ * in the ELF ABI.  That's "Boo Boo" in case you wonder...
+ */
+#define BUG_OPCODE .long 0x00b00b00  /* For asm */
+#define BUG_ILLEGAL_INSTR "0x00b00b00" /* For BUG macro */
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+#include <asm/Naca.h>
+
+#define STRICT_MM_TYPECHECKS
+
+#define REGION_SIZE   4UL
+#define OFFSET_SIZE   60UL
+#define REGION_SHIFT  60UL
+#define OFFSET_SHIFT  0UL
+#define REGION_MASK   (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
+#define REGION_STRIDE (1UL << REGION_SHIFT)
+
+typedef union ppc64_va {
+        struct {
+                unsigned long off : OFFSET_SIZE;  /* intra-region offset */
+                unsigned long reg : REGION_SIZE;  /* region number */
+        } f;
+        unsigned long l;
+        void *p;
+} ppc64_va;
+       
+static __inline__ void clear_page(void *addr)
+{
+	unsigned long lines, line_size;
+
+	line_size = naca->dCacheL1LineSize; 
+	lines = naca->dCacheL1LinesPerPage;
+
+	__asm__ __volatile__(
+"  	mtctr  	%1\n\
+1:      dcbz  	0,%0\n\
+	add	%0,%0,%3\n\
+	bdnz+	1b"
+        : "=r" (addr)
+        : "r" (lines), "0" (addr), "r" (line_size)
+	: "ctr", "memory");
+}
+
+extern void copy_page(void *to, void *from);
+struct page;
+extern void clear_user_page(void *page, unsigned long vaddr);
+extern void copy_user_page(void *to, void *from, unsigned long vaddr);
+
+#ifdef STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking.  
+ * Entries in the pte table are 64b, while entries in the pgd & pmd are 32b.
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned int  pmd; } pmd_t;
+typedef struct { unsigned int  pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)	((x).pte)
+#define pmd_val(x)	((x).pmd)
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)	((x).pgprot)
+
+#define __pte(x)	((pte_t) { (x) } )
+#define __pmd(x)	((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef unsigned int  pmd_t;
+typedef unsigned int  pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)	(x)
+#define pmd_val(x)	(x)
+#define pgd_val(x)	(x)
+#define pgprot_val(x)	(x)
+
+#define __pte(x)	(x)
+#define __pmd(x)	(x)
+#define __pgd(x)	(x)
+#define __pgprot(x)	(x)
+
+#endif
+
+#ifdef CONFIG_XMON
+#include <asm/ptrace.h>
+extern void xmon(struct pt_regs *excp);
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	xmon(0); \
+} while (0)
+#else
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	__asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \
+} while (0)
+#endif
+
+#define PAGE_BUG(page) do { BUG(); } while (0)
+
+/* Pure 2^n version of get_order */
+extern __inline__ int get_order(unsigned long size)
+{
+	int order;
+
+	size = (size-1) >> (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
+
+#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
+
+#endif /* __ASSEMBLY__ */
+
+/* align addr on a size boundry - adjust address up/down if needed */
+#define _ALIGN_UP(addr,size)	(((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size)	((addr)&(~((size)-1)))
+
+/* align addr on a size boundry - adjust address up if needed */
+#define _ALIGN(addr,size)     _ALIGN_UP(addr,size)
+
+/* to align the pointer to the (next) double word boundary */
+#define DOUBLEWORD_ALIGN(addr)	_ALIGN(addr,sizeof(unsigned long))
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	_ALIGN(addr, PAGE_SIZE)
+
+#ifdef MODULE
+#define __page_aligned __attribute__((__aligned__(PAGE_SIZE)))
+#else
+#define __page_aligned \
+	__attribute__((__aligned__(PAGE_SIZE), \
+		__section__(".data.page_aligned")))
+#endif
+
+
+/* This must match the -Ttext linker address            */
+/* Note: tophys & tovirt make assumptions about how     */
+/*       KERNELBASE is defined for performance reasons. */
+/*       When KERNELBASE moves, those macros may have   */
+/*             to change!                               */
+#define PAGE_OFFSET     0xC000000000000000
+#define KERNELBASE      PAGE_OFFSET
+#define VMALLOCBASE     0xD000000000000000
+#define IOREGIONBASE    0xE000000000000000
+
+#define IO_REGION_ID       (IOREGIONBASE>>REGION_SHIFT)
+#define VMALLOC_REGION_ID  (VMALLOCBASE>>REGION_SHIFT)
+#define KERNEL_REGION_ID   (KERNELBASE>>REGION_SHIFT)
+#define USER_REGION_ID     (0UL)
+#define REGION_ID(X)	   (((unsigned long)(X))>>REGION_SHIFT)
+
+/*
+ * Define valid/invalid EA bits (for all ranges)
+ */
+#define VALID_EA_BITS   (0x000001ffffffffffUL)
+#define INVALID_EA_BITS (~(REGION_MASK|VALID_EA_BITS))
+
+#define IS_VALID_REGION_ID(x) \
+        (((x) == USER_REGION_ID) || ((x) >= KERNEL_REGION_ID))
+#define IS_VALID_EA(x) \
+        ((!((x) & INVALID_EA_BITS)) && IS_VALID_REGION_ID(REGION_ID(x)))
+
+#define __bpn_to_ba(x) ((((unsigned long)(x))<<PAGE_SHIFT) + KERNELBASE)
+#define __ba_to_bpn(x) ((((unsigned long)(x)) & ~REGION_MASK) >> PAGE_SHIFT)
+
+#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
+
+/* Given that physical addresses do not map 1-1 to absolute addresses, we
+ * use these macros to better specify exactly what we want to do.
+ * The only restriction on their use is that the absolute address
+ * macros cannot be used until after the LMB structure has been
+ * initialized in prom.c.  -Peter
+ */
+#define __v2p(x) ((void *) __pa(x))
+#define __v2a(x) ((void *) phys_to_absolute(__pa(x)))
+#define __p2a(x) ((void *) phys_to_absolute(x))
+#define __p2v(x) ((void *) __va(x))
+#define __a2p(x) ((void *) absolute_to_phys(x))
+#define __a2v(x) ((void *) __va(absolute_to_phys(x)))
+
+#define virt_to_page(kaddr) (mem_map+(__pa((unsigned long)kaddr) >> PAGE_SHIFT))
+
+#define VALID_PAGE(page)    ((page - mem_map) < max_mapnr)
+
+#define MAP_NR(addr)        (__pa(addr) >> PAGE_SHIFT)
+
+#endif /* __KERNEL__ */
+#endif /* _PPC64_PAGE_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/param.h linux-2.4.19-pre5/include/asm-ppc64/param.h
--- linux-2.4.19-pre4/include/asm-ppc64/param.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/param.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,41 @@
+#ifndef _ASM_PPC64_PARAM_H
+#define _ASM_PPC64_PARAM_H
+
+/*
+ * 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.
+ */
+
+#ifndef HZ
+#define HZ 100
+#ifdef __KERNEL__
+#if HZ == 100
+/* ppc (like X86) is defined to provide userspace with a world where HZ=100
+   We have to do this, (x*const)/const2 isnt optimised out because its not
+   a null operation as it might overflow.. */
+#define hz_to_std(a) (a)
+#else
+#define hz_to_std(a) ((a)*(100/HZ)+((a)*(100%HZ))/HZ)
+#endif
+#endif
+#endif
+
+#define EXEC_PAGESIZE	4096
+
+#ifndef NGROUPS
+#define NGROUPS		32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP		(-1)
+#endif
+
+#define MAXHOSTNAMELEN	64	/* max length of hostname */
+
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
+#endif
+
+#endif /* _ASM_PPC64_PARAM_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/parport.h linux-2.4.19-pre5/include/asm-ppc64/parport.h
--- linux-2.4.19-pre4/include/asm-ppc64/parport.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/parport.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,21 @@
+/*
+ * BK Id: SCCS/s.parport.h 1.5 05/17/01 18:14:25 cort
+ */
+/*
+ * parport.h: platform-specific PC-style parport initialisation
+ *
+ * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This file should only be included by drivers/parport/parport_pc.c.
+ */
+
+#ifndef _ASM_PPC64_PARPORT_H
+#define _ASM_PPC64_PARPORT_H
+
+static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
+static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+{
+	return parport_pc_find_isa_ports (autoirq, autodma);
+}
+
+#endif /* !(_ASM_PPC_PARPORT_H) */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pci-bridge.h linux-2.4.19-pre5/include/asm-ppc64/pci-bridge.h
--- linux-2.4.19-pre4/include/asm-ppc64/pci-bridge.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pci-bridge.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,114 @@
+#ifdef __KERNEL__
+#ifndef _ASM_PCI_BRIDGE_H
+#define _ASM_PCI_BRIDGE_H
+
+/*
+ * 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.
+ */
+
+struct device_node;
+struct pci_controller;
+
+/*
+ * pci_io_base returns the memory address at which you can access
+ * the I/O space for PCI bus number `bus' (or NULL on error).
+ */
+extern void *pci_bus_io_base(unsigned int bus);
+extern unsigned long pci_bus_io_base_phys(unsigned int bus);
+extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
+
+/* Get the PCI host controller for a bus */
+extern struct pci_controller* pci_bus_to_hose(int bus);
+
+/* Get the PCI host controller for an OF device */
+extern struct pci_controller*
+pci_find_hose_for_OF_device(struct device_node* node);
+
+enum phb_types { 
+	phb_type_unknown    = 0x0,
+	phb_type_hypervisor = 0x1,
+	phb_type_python     = 0x10,
+	phb_type_speedwagon = 0x11
+};
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+struct pci_controller {
+	char what[8];                     /* Eye catcher      */
+	enum phb_types type;              /* Type of hardware */
+	struct pci_controller *next;
+	struct pci_bus *bus;
+	void *arch_data;
+
+	int first_busno;
+	int last_busno;
+
+	void *io_base_virt;
+	unsigned long io_base_phys;
+
+	/* Some machines (PReP) have a non 1:1 mapping of
+	 * the PCI memory space in the CPU bus space
+	 */
+	unsigned long pci_mem_offset;
+	unsigned long pci_io_offset;
+
+	struct pci_ops *ops;
+	volatile unsigned long *cfg_addr;
+	volatile unsigned char *cfg_data;
+	volatile unsigned long *phb_regs;
+	volatile unsigned long *chip_regs;
+
+	/* Currently, we limit ourselves to 1 IO range and 3 mem
+	 * ranges since the common pci_bus structure can't handle more
+	 */
+	struct resource io_resource;
+	struct resource mem_resources[3];
+	int mem_resource_count;
+	int    global_number;		
+	int    local_number;		
+	int    system_bus_number;	
+	unsigned long buid;
+	unsigned long dma_window_base_cur;
+	unsigned long dma_window_size;
+};
+
+
+/* This version handles the new Uni-N host bridge, the iobase is now
+ * a per-device thing. I also added the memory base so PReP can
+ * be fixed to return 0xc0000000 (I didn't actually implement it)
+ *
+ * pci_dev_io_base() returns either a virtual (ioremap'ed) address or
+ * a physical address. In-kernel clients will use logical while the
+ * sys_pciconfig_iobase syscall returns a physical one to userland.
+ */
+void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical);
+void *pci_dev_mem_base(unsigned char bus, unsigned char devfn);
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
+
+/*
+ * pci_device_loc returns the bus number and device/function number
+ * for a device on a PCI bus, given its device_node struct.
+ * It returns 0 if OK, -1 on error.
+ */
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+		   unsigned char *devfn_ptr);
+
+struct bridge_data {
+	volatile unsigned int *cfg_addr;
+	volatile unsigned char *cfg_data;
+	void *io_base;		/* virtual */
+	unsigned long io_base_phys;
+	int bus_number;
+	int max_bus;
+	struct bridge_data *next;
+	struct device_node *node;
+};
+
+#endif
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pci.h linux-2.4.19-pre5/include/asm-ppc64/pci.h
--- linux-2.4.19-pre4/include/asm-ppc64/pci.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pci.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,144 @@
+#ifndef __PPC64_PCI_H
+#define __PPC64_PCI_H
+#ifdef __KERNEL__
+
+/*
+ * 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.
+ */
+
+/* Values for the `which' argument to sys_pciconfig_iobase syscall.  */
+#define IOBASE_BRIDGE_NUMBER	0
+#define IOBASE_MEMORY		1
+#define IOBASE_IO		2
+#define IOBASE_ISA_IO           3
+#define IOBASE_ISA_MEM          4
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ * already-configured bus numbers - to be used for buggy BIOSes
+ * or architectures with incomplete PCI setup by the loader.
+ */
+extern int pcibios_assign_all_busses(void);
+
+#define PCIBIOS_MIN_IO		0x1000
+#define PCIBIOS_MIN_MEM		0x10000000
+
+extern inline void pcibios_set_master(struct pci_dev *dev)
+{
+	/* No special bus mastering setup handling */
+}
+
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+	/* We don't do dynamic PCI IRQ allocation */
+}
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+struct pci_dev;
+#define REG_SAVE_SIZE 64
+/************************************************************************
+ * Structure to hold the data for PCI Register Save/Restore functions.  *
+ ************************************************************************/
+struct pci_config_reg_save_area {
+	struct pci_dev* PciDev;	    /* Pointer to device(Sanity Check)     */ 
+	int    Flags;               /* Control & Info Flags                */
+	int    RCode;               /* Return Code on Save/Restore         */
+	int    Register;            /* Pointer to current register.        */
+	u8     Regs[REG_SAVE_SIZE]; /* Save Area                           */ 
+};
+/************************************************************************
+ * Functions to support device reset                                    *
+ ************************************************************************/
+extern int   pci_reset_device(struct pci_dev*, int, int);
+extern int   pci_save_config_regs(struct pci_dev*,struct pci_config_reg_save_area*);
+extern int   pci_restore_config_regs(struct pci_dev*,struct pci_config_reg_save_area*);
+extern char* pci_card_location(struct pci_dev*);
+
+extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				  dma_addr_t *dma_handle);
+extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+				void *vaddr, dma_addr_t dma_handle);
+
+extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size, int direction);
+extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+                             size_t size, int direction);
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+                      int nents, int direction);
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+                         int nents, int direction);
+
+extern void pSeries_pcibios_init_early(void);
+
+extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+				       dma_addr_t dma_handle,
+				       size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	/* nothing to do */
+}
+
+extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+				   struct scatterlist *sg,
+				   int nelems, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	/* nothing to do */
+}
+
+/* Return whether the given PCI device DMA address mask can
+ * be supported properly.  For example, if your device can
+ * only drive the low 24-bits during PCI bus mastering, then
+ * you would pass 0x00ffffff as the mask to this function.
+ */
+extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+{
+	return 1;
+}
+
+/* Return the index of the PCI controller for device PDEV. */
+extern int pci_controller_num(struct pci_dev *pdev);
+
+/* Map a range of PCI memory or I/O space for a device into user space */
+int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine);
+
+/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
+#define HAVE_PCI_MMAP	1
+
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->dma_length)
+
+#define pci_map_page(dev, page, off, size, dir) \
+		pci_map_single(dev, (page_address(page) + (off)), size, dir)
+#define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir)
+
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
+#define pci_dac_dma_supported(pci_dev, mask)	(0)
+
+#endif	/* __KERNEL__ */
+
+#endif /* __PPC64_PCI_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pci_dma.h linux-2.4.19-pre5/include/asm-ppc64/pci_dma.h
--- linux-2.4.19-pre4/include/asm-ppc64/pci_dma.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pci_dma.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,100 @@
+/*
+ * pci_dma.h
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _PCI_DMA_H
+#define _PCI_DMA_H
+
+#include <asm/types.h>
+#include <linux/spinlock.h>
+
+/*
+ * NUM_TCE_LEVELS defines the largest contiguous block
+ * of dma (tce) space we can get.  NUM_TCE_LEVELS = 10 
+ * allows up to 2**9 pages (512 * 4096) = 2 MB
+ */
+#define NUM_TCE_LEVELS 10
+
+#define NO_TCE ((dma_addr_t)-1)
+
+/*
+ * Tces come in two formats, one for the virtual bus and a different
+ * format for PCI
+ */
+#define TCE_VB  0
+#define TCE_PCI 1
+
+union Tce {
+   	u64 wholeTce;
+	struct {
+		u64 cacheBits	:6;	/* Cache hash bits - not used */
+		u64 rsvd	:6;
+		u64 rpn		:40;	/* Absolute page number */
+		u64 valid	:1;	/* Tce is valid (vb only) */
+		u64 allIo	:1;	/* Tce is valid for all lps (vb only) */
+		u64 lpIndex	:8;	/* LpIndex for user of TCE (vb only) */
+		u64 pciWrite	:1;	/* Write allowed (pci only) */
+		u64 readWrite	:1;	/* Read allowed (pci), Write allowed (vb) */
+	} tceBits;
+};
+
+struct Bitmap {
+	unsigned long	numBits;
+	unsigned long	numBytes;
+	unsigned char * map;
+};
+
+struct MultiLevelBitmap {
+	unsigned long 	maxLevel;
+	struct Bitmap 	level[NUM_TCE_LEVELS];
+};
+
+struct TceTable {
+	u64	busNumber;
+	u64	size;
+	u64	startOffset;
+	u64     base;                   /* pSeries native only */
+	u64	index;
+	u64	tceType;
+	spinlock_t lock;
+	struct MultiLevelBitmap mlbm;
+};
+
+struct TceTableManagerCB {
+	u64	busNumber;		/* Bus number for this tce table */
+	u64	start;			/* Will be NULL for secondary */
+	u64	totalSize;		/* Size (in pages) of whole table */
+	u64	startOffset;		/* Index into real tce table of the
+					   start of our section */
+	u64	size;			/* Size (in pages) of our section */
+	u64	index;			/* Index of this tce table (token?) */
+	u16	maxTceTableIndex;	/* Max num of tables for partition */
+	u8	virtualBusFlag;		/* Flag to indicate virtual bus */
+ 	u8	logicalSlot;		/* IOA Tce Slot Index */
+ 	u8	rsvd[4];
+};
+
+extern struct TceTable virtBusTceTable;	/* Tce table for virtual bus */
+
+extern void create_tce_tables(void);
+extern void create_pci_bus_tce_table(unsigned long);
+
+void tce_init_pSeries(void);
+void tce_init_iSeries(void);
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pgalloc.h linux-2.4.19-pre5/include/asm-ppc64/pgalloc.h
--- linux-2.4.19-pre4/include/asm-ppc64/pgalloc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pgalloc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,127 @@
+#ifndef _PPC64_PGALLOC_H
+#define _PPC64_PGALLOC_H
+
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/Naca.h>
+#include <asm/Paca.h>
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define quicklists      get_paca()
+
+#define pgd_quicklist 		(quicklists->pgd_cache)
+#define pmd_quicklist 		(quicklists->pmd_cache)
+#define pte_quicklist 		(quicklists->pte_cache)
+#define pgtable_cache_size 	(quicklists->pgtable_cache_sz)
+
+static inline pgd_t*
+pgd_alloc_one_fast (struct mm_struct *mm)
+{
+	unsigned long *ret = pgd_quicklist;
+
+	if (ret != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		--pgtable_cache_size;
+	} else
+		ret = NULL;
+	return (pgd_t *) ret;
+}
+
+static inline pgd_t*
+pgd_alloc (struct mm_struct *mm)
+{
+	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
+	pgd_t *pgd = pgd_alloc_one_fast(mm);
+
+	if (pgd == NULL) {
+		pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+		if (pgd != NULL)
+			clear_page(pgd);
+	}
+	return pgd;
+}
+
+static inline void
+pgd_free (pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	++pgtable_cache_size;
+}
+
+#define pgd_populate(MM, PGD, PMD)	pgd_set(PGD, PMD)
+
+static inline pmd_t*
+pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
+{
+	unsigned long *ret = (unsigned long *)pmd_quicklist;
+
+	if (ret != NULL) {
+		pmd_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		--pgtable_cache_size;
+	}
+	return (pmd_t *)ret;
+}
+
+static inline pmd_t*
+pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
+{
+	pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+
+	if (pmd != NULL)
+		clear_page(pmd);
+	return pmd;
+}
+
+static inline void
+pmd_free (pmd_t *pmd)
+{
+	*(unsigned long *)pmd = (unsigned long) pmd_quicklist;
+	pmd_quicklist = (unsigned long *) pmd;
+	++pgtable_cache_size;
+}
+
+#define pmd_populate(MM, PMD, PTE)	pmd_set(PMD, PTE)
+
+static inline pte_t*
+pte_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
+{
+	unsigned long *ret = (unsigned long *)pte_quicklist;
+
+	if (ret != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		--pgtable_cache_size;
+	}
+	return (pte_t *)ret;
+}
+
+
+static inline pte_t*
+pte_alloc_one (struct mm_struct *mm, unsigned long addr)
+{
+	pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL);
+
+	if (pte != NULL)
+		clear_page(pte);
+	return pte;
+}
+
+static inline void
+pte_free (pte_t *pte)
+{
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	++pgtable_cache_size;
+}
+
+extern int do_check_pgt_cache(int, int);
+
+#endif /* _PPC64_PGALLOC_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pgtable.h linux-2.4.19-pre5/include/asm-ppc64/pgtable.h
--- linux-2.4.19-pre4/include/asm-ppc64/pgtable.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pgtable.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,444 @@
+#ifndef _PPC64_PGTABLE_H
+#define _PPC64_PGTABLE_H
+
+#define NEW_HPT 1
+
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the ppc64 hashed page table.
+ */
+
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>		/* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#endif /* __ASSEMBLY__ */
+
+/* Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+
+
+/* PMD_SHIFT determines what a second-level page table entry can map */
+#define PMD_SHIFT	(PAGE_SHIFT + PAGE_SHIFT - 3)
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT - 3) + (PAGE_SHIFT - 2))
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * Entries per page directory level.  The PTE level must use a 64b record
+ * for each page table entry.  The PMD and PGD level use a 32b record for 
+ * each entry by assuming that each entry is page aligned.
+ */
+#define PTE_INDEX_SIZE  9
+#define PMD_INDEX_SIZE  10
+#define PGD_INDEX_SIZE  10
+
+#define PTRS_PER_PTE	(1 << PTE_INDEX_SIZE)
+#define PTRS_PER_PMD	(1 << PMD_INDEX_SIZE)
+#define PTRS_PER_PGD	(1 << PGD_INDEX_SIZE)
+
+#if 0
+/* DRENG / PPPBBB This is a compiler bug!!! */
+#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
+#else
+#define USER_PTRS_PER_PGD	(1024)
+#endif
+#define FIRST_USER_PGD_NR	0
+
+#define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
+                    PGD_INDEX_SIZE + PAGE_SHIFT) 
+
+/*
+ * Define the address range of the vmalloc VM area.
+ */
+#define VMALLOC_START (0xD000000000000000)
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END   (VMALLOC_START + VALID_EA_BITS)
+
+/*
+ * Define the address range of the imalloc VM area.
+ * (used for ioremap)
+ */
+#define IMALLOC_START (ioremap_bot)
+#define IMALLOC_VMADDR(x) ((unsigned long)(x))
+#define IMALLOC_BASE  (0xE000000000000000)
+#define IMALLOC_END   (IMALLOC_BASE + VALID_EA_BITS)
+
+/*
+ * Define the address range mapped virt <-> physical
+ */
+#define KRANGE_START KERNELBASE
+#define KRANGE_END   (KRANGE_START + VALID_EA_BITS)
+
+/*
+ * Define the user address range
+ */
+#define USER_START (0UL)
+#define USER_END   (USER_START + VALID_EA_BITS)
+
+
+/*
+ * Bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+#define _PAGE_PRESENT	0x001UL	/* software: pte contains a translation */
+#define _PAGE_USER	0x002UL	/* matches one of the PP bits */
+#define _PAGE_RW	0x004UL	/* software: user write access allowed */
+#define _PAGE_GUARDED	0x008UL
+#define _PAGE_COHERENT	0x010UL	/* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE	0x020UL	/* I: cache inhibit */
+#define _PAGE_WRITETHRU	0x040UL	/* W: cache write-through */
+#define _PAGE_DIRTY	0x080UL	/* C: page changed */
+#define _PAGE_ACCESSED	0x100UL	/* R: page referenced */
+#define _PAGE_HPTENOIX	0x200UL /* software: pte HPTE slot unknown */
+#define _PAGE_HASHPTE	0x400UL	/* software: pte has an associated HPTE */
+#define _PAGE_EXEC	0x800UL	/* software: i-cache coherence required */
+#define _PAGE_SECONDARY 0x8000UL /* software: HPTE is in secondary group */
+#define _PAGE_GROUP_IX  0x7000UL /* software: HPTE index within group */
+/* Bits 0x7000 identify the index within an HPT Group */
+#define _PAGE_HPTEFLAGS (_PAGE_HASHPTE | _PAGE_HPTENOIX | _PAGE_SECONDARY | _PAGE_GROUP_IX)
+/* PAGE_MASK gives the right answer below, but only by accident */
+/* It should be preserving the high 48 bits and then specifically */
+/* preserving _PAGE_SECONDARY | _PAGE_GROUP_IX */
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HPTEFLAGS)
+
+#define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT
+
+#define _PAGE_WRENABLE	_PAGE_RW | _PAGE_DIRTY 
+
+/* __pgprot defined in asm-ppc64/page.h */
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
+#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_WRENABLE)
+#define PAGE_KERNEL_CI	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+			       _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
+
+/*
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis.  So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY_X
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY_X
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY_X
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY_X
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY_X
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED_X
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY_X
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page))
+#endif /* __ASSEMBLY__ */
+
+/* shift to put page number into pte */
+#define PTE_SHIFT (16)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * mk_pte_phys takes a physical address as input 
+ *
+ * mk_pte takes a (struct page *) as input
+ */
+
+#define mk_pte_phys(physpage,pgprot)                                      \
+({									  \
+	pte_t pte;							  \
+	pte_val(pte) = (((physpage)<<(PTE_SHIFT-PAGE_SHIFT)) | pgprot_val(pgprot)); \
+	pte;							          \
+})
+
+#define mk_pte(page,pgprot)                                               \
+({									  \
+	pte_t pte;							  \
+	pte_val(pte) = ((unsigned long)((page) - mem_map) << PTE_SHIFT) |   \
+                        pgprot_val(pgprot);                               \
+	pte;							          \
+})
+
+#define pte_modify(_pte, newprot) \
+  (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
+
+#define pte_none(pte)		((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
+#define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
+
+/* pte_clear moved to later in this file */
+
+#define pte_pagenr(x)		((unsigned long)((pte_val(x) >> PTE_SHIFT)))
+#define pte_page(x)		(mem_map+pte_pagenr(x))
+
+#define pmd_set(pmdp, ptep) 	(pmd_val(*(pmdp)) = (__ba_to_bpn(ptep)))
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define	pmd_bad(pmd)		((pmd_val(pmd)) == 0)
+#define	pmd_present(pmd)	((pmd_val(pmd)) != 0)
+#define	pmd_clear(pmdp)		(pmd_val(*(pmdp)) = 0)
+#define pmd_page(pmd)		(__bpn_to_ba(pmd_val(pmd)))
+#define pgd_set(pgdp, pmdp)	(pgd_val(*(pgdp)) = (__ba_to_bpn(pmdp)))
+#define pgd_none(pgd)		(!pgd_val(pgd))
+#define pgd_bad(pgd)		((pgd_val(pgd)) == 0)
+#define pgd_present(pgd)	(pgd_val(pgd) != 0UL)
+#define pgd_clear(pgdp)		(pgd_val(*(pgdp)) = 0UL)
+#define pgd_page(pgd)		(__bpn_to_ba(pgd_val(pgd))) 
+
+/* 
+ * Find an entry in a page-table-directory.  We combine the address region 
+ * (the high order N bits) and the pgd portion of the address.
+ */
+#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD -1))
+
+#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir,addr) \
+  ((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+
+/* Find an entry in the third-level page table.. */
+#define pte_offset(dir,addr) \
+  ((pte_t *) pmd_page(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+
+/* to find an entry in a kernel page-table-directory */
+/* This now only contains the vmalloc pages */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in the ioremap page-table-directory */
+#define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
+
+/*
+ * Given a pointer to an mem_map[] entry, return the kernel virtual
+ * address corresponding to that page.
+ */
+#define page_address(page) ((page)->virtual)
+
+#define pages_to_mb(x)		((x) >> (20-PAGE_SHIFT))
+
+/*
+ * 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_EXEC;}
+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;}
+
+extern inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+extern inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+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_EXEC; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_RW); 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_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 | _PAGE_EXEC; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte) {
+	pte_val(pte) |= _PAGE_RW; 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; }
+
+/* Atomic PTE updates */
+
+static inline unsigned long pte_update( pte_t *p, unsigned long clr,
+					unsigned long set )
+{
+	unsigned long old, tmp;
+
+	__asm__ __volatile__("\n\
+1:	ldarx	%0,0,%3	\n\
+	andc	%1,%0,%4 \n\
+	or	%1,%1,%5 \n\
+	stdcx.	%1,0,%3 \n\
+	bne-	1b"
+	: "=&r" (old), "=&r" (tmp), "=m" (*p)
+	: "r" (p), "r" (clr), "r" (set), "m" (*p)
+	: "cc" );
+	return old;
+}
+
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+	return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0;
+}
+
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+	return (pte_update(ptep, _PAGE_DIRTY, 0) & _PAGE_DIRTY) != 0;
+}
+
+static inline pte_t ptep_get_and_clear(pte_t *ptep)
+{
+	return __pte(pte_update(ptep, ~_PAGE_HPTEFLAGS, 0));
+}
+
+static inline void ptep_set_wrprotect(pte_t *ptep)
+{
+	pte_update(ptep, _PAGE_RW, 0);
+}
+
+static inline void ptep_mkdirty(pte_t *ptep)
+{
+	pte_update(ptep, 0, _PAGE_DIRTY);
+}
+
+#define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ * On machines which use an MMU hash table we avoid changing the
+ * _PAGE_HASHPTE bit.
+ */
+static inline void set_pte(pte_t *ptep, pte_t pte)
+{
+	pte_update(ptep, ~_PAGE_HPTEFLAGS, pte_val(pte) & ~_PAGE_HPTEFLAGS);
+}
+
+static inline void pte_clear(pte_t * ptep)
+{
+	pte_update(ptep, ~_PAGE_HPTEFLAGS, 0);
+}
+
+struct mm_struct;
+struct vm_area_struct;
+extern void local_flush_tlb_all(void);
+extern void local_flush_tlb_mm(struct mm_struct *mm);
+extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+			    unsigned long end);
+
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_range local_flush_tlb_range
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+				unsigned long start, unsigned long end)
+{
+	/* PPC has hw page tables. */
+}
+
+/*
+ * No cache flushing is required when address mappings are
+ * changed, because the caches on PowerPCs are physically
+ * addressed.
+ */
+#define flush_cache_all()		do { } while (0)
+#define flush_cache_mm(mm)		do { } while (0)
+#define flush_cache_range(mm, a, b)	do { } while (0)
+#define flush_cache_page(vma, p)	do { } while (0)
+#define flush_page_to_ram(page)		do { } while (0)
+
+extern void flush_icache_user_range(struct vm_area_struct *vma,
+			struct page *page, unsigned long addr, int len);
+extern void flush_icache_range(unsigned long, unsigned long);
+extern void __flush_dcache_icache(void *page_va);
+extern void flush_dcache_page(struct page *page);
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+
+extern unsigned long va_to_phys(unsigned long address);
+extern pte_t *va_to_pte(unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+	printk("%s:%d: bad pmd %08x.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %08x.\n", __FILE__, __LINE__, pgd_val(e))
+
+extern pgd_t swapper_pg_dir[1024];
+extern pgd_t ioremap_dir[1024];
+
+extern void paging_init(void);
+
+/*
+ * Page tables may have changed.  We don't need to do anything here
+ * as entries are faulted into the hash table by the low-level
+ * data/instruction access exception handlers.
+ */
+/*
+ * We won't be able to use update_mmu_cache to update the 
+ * hardware page table because we need to update the pte
+ * as well, but we don't get the address of the pte, only
+ * its value.
+ */
+#define update_mmu_cache(vma, addr, pte)	do { } while (0)
+
+extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid);
+extern void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte);
+
+/* Encode and de-code a swap entry */
+#define SWP_TYPE(entry)			(((entry).val >> 1) & 0x3f)
+#define SWP_OFFSET(entry)		((entry).val >> 8)
+#define SWP_ENTRY(type, offset)		((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) >> PTE_SHIFT })
+#define swp_entry_to_pte(x)		((pte_t) { (x).val << PTE_SHIFT })
+
+/*
+ * kern_addr_valid is intended to indicate whether an address is a valid
+ * kernel address.  Most 32-bit archs define it as always true (like this)
+ * but most 64-bit archs actually perform a test.  What should we do here?
+ * The only use is in fs/ncpfs/dir.c
+ */
+#define kern_addr_valid(addr)	(1)
+
+#define io_remap_page_range remap_page_range 
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()	do { } while (0)
+
+extern void updateBoltedHptePP(unsigned long newpp, unsigned long ea);
+extern void hpte_init_pSeries(void);
+extern void hpte_init_iSeries(void);
+
+extern void make_pte(HPTE * htab, unsigned long va, unsigned long pa,
+		int mode, unsigned long hash_mask, int large);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _PPC64_PGTABLE_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pmc.h linux-2.4.19-pre5/include/asm-ppc64/pmc.h
--- linux-2.4.19-pre4/include/asm-ppc64/pmc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pmc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,113 @@
+/* 
+ * pmc.h
+ * Copyright (C) 2001  Dave Engebretsen & Mike Corrigan IBM Corporation.
+ *
+ * The PPC64 PMC subsystem encompases both the hardware PMC registers and 
+ * a set of software event counters.  An interface is provided via the
+ * proc filesystem which can be used to access this subsystem.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Start Change Log
+ * 2001/06/05 : engebret : Created.
+ * End Change Log 
+ */
+
+#ifndef _PPC64_TYPES_H
+#include        <asm/types.h>
+#endif
+
+#ifndef _PMC_H
+#define _PMC_H
+
+#define STAB_ENTRY_MAX 64
+
+struct _pmc_hw
+{
+	u64 mmcr0; 
+	u64 mmcr1; 
+	u64 mmcra; 
+
+	u64 pmc1; 
+	u64 pmc2; 
+	u64 pmc3; 
+	u64 pmc4; 
+	u64 pmc5; 
+	u64 pmc6; 
+	u64 pmc7; 
+	u64 pmc8; 
+};
+
+struct _pmc_sw
+{
+	u64 stab_faults;           /* Count of faults on the stab      */
+	u64 stab_capacity_castouts;/* Count of castouts from the stab  */
+	u64 stab_invalidations;	   /* Count of invalidations from the  */
+                                   /*   stab, not including castouts   */
+	u64 stab_entry_use[STAB_ENTRY_MAX]; 
+
+	u64 htab_primary_overflows;
+	u64 htab_capacity_castouts;
+	u64 htab_read_to_write_fault;
+};
+
+#define PMC_HW_TEXT_ENTRY_COUNT (sizeof(struct _pmc_hw) / sizeof(u64))
+#define PMC_SW_TEXT_ENTRY_COUNT (sizeof(struct _pmc_sw) / sizeof(u64))
+#define PMC_TEXT_ENTRY_SIZE  64
+
+struct _pmc_sw_text {
+	char buffer[PMC_SW_TEXT_ENTRY_COUNT * PMC_TEXT_ENTRY_SIZE];
+};
+
+struct _pmc_hw_text {
+	char buffer[PMC_HW_TEXT_ENTRY_COUNT * PMC_TEXT_ENTRY_SIZE];
+};
+
+extern struct _pmc_sw pmc_sw_system;
+extern struct _pmc_sw pmc_sw_cpu[];
+
+extern struct _pmc_sw_text pmc_sw_text;
+extern struct _pmc_hw_text pmc_hw_text;
+extern char *ppc64_pmc_stab(int file);
+extern char *ppc64_pmc_htab(int file);
+extern char *ppc64_pmc_hw(int file);
+
+#if 1
+#define PMC_SW_PROCESSOR(F)      pmc_sw_cpu[smp_processor_id()].F++
+#define PMC_SW_PROCESSOR_A(F, E) (pmc_sw_cpu[smp_processor_id()].F[(E)])++
+#define PMC_SW_SYSTEM(F)         pmc_sw_system.F++
+#else
+#define PMC_SW_PROCESSOR(F)   do {;} while (0)
+#define PMC_SW_PROCESSOR_A(F) do {;} while (0)
+#define PMC_SW_SYSTEM(F)      do {;} while (0)
+#endif
+
+#define MMCR0 795
+#define MMCR1 798
+#define MMCRA 786
+#define PMC1  787
+#define PMC2  788
+#define PMC3  789
+#define PMC4  790
+#define PMC5  791
+#define PMC6  792
+#define PMC7  793
+#define PMC8  794
+
+#define PMC_CONTROL_CPI 1
+#define PMC_CONTROL_TLB 2
+
+#endif /* _PMC_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/pnp.h linux-2.4.19-pre5/include/asm-ppc64/pnp.h
--- linux-2.4.19-pre4/include/asm-ppc64/pnp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/pnp.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,648 @@
+/* 11/02/95                                                                   */
+/*----------------------------------------------------------------------------*/
+/*      Plug and Play header definitions                                      */
+/*----------------------------------------------------------------------------*/
+
+/* Structure map for PnP on PowerPC Reference Platform                        */
+/* See Plug and Play ISA Specification, Version 1.0, May 28, 1993.  It        */
+/* (or later versions) is available on Compuserve in the PLUGPLAY area.       */
+/* This code has extensions to that specification, namely new short and       */
+/* long tag types for platform dependent information                          */
+/*
+ * 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.
+ */
+/* Warning: LE notation used throughout this file                             */
+
+/* For enum's: if given in hex then they are bit significant, i.e.            */
+/* only one bit is on for each enum                                           */
+
+#ifndef _PNP_
+#define _PNP_
+
+#ifndef __ASSEMBLY__
+#define MAX_MEM_REGISTERS 9
+#define MAX_IO_PORTS 20
+#define MAX_IRQS 7
+/*#define MAX_DMA_CHANNELS 7*/
+
+/* Interrupt controllers */
+
+#define PNPinterrupt0 "PNP0000"      /* AT Interrupt Controller               */
+#define PNPinterrupt1 "PNP0001"      /* EISA Interrupt Controller             */
+#define PNPinterrupt2 "PNP0002"      /* MCA Interrupt Controller              */
+#define PNPinterrupt3 "PNP0003"      /* APIC                                  */
+#define PNPExtInt     "IBM000D"      /* PowerPC Extended Interrupt Controller */
+
+/* Timers */
+
+#define PNPtimer0     "PNP0100"      /* AT Timer                              */
+#define PNPtimer1     "PNP0101"      /* EISA Timer                            */
+#define PNPtimer2     "PNP0102"      /* MCA Timer                             */
+
+/* DMA controllers */
+
+#define PNPdma0       "PNP0200"      /* AT DMA Controller                     */
+#define PNPdma1       "PNP0201"      /* EISA DMA Controller                   */
+#define PNPdma2       "PNP0202"      /* MCA DMA Controller                    */
+
+/* start of August 15, 1994 additions */
+/* CMOS */
+#define PNPCMOS       "IBM0009"      /* CMOS                                  */
+
+/* L2 Cache */
+#define PNPL2         "IBM0007"      /* L2 Cache                              */
+
+/* NVRAM */
+#define PNPNVRAM      "IBM0008"      /* NVRAM                                 */
+
+/* Power Management */
+#define PNPPM         "IBM0005"      /* Power Management                      */
+/* end of August 15, 1994 additions */
+
+/* Keyboards */
+
+#define PNPkeyboard0  "PNP0300"      /* IBM PC/XT KB Cntlr (83 key, no mouse) */
+#define PNPkeyboard1  "PNP0301"      /* Olivetti ICO (102 key)                */
+#define PNPkeyboard2  "PNP0302"      /* IBM PC/AT KB Cntlr (84 key)           */
+#define PNPkeyboard3  "PNP0303"      /* IBM Enhanced (101/2 key, PS/2 mouse)  */
+#define PNPkeyboard4  "PNP0304"      /* Nokia 1050 KB Cntlr                   */
+#define PNPkeyboard5  "PNP0305"      /* Nokia 9140 KB Cntlr                   */
+#define PNPkeyboard6  "PNP0306"      /* Standard Japanese KB Cntlr            */
+#define PNPkeyboard7  "PNP0307"      /* Microsoft Windows (R) KB Cntlr        */
+
+/* Parallel port controllers */
+
+#define PNPparallel0 "PNP0400"       /* Standard LPT Parallel Port            */
+#define PNPparallel1 "PNP0401"       /* ECP Parallel Port                     */
+#define PNPepp       "IBM001C"       /* EPP Parallel Port                     */
+
+/* Serial port controllers */
+
+#define PNPserial0   "PNP0500"       /* Standard PC Serial port               */
+#define PNPSerial1   "PNP0501"       /* 16550A Compatible Serial port         */
+
+/* Disk controllers */
+
+#define PNPdisk0     "PNP0600"       /* Generic ESDI/IDE/ATA Compat HD Cntlr  */
+#define PNPdisk1     "PNP0601"       /* Plus Hardcard II                      */
+#define PNPdisk2     "PNP0602"       /* Plus Hardcard IIXL/EZ                 */
+
+/* Diskette controllers */
+
+#define PNPdiskette0 "PNP0700"       /* PC Standard Floppy Disk Controller    */
+
+/* Display controllers */
+
+#define PNPdisplay0  "PNP0900"       /* VGA Compatible                        */
+#define PNPdisplay1  "PNP0901"       /* Video Seven VGA                       */
+#define PNPdisplay2  "PNP0902"       /* 8514/A Compatible                     */
+#define PNPdisplay3  "PNP0903"       /* Trident VGA                           */
+#define PNPdisplay4  "PNP0904"       /* Cirrus Logic Laptop VGA               */
+#define PNPdisplay5  "PNP0905"       /* Cirrus Logic VGA                      */
+#define PNPdisplay6  "PNP0906"       /* Tseng ET4000 or ET4000/W32            */
+#define PNPdisplay7  "PNP0907"       /* Western Digital VGA                   */
+#define PNPdisplay8  "PNP0908"       /* Western Digital Laptop VGA            */
+#define PNPdisplay9  "PNP0909"       /* S3                                    */
+#define PNPdisplayA  "PNP090A"       /* ATI Ultra Pro/Plus (Mach 32)          */
+#define PNPdisplayB  "PNP090B"       /* ATI Ultra (Mach 8)                    */
+#define PNPdisplayC  "PNP090C"       /* XGA Compatible                        */
+#define PNPdisplayD  "PNP090D"       /* ATI VGA Wonder                        */
+#define PNPdisplayE  "PNP090E"       /* Weitek P9000 Graphics Adapter         */
+#define PNPdisplayF  "PNP090F"       /* Oak Technology VGA                    */
+
+/* Peripheral busses */
+
+#define PNPbuses0    "PNP0A00"       /* ISA Bus                               */
+#define PNPbuses1    "PNP0A01"       /* EISA Bus                              */
+#define PNPbuses2    "PNP0A02"       /* MCA Bus                               */
+#define PNPbuses3    "PNP0A03"       /* PCI Bus                               */
+#define PNPbuses4    "PNP0A04"       /* VESA/VL Bus                           */
+
+/* RTC, BIOS, planar devices */
+
+#define PNPspeaker0  "PNP0800"       /* AT Style Speaker Sound                */
+#define PNPrtc0      "PNP0B00"       /* AT RTC                                */
+#define PNPpnpbios0  "PNP0C00"       /* PNP BIOS (only created by root enum)  */
+#define PNPpnpbios1  "PNP0C01"       /* System Board Memory Device            */
+#define PNPpnpbios2  "PNP0C02"       /* Math Coprocessor                      */
+#define PNPpnpbios3  "PNP0C03"       /* PNP BIOS Event Notification Interrupt */
+
+/* PCMCIA controller */
+
+#define PNPpcmcia0   "PNP0E00"       /* Intel 82365 Compatible PCMCIA Cntlr   */
+
+/* Mice */
+
+#define PNPmouse0    "PNP0F00"       /* Microsoft Bus Mouse                   */
+#define PNPmouse1    "PNP0F01"       /* Microsoft Serial Mouse                */
+#define PNPmouse2    "PNP0F02"       /* Microsoft Inport Mouse                */
+#define PNPmouse3    "PNP0F03"       /* Microsoft PS/2 Mouse                  */
+#define PNPmouse4    "PNP0F04"       /* Mousesystems Mouse                    */
+#define PNPmouse5    "PNP0F05"       /* Mousesystems 3 Button Mouse - COM2    */
+#define PNPmouse6    "PNP0F06"       /* Genius Mouse - COM1                   */
+#define PNPmouse7    "PNP0F07"       /* Genius Mouse - COM2                   */
+#define PNPmouse8    "PNP0F08"       /* Logitech Serial Mouse                 */
+#define PNPmouse9    "PNP0F09"       /* Microsoft Ballpoint Serial Mouse      */
+#define PNPmouseA    "PNP0F0A"       /* Microsoft PNP Mouse                   */
+#define PNPmouseB    "PNP0F0B"       /* Microsoft PNP Ballpoint Mouse         */
+
+/* Modems */
+
+#define PNPmodem0    "PNP9000"       /* Specific IDs TBD                      */
+
+/* Network controllers */
+
+#define PNPnetworkC9 "PNP80C9"       /* IBM Token Ring                        */
+#define PNPnetworkCA "PNP80CA"       /* IBM Token Ring II                     */
+#define PNPnetworkCB "PNP80CB"       /* IBM Token Ring II/Short               */
+#define PNPnetworkCC "PNP80CC"       /* IBM Token Ring 4/16Mbs                */
+#define PNPnetwork27 "PNP8327"       /* IBM Token Ring (All types)            */
+#define PNPnetworket "IBM0010"       /* IBM Ethernet used by Power PC         */
+#define PNPneteisaet "IBM2001"       /* IBM Ethernet EISA adapter             */
+#define PNPAMD79C970 "IBM0016"       /* AMD 79C970 (PCI Ethernet)             */
+
+/* SCSI controllers */
+
+#define PNPscsi0     "PNPA000"       /* Adaptec 154x Compatible SCSI Cntlr    */
+#define PNPscsi1     "PNPA001"       /* Adaptec 174x Compatible SCSI Cntlr    */
+#define PNPscsi2     "PNPA002"       /* Future Domain 16-700 Compat SCSI Cntlr*/
+#define PNPscsi3     "PNPA003"       /* Panasonic CDROM Adapter (SBPro/SB16)  */
+#define PNPscsiF     "IBM000F"       /* NCR 810 SCSI Controller               */
+#define PNPscsi825   "IBM001B"       /* NCR 825 SCSI Controller               */
+#define PNPscsi875   "IBM0018"       /* NCR 875 SCSI Controller               */
+
+/* Sound/Video, Multimedia */
+
+#define PNPmm0       "PNPB000"       /* Sound Blaster Compatible Sound Device */
+#define PNPmm1       "PNPB001"       /* MS Windows Sound System Compat Device */
+#define PNPmmF       "IBM000E"       /* Crystal CS4231 Audio Device           */
+#define PNPv7310     "IBM0015"       /* ASCII V7310 Video Capture Device      */
+#define PNPmm4232    "IBM0017"       /* Crystal CS4232 Audio Device           */
+#define PNPpmsyn     "IBM001D"       /* YMF 289B chip (Yamaha)                */
+#define PNPgp4232    "IBM0012"       /* Crystal CS4232 Game Port              */
+#define PNPmidi4232  "IBM0013"       /* Crystal CS4232 MIDI                   */
+
+/* Operator Panel */
+#define PNPopctl     "IBM000B"       /* Operator's panel                      */
+
+/* Service Processor */
+#define PNPsp        "IBM0011"       /* IBM Service Processor                 */
+#define PNPLTsp      "IBM001E"       /* Lightning/Terlingua Support Processor */
+#define PNPLTmsp     "IBM001F"       /* Lightning/Terlingua Mini-SP           */
+
+/* Memory Controller */
+#define PNPmemctl    "IBM000A"       /* Memory controller                     */
+
+/* Graphics Assist */
+#define PNPg_assist  "IBM0014"       /* Graphics Assist                       */
+
+/* Miscellaneous Device Controllers */
+#define PNPtablet    "IBM0019"       /* IBM Tablet Controller                 */
+
+/* PNP Packet Handles */
+
+#define S1_Packet                0x0A   /* Version resource                   */
+#define S2_Packet                0x15   /* Logical DEVID (without flags)      */
+#define S2_Packet_flags          0x16   /* Logical DEVID (with flags)         */
+#define S3_Packet                0x1C   /* Compatible device ID               */
+#define S4_Packet                0x22   /* IRQ resource (without flags)       */
+#define S4_Packet_flags          0x23   /* IRQ resource (with flags)          */
+#define S5_Packet                0x2A   /* DMA resource                       */
+#define S6_Packet                0x30   /* Depend funct start (w/o priority)  */
+#define S6_Packet_priority       0x31   /* Depend funct start (w/ priority)   */
+#define S7_Packet                0x38   /* Depend funct end                   */
+#define S8_Packet                0x47   /* I/O port resource (w/o fixed loc)  */
+#define S9_Packet_fixed          0x4B   /* I/O port resource (w/ fixed loc)   */
+#define S14_Packet               0x71   /* Vendor defined                     */
+#define S15_Packet               0x78   /* End of resource (w/o checksum)     */
+#define S15_Packet_checksum      0x79   /* End of resource (w/ checksum)      */
+#define L1_Packet                0x81   /* Memory range                       */
+#define L1_Shadow                0x20   /* Memory is shadowable               */
+#define L1_32bit_mem             0x18   /* 32-bit memory only                 */
+#define L1_8_16bit_mem           0x10   /* 8- and 16-bit supported            */
+#define L1_Decode_Hi             0x04   /* decode supports high address       */
+#define L1_Cache                 0x02   /* read cacheable, write-through      */
+#define L1_Writeable             0x01   /* Memory is writeable                */
+#define L2_Packet                0x82   /* ANSI ID string                     */
+#define L3_Packet                0x83   /* Unicode ID string                  */
+#define L4_Packet                0x84   /* Vendor defined                     */
+#define L5_Packet                0x85   /* Large I/O                          */
+#define L6_Packet                0x86   /* 32-bit Fixed Loc Mem Range Desc    */
+#define END_TAG                  0x78   /* End of resource                    */
+#define DF_START_TAG             0x30   /* Dependent function start           */
+#define DF_START_TAG_priority    0x31   /* Dependent function start           */
+#define DF_END_TAG               0x38   /* Dependent function end             */
+#define SUBOPTIMAL_CONFIGURATION 0x2    /* Priority byte sub optimal config   */
+
+/* Device Base Type Codes */
+
+typedef enum _PnP_BASE_TYPE {
+  Reserved = 0,
+  MassStorageDevice = 1,
+  NetworkInterfaceController = 2,
+  DisplayController = 3,
+  MultimediaController = 4,
+  MemoryController = 5,
+  BridgeController = 6,
+  CommunicationsDevice = 7,
+  SystemPeripheral = 8,
+  InputDevice = 9,
+  ServiceProcessor = 0x0A,              /* 11/2/95                            */
+  } PnP_BASE_TYPE;
+
+/* Device Sub Type Codes */
+
+typedef enum _PnP_SUB_TYPE {
+  SCSIController = 0,
+  IDEController = 1,
+  FloppyController = 2,
+  IPIController = 3,
+  OtherMassStorageController = 0x80,
+
+  EthernetController = 0,
+  TokenRingController = 1,
+  FDDIController = 2,
+  OtherNetworkController = 0x80,
+
+  VGAController= 0,
+  SVGAController= 1,
+  XGAController= 2,
+  OtherDisplayController = 0x80,
+
+  VideoController = 0,
+  AudioController = 1,
+  OtherMultimediaController = 0x80,
+
+  RAM = 0,
+  FLASH = 1,
+  OtherMemoryDevice = 0x80,
+
+  HostProcessorBridge = 0,
+  ISABridge = 1,
+  EISABridge = 2,
+  MicroChannelBridge = 3,
+  PCIBridge = 4,
+  PCMCIABridge = 5,
+  VMEBridge = 6,
+  OtherBridgeDevice = 0x80,
+
+  RS232Device = 0,
+  ATCompatibleParallelPort = 1,
+  OtherCommunicationsDevice = 0x80,
+
+  ProgrammableInterruptController = 0,
+  DMAController = 1,
+  SystemTimer = 2,
+  RealTimeClock = 3,
+  L2Cache = 4,
+  NVRAM = 5,
+  PowerManagement = 6,
+  CMOS = 7,
+  OperatorPanel = 8,
+  ServiceProcessorClass1 = 9,
+  ServiceProcessorClass2 = 0xA,
+  ServiceProcessorClass3 = 0xB,
+  GraphicAssist = 0xC,
+  SystemPlanar = 0xF,                   /* 10/5/95                            */
+  OtherSystemPeripheral = 0x80,
+
+  KeyboardController = 0,
+  Digitizer = 1,
+  MouseController = 2,
+  TabletController = 3,                 /* 10/27/95                           */
+  OtherInputController = 0x80,
+
+  GeneralMemoryController = 0,
+  } PnP_SUB_TYPE;
+
+/* Device Interface Type Codes */
+
+typedef enum _PnP_INTERFACE {
+  General = 0,
+  GeneralSCSI = 0,
+  GeneralIDE = 0,
+  ATACompatible = 1,
+
+  GeneralFloppy = 0,
+  Compatible765 = 1,
+  NS398_Floppy = 2,                     /* NS Super I/O wired to use index
+                                           register at port 398 and data
+                                           register at port 399               */
+  NS26E_Floppy = 3,                     /* Ports 26E and 26F                  */
+  NS15C_Floppy = 4,                     /* Ports 15C and 15D                  */
+  NS2E_Floppy = 5,                      /* Ports 2E and 2F                    */
+  CHRP_Floppy = 6,                      /* CHRP Floppy in PR*P system         */
+
+  GeneralIPI = 0,
+
+  GeneralEther = 0,
+  GeneralToken = 0,
+  GeneralFDDI = 0,
+
+  GeneralVGA = 0,
+  GeneralSVGA = 0,
+  GeneralXGA = 0,
+
+  GeneralVideo = 0,
+  GeneralAudio = 0,
+  CS4232Audio = 1,                      /* CS 4232 Plug 'n Play Configured    */
+
+  GeneralRAM = 0,
+  GeneralFLASH = 0,
+  PCIMemoryController = 0,              /* PCI Config Method                  */
+  RS6KMemoryController = 1,             /* RS6K Config Method                 */
+
+  GeneralHostBridge = 0,
+  GeneralISABridge = 0,
+  GeneralEISABridge = 0,
+  GeneralMCABridge = 0,
+  GeneralPCIBridge = 0,
+  PCIBridgeDirect = 0,
+  PCIBridgeIndirect = 1,
+  PCIBridgeRS6K = 2,
+  GeneralPCMCIABridge = 0,
+  GeneralVMEBridge = 0,
+
+  GeneralRS232 = 0,
+  COMx = 1,
+  Compatible16450 = 2,
+  Compatible16550 = 3,
+  NS398SerPort = 4,                     /* NS Super I/O wired to use index
+                                           register at port 398 and data
+                                           register at port 399               */
+  NS26ESerPort = 5,                     /* Ports 26E and 26F                  */
+  NS15CSerPort = 6,                     /* Ports 15C and 15D                  */
+  NS2ESerPort = 7,                      /* Ports 2E and 2F                    */
+
+  GeneralParPort = 0,
+  LPTx = 1,
+  NS398ParPort = 2,                     /* NS Super I/O wired to use index
+                                           register at port 398 and data
+                                           register at port 399               */
+  NS26EParPort = 3,                     /* Ports 26E and 26F                  */
+  NS15CParPort = 4,                     /* Ports 15C and 15D                  */
+  NS2EParPort = 5,                      /* Ports 2E and 2F                    */
+
+  GeneralPIC = 0,
+  ISA_PIC = 1,
+  EISA_PIC = 2,
+  MPIC = 3,
+  RS6K_PIC = 4,
+
+  GeneralDMA = 0,
+  ISA_DMA = 1,
+  EISA_DMA = 2,
+
+  GeneralTimer = 0,
+  ISA_Timer = 1,
+  EISA_Timer = 2,
+  GeneralRTC = 0,
+  ISA_RTC = 1,
+
+  StoreThruOnly = 1,
+  StoreInEnabled = 2,
+  RS6KL2Cache = 3,
+
+  IndirectNVRAM = 0,                    /* Indirectly addressed               */
+  DirectNVRAM = 1,                      /* Memory Mapped                      */
+  IndirectNVRAM24 = 2,                  /* Indirectly addressed - 24 bit      */
+
+  GeneralPowerManagement = 0,
+  EPOWPowerManagement = 1,
+  PowerControl = 2,                    /* d1378 */
+
+  GeneralCMOS = 0,
+
+  GeneralOPPanel = 0,
+  HarddiskLight = 1,
+  CDROMLight = 2,
+  PowerLight = 3,
+  KeyLock = 4,
+  ANDisplay = 5,                        /* AlphaNumeric Display               */
+  SystemStatusLED = 6,                  /* 3 digit 7 segment LED              */
+  CHRP_SystemStatusLED = 7,             /* CHRP LEDs in PR*P system           */
+
+  GeneralServiceProcessor = 0,
+
+  TransferData = 1,
+  IGMC32 = 2,
+  IGMC64 = 3,
+
+  GeneralSystemPlanar = 0,              /* 10/5/95                            */
+
+  } PnP_INTERFACE;
+
+/* PnP resources */
+
+/* Compressed ASCII is 5 bits per char; 00001=A ... 11010=Z */
+
+typedef struct _SERIAL_ID {
+  unsigned char VendorID0;              /*    Bit(7)=0                        */
+                                        /*    Bits(6:2)=1st character in      */
+                                        /*       compressed ASCII             */
+                                        /*    Bits(1:0)=2nd character in      */
+                                        /*       compressed ASCII bits(4:3)   */
+  unsigned char VendorID1;              /*    Bits(7:5)=2nd character in      */
+                                        /*       compressed ASCII bits(2:0)   */
+                                        /*    Bits(4:0)=3rd character in      */
+                                        /*       compressed ASCII             */
+  unsigned char VendorID2;              /* Product number - vendor assigned   */
+  unsigned char VendorID3;              /* Product number - vendor assigned   */
+
+/* Serial number is to provide uniqueness if more than one board of same      */
+/* type is in system.  Must be "FFFFFFFF" if feature not supported.           */
+
+  unsigned char Serial0;                /* Unique serial number bits (7:0)    */
+  unsigned char Serial1;                /* Unique serial number bits (15:8)   */
+  unsigned char Serial2;                /* Unique serial number bits (23:16)  */
+  unsigned char Serial3;                /* Unique serial number bits (31:24)  */
+  unsigned char Checksum;
+  } SERIAL_ID;
+
+typedef enum _PnPItemName {
+  Unused = 0,
+  PnPVersion = 1,
+  LogicalDevice = 2,
+  CompatibleDevice = 3,
+  IRQFormat = 4,
+  DMAFormat = 5,
+  StartDepFunc = 6,
+  EndDepFunc = 7,
+  IOPort = 8,
+  FixedIOPort = 9,
+  Res1 = 10,
+  Res2 = 11,
+  Res3 = 12,
+  SmallVendorItem = 14,
+  EndTag = 15,
+  MemoryRange = 1,
+  ANSIIdentifier = 2,
+  UnicodeIdentifier = 3,
+  LargeVendorItem = 4,
+  MemoryRange32 = 5,
+  MemoryRangeFixed32 = 6,
+  } PnPItemName;
+
+/* Define a bunch of access functions for the bits in the tag field */
+
+/* Tag type - 0 = small; 1 = large */
+#define tag_type(t) (((t) & 0x80)>>7)
+#define set_tag_type(t,v) (t = (t & 0x7f) | ((v)<<7))
+
+/* Small item name is 4 bits - one of PnPItemName enum above */
+#define tag_small_item_name(t) (((t) & 0x78)>>3)
+#define set_tag_small_item_name(t,v) (t = (t & 0x07) | ((v)<<3))
+
+/* Small item count is 3 bits - count of further bytes in packet */
+#define tag_small_count(t) ((t) & 0x07)
+#define set_tag_count(t,v) (t = (t & 0x78) | (v))
+
+/* Large item name is 7 bits - one of PnPItemName enum above */
+#define tag_large_item_name(t) ((t) & 0x7f)
+#define set_tag_large_item_name(t,v) (t = (t | 0x80) | (v))
+
+/* a PnP resource is a bunch of contiguous TAG packets ending with an end tag */
+
+typedef union _PnP_TAG_PACKET {
+  struct _S1_Pack{                      /* VERSION PACKET                     */
+    unsigned char Tag;                  /* small tag = 0x0a                   */
+    unsigned char Version[2];           /* PnP version, Vendor version        */
+    } S1_Pack;
+
+  struct _S2_Pack{                      /* LOGICAL DEVICE ID PACKET           */
+    unsigned char Tag;                  /* small tag = 0x15 or 0x16           */
+    unsigned char DevId[4];             /* Logical device id                  */
+    unsigned char Flags[2];             /* bit(0) boot device;                */
+                                        /* bit(7:1) cmd in range x31-x37      */
+                                        /* bit(7:0) cmd in range x28-x3f (opt)*/
+    } S2_Pack;
+
+  struct _S3_Pack{                      /* COMPATIBLE DEVICE ID PACKET        */
+    unsigned char Tag;                  /* small tag = 0x1c                   */
+    unsigned char CompatId[4];          /* Compatible device id               */
+    } S3_Pack;
+
+  struct _S4_Pack{                      /* IRQ PACKET                         */
+    unsigned char Tag;                  /* small tag = 0x22 or 0x23           */
+    unsigned char IRQMask[2];           /* bit(0) is IRQ0, ...;               */
+                                        /* bit(0) is IRQ8 ...                 */
+    unsigned char IRQInfo;              /* optional; assume bit(0)=1; else    */
+                                        /*  bit(0) - high true edge sensitive */
+                                        /*  bit(1) - low true edge sensitive  */
+                                        /*  bit(2) - high true level sensitive*/
+                                        /*  bit(3) - low true level sensitive */
+                                        /*  bit(7:4) - must be 0              */
+    } S4_Pack;
+
+  struct _S5_Pack{                      /* DMA PACKET                         */
+    unsigned char Tag;                  /* small tag = 0x2a                   */
+    unsigned char DMAMask;              /* bit(0) is channel 0 ...            */
+    unsigned char DMAInfo;
+    } S5_Pack;
+
+  struct _S6_Pack{                      /* START DEPENDENT FUNCTION PACKET    */
+    unsigned char Tag;                  /* small tag = 0x30 or 0x31           */
+    unsigned char Priority;             /* Optional; if missing then x01; else*/
+                                        /*  x00 = best possible               */
+                                        /*  x01 = acceptible                  */
+                                        /*  x02 = sub-optimal but functional  */
+    } S6_Pack;
+
+  struct _S7_Pack{                      /* END DEPENDENT FUNCTION PACKET      */
+    unsigned char Tag;                  /* small tag = 0x38                   */
+    } S7_Pack;
+
+  struct _S8_Pack{                      /* VARIABLE I/O PORT PACKET           */
+    unsigned char Tag;                  /* small tag x47                      */
+    unsigned char IOInfo;               /* x0  = decode only bits(9:0);       */
+#define  ISAAddr16bit         0x01      /* x01 = decode bits(15:0)            */
+    unsigned char RangeMin[2];          /* Min base address                   */
+    unsigned char RangeMax[2];          /* Max base address                   */
+    unsigned char IOAlign;              /* base alignmt, incr in 1B blocks    */
+    unsigned char IONum;                /* number of contiguous I/O ports     */
+    } S8_Pack;
+
+  struct _S9_Pack{                      /* FIXED I/O PORT PACKET              */
+    unsigned char Tag;                  /* small tag = 0x4b                   */
+    unsigned char Range[2];             /* base address 10 bits               */
+    unsigned char IONum;                /* number of contiguous I/O ports     */
+    } S9_Pack;
+
+  struct _S14_Pack{                     /* VENDOR DEFINED PACKET              */
+    unsigned char Tag;                  /* small tag = 0x7m m = 1-7           */
+    union _S14_Data{
+      unsigned char Data[7];            /* Vendor defined                     */
+      struct _S14_PPCPack{              /* Pr*p s14 pack                      */
+         unsigned char Type;            /* 00=non-IBM                         */
+         unsigned char PPCData[6];      /* Vendor defined                     */
+        } S14_PPCPack;
+      } S14_Data;
+    } S14_Pack;
+
+  struct _S15_Pack{                     /* END PACKET                         */
+    unsigned char Tag;                  /* small tag = 0x78 or 0x79           */
+    unsigned char Check;                /* optional - checksum                */
+    } S15_Pack;
+
+  struct _L1_Pack{                      /* MEMORY RANGE PACKET                */
+    unsigned char Tag;                  /* large tag = 0x81                   */
+    unsigned char Count0;               /* x09                                */
+    unsigned char Count1;               /* x00                                */
+    unsigned char Data[9];              /* a variable array of bytes,         */
+                                        /* count in tag                       */
+    } L1_Pack;
+
+  struct _L2_Pack{                      /* ANSI ID STRING PACKET              */
+    unsigned char Tag;                  /* large tag = 0x82                   */
+    unsigned char Count0;               /* Length of string                   */
+    unsigned char Count1;
+    unsigned char Identifier[1];        /* a variable array of bytes,         */
+                                        /* count in tag                       */
+    } L2_Pack;
+
+  struct _L3_Pack{                      /* UNICODE ID STRING PACKET           */
+    unsigned char Tag;                  /* large tag = 0x83                   */
+    unsigned char Count0;               /* Length + 2 of string               */
+    unsigned char Count1;
+    unsigned char Country0;             /* TBD                                */
+    unsigned char Country1;             /* TBD                                */
+    unsigned char Identifier[1];        /* a variable array of bytes,         */
+                                        /* count in tag                       */
+    } L3_Pack;
+
+  struct _L4_Pack{                      /* VENDOR DEFINED PACKET              */
+    unsigned char Tag;                  /* large tag = 0x84                   */
+    unsigned char Count0;
+    unsigned char Count1;
+    union _L4_Data{
+      unsigned char Data[1];            /* a variable array of bytes,         */
+                                        /* count in tag                       */
+      struct _L4_PPCPack{               /* Pr*p L4 packet                     */
+         unsigned char Type;            /* 00=non-IBM                         */
+         unsigned char PPCData[1];      /* a variable array of bytes,         */
+                                        /* count in tag                       */
+        } L4_PPCPack;
+      } L4_Data;
+    } L4_Pack;
+
+  struct _L5_Pack{
+    unsigned char Tag;                  /* large tag = 0x85                   */
+    unsigned char Count0;               /* Count = 17                         */
+    unsigned char Count1;
+    unsigned char Data[17];
+    } L5_Pack;
+
+  struct _L6_Pack{
+    unsigned char Tag;                  /* large tag = 0x86                   */
+    unsigned char Count0;               /* Count = 9                          */
+    unsigned char Count1;
+    unsigned char Data[9];
+    } L6_Pack;
+
+  } PnP_TAG_PACKET;
+
+#endif /* __ASSEMBLY__ */
+#endif  /* ndef _PNP_ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/poll.h linux-2.4.19-pre5/include/asm-ppc64/poll.h
--- linux-2.4.19-pre4/include/asm-ppc64/poll.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/poll.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,31 @@
+#ifndef __PPC64_POLL_H
+#define __PPC64_POLL_H
+
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define POLLIN		0x0001
+#define POLLPRI		0x0002
+#define POLLOUT		0x0004
+#define POLLERR		0x0008
+#define POLLHUP		0x0010
+#define POLLNVAL	0x0020
+#define POLLRDNORM	0x0040
+#define POLLRDBAND	0x0080
+#define POLLWRNORM	0x0100
+#define POLLWRBAND	0x0200
+#define POLLMSG		0x0400
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif /* __PPC64_POLL_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/posix_types.h linux-2.4.19-pre5/include/asm-ppc64/posix_types.h
--- linux-2.4.19-pre4/include/asm-ppc64/posix_types.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/posix_types.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,141 @@
+#ifndef _PPC64_POSIX_TYPES_H
+#define _PPC64_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+typedef unsigned int	__kernel_dev_t;
+typedef unsigned int	__kernel_ino_t;
+typedef unsigned int	__kernel_mode_t;
+typedef unsigned int  	__kernel_nlink_t;
+typedef long		__kernel_off_t;
+typedef long long	        __kernel_loff_t;
+typedef int		__kernel_pid_t;
+typedef int             __kernel_ipc_pid_t;
+typedef unsigned int	__kernel_uid_t;
+typedef unsigned int	__kernel_gid_t;
+typedef unsigned long	__kernel_size_t;
+typedef long		__kernel_ssize_t;
+typedef long		__kernel_ptrdiff_t;
+typedef long		__kernel_time_t;
+typedef long		__kernel_suseconds_t;
+typedef long		__kernel_clock_t;
+typedef int		__kernel_daddr_t;
+typedef char *		__kernel_caddr_t;
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
+typedef unsigned int	__kernel_uid32_t;
+typedef unsigned int	__kernel_gid32_t;
+
+typedef unsigned int	__kernel_old_uid_t;
+typedef unsigned int	__kernel_old_gid_t;
+
+typedef struct {
+	int	val[2];
+} __kernel_fsid_t;
+
+
+/* These are here to support 32-bit syscalls on a 64-bit kernel. */
+typedef unsigned int           __kernel_size_t32;
+typedef int                    __kernel_ssize_t32;
+typedef int                    __kernel_ptrdiff_t32;
+typedef int                    __kernel_time_t32;
+typedef int                    __kernel_clock_t32;
+typedef int                    __kernel_pid_t32;
+typedef unsigned short         __kernel_ipc_pid_t32;
+typedef unsigned int           __kernel_uid_t32;
+typedef unsigned int           __kernel_gid_t32;
+typedef unsigned int           __kernel_dev_t32;
+typedef unsigned int           __kernel_ino_t32;
+typedef unsigned int           __kernel_mode_t32;
+typedef unsigned int           __kernel_umode_t32;
+typedef short                  __kernel_nlink_t32;
+typedef int                    __kernel_daddr_t32;
+typedef int                    __kernel_off_t32;
+typedef unsigned int           __kernel_caddr_t32;
+typedef int 		       __kernel_loff_t32;
+/* typedef __kernel_fsid_t        __kernel_fsid_t32; */
+
+
+
+#ifndef __GNUC__
+
+#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+#define	__FD_ISSET(d, set)	((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+#define	__FD_ZERO(set)	\
+  ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+
+#else /* __GNUC__ */
+
+#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
+static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
+{ 
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *p)
+{
+	unsigned long *tmp = (unsigned long *)p->fds_bits;
+	int i;
+
+	if (__builtin_constant_p(__FDSET_LONGS)) {
+		switch (__FDSET_LONGS) {
+		      case 16:
+			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+
+		      case 8:
+			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+
+		      case 4:
+			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			return;
+		}
+	}
+	i = __FDSET_LONGS;
+	while (i) {
+		i--;
+		*tmp = 0;
+		tmp++;
+	}
+}
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+#endif /* __GNUC__ */
+#endif /* _PPC64_POSIX_TYPES_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ppc32.h linux-2.4.19-pre5/include/asm-ppc64/ppc32.h
--- linux-2.4.19-pre4/include/asm-ppc64/ppc32.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ppc32.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,232 @@
+#ifndef _PPC64_PPC32_H
+#define _PPC64_PPC32_H
+
+#include <asm/siginfo.h>
+#include <asm/signal.h>
+
+/*
+ * Data types and macros for providing 32b PowerPC support.
+ * 
+ * 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.
+ */
+
+#ifndef __KERNEL_STRICT_NAMES
+#include <linux/types.h>
+typedef __kernel_fsid_t __kernel_fsid_t32;
+#endif
+
+/* Use this to get at 32-bit user passed pointers. */
+/* Things to consider: the low-level assembly stub does
+   srl x, 0, x for first four arguments, so if you have
+   pointer to something in the first four arguments, just
+   declare it as a pointer, not u32. On the other side, 
+   arguments from 5th onwards should be declared as u32
+   for pointers, and need AA() around each usage.
+   A() macro should be used for places where you e.g.
+   have some internal variable u32 and just want to get
+   rid of a compiler warning. AA() has to be used in
+   places where you want to convert a function argument
+   to 32bit pointer or when you e.g. access pt_regs
+   structure and want to consider 32bit registers only.
+   -
+ */
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x)				\
+({	unsigned long __ret;		\
+	__asm__ ("clrldi	%0, %0, 32"	\
+		 : "=r" (__ret)		\
+		 : "0" (__x));		\
+	__ret;				\
+})
+
+/* These are here to support 32-bit syscalls on a 64-bit kernel. */
+typedef unsigned int           __kernel_size_t32;
+typedef int                    __kernel_ssize_t32;
+typedef int                    __kernel_ptrdiff_t32;
+typedef int                    __kernel_time_t32;
+typedef int                    __kernel_clock_t32;
+typedef int                    __kernel_pid_t32;
+typedef unsigned short         __kernel_ipc_pid_t32;
+typedef unsigned int           __kernel_uid_t32;
+typedef unsigned int           __kernel_gid_t32;
+typedef unsigned int           __kernel_dev_t32;
+typedef unsigned int           __kernel_ino_t32;
+typedef unsigned int           __kernel_mode_t32;
+typedef unsigned int           __kernel_umode_t32;
+typedef short                  __kernel_nlink_t32;
+typedef int                    __kernel_daddr_t32;
+typedef int                    __kernel_off_t32;
+typedef unsigned int           __kernel_caddr_t32;
+typedef int 		       __kernel_loff_t32;
+/* typedef __kernel_fsid_t        __kernel_fsid_t32; */
+
+struct statfs32 {
+	int f_type;
+	int f_bsize;
+	int f_blocks;
+	int f_bfree;
+	int f_bavail;
+	int f_files;
+	int f_ffree;
+	__kernel_fsid_t32 f_fsid;
+	int f_namelen;  /* SunOS ignores this field. */
+	int f_spare[6];
+};
+
+typedef union sigval32 {
+	int sival_int;
+	unsigned int sival_ptr;
+} sigval_t32;
+
+typedef struct siginfo32 {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			__kernel_pid_t32 _pid;		/* sender's pid */
+			unsigned int _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			__kernel_pid_t32 _pid;		/* sender's pid */
+			unsigned int _uid;		/* sender's uid */
+			sigval_t32 _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			__kernel_pid_t32 _pid;		/* which child */
+			unsigned int _uid;		/* sender's uid */
+			int _status;			/* exit code */
+			__kernel_clock_t32 _utime;
+			__kernel_clock_t32 _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
+		struct {
+			u32 _addr; /* faulting insn/memory ref. */
+			int _trapno;
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t32;
+
+#define __old_sigset_t32	old_sigset_t32
+#define __old_sigaction32	old_sigaction32
+
+typedef unsigned int __old_sigset_t32;
+struct __old_sigaction32 {
+	unsigned		sa_handler;
+	__old_sigset_t32  	sa_mask;
+	unsigned int    	sa_flags;
+	unsigned		sa_restorer;     /* not used by Linux/SPARC yet */
+};
+
+
+
+#define _PPC32_NSIG	       64
+#define _PPC32_NSIG_BPW	       32
+#define _PPC32_NSIG_WORDS	       (_PPC32_NSIG / _PPC32_NSIG_BPW)
+
+typedef struct {
+       unsigned int sig[_PPC32_NSIG_WORDS];
+} sigset32_t;
+
+struct sigaction32 {
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+					     with 32 bits */
+       unsigned int sa_flags;
+       unsigned int sa_restorer;	/* Another 32 bit pointer */
+       sigset32_t sa_mask;		/* A 32 bit mask */
+};
+
+typedef struct sigaltstack_32 {
+	unsigned int ss_sp;
+	int ss_flags;
+	__kernel_size_t32 ss_size;
+} stack_32_t;
+
+struct flock32 {
+	short l_type;
+	short l_whence;
+	__kernel_off_t32 l_start;
+	__kernel_off_t32 l_len;
+	__kernel_pid_t32 l_pid;
+	short __unused;
+};
+
+struct stat32 {
+	__kernel_dev_t32   st_dev; /* 2 */
+	/* __kernel_dev_t32 __pad1; */ /* 2 */
+	__kernel_ino_t32   st_ino; /* 4  */
+	__kernel_mode_t32  st_mode; /* 2  */
+	short   	   st_nlink; /* 2 */
+	__kernel_uid_t32   st_uid; /* 2 */
+	__kernel_gid_t32   st_gid; /* 2 */
+	__kernel_dev_t32   st_rdev; /* 2 */
+	/* __kernel_dev_t32 __pad2; */ /* 2 */
+	__kernel_off_t32   st_size; /* 4 */
+	__kernel_off_t32   st_blksize; /* 4 */
+	__kernel_off_t32   st_blocks; /* 4 */
+	__kernel_time_t32  st_atime; /* 4 */
+	unsigned int       __unused1; /* 4 */
+	__kernel_time_t32  st_mtime; /* 4 */
+	unsigned int       __unused2; /* 4 */
+	__kernel_time_t32  st_ctime; /* 4 */
+	unsigned int       __unused3; /* 4 */
+	unsigned int  __unused4[2]; /* 2*4 */
+};
+
+struct __old_kernel_stat32
+{
+	unsigned short st_dev;
+	unsigned short st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned int   st_size;
+	unsigned int   st_atime;
+	unsigned int   st_mtime;
+	unsigned int   st_ctime;
+};
+
+struct sigcontext32_struct {
+	unsigned int	_unused[4];
+	int		signal;
+	unsigned int	handler;
+	unsigned int	oldmask;
+	u32 regs;  /* 4 byte pointer to the pt_regs32 structure. */
+};
+
+struct ucontext32 { 
+	unsigned int	  uc_flags;
+	unsigned int 	  uc_link;
+	stack_32_t	  uc_stack;
+	struct sigcontext32_struct uc_mcontext;
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+
+#endif  /* _PPC64_PPC32_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ppcdebug.h linux-2.4.19-pre5/include/asm-ppc64/ppcdebug.h
--- linux-2.4.19-pre4/include/asm-ppc64/ppcdebug.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ppcdebug.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,115 @@
+#ifndef __PPCDEBUG_H
+#define __PPCDEBUG_H
+/********************************************************************
+ * Author: Adam Litke, IBM Corp
+ * (c) 2001
+ *
+ * This file contains definitions and macros for a runtime debugging
+ * system for ppc64 (This should also work on 32 bit with a few    
+ * adjustments.                                                   
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <asm/udbg.h>
+#include <stdarg.h>
+
+#define PPCDBG_BITVAL(X)     ((1UL)<<((unsigned long)(X)))
+
+/* Defined below are the bit positions of various debug flags in the
+ * debug_switch variable (defined in Naca.h).
+ * -- When adding new values, please enter them into trace names below -- 
+ *
+ * Values 62 & 63 can be used to stress the hardware page table management
+ * code.  They must be set statically, any attempt to change them dynamically
+ * would be a very bad idea.
+ */
+#define PPCDBG_MMINIT        PPCDBG_BITVAL(0)
+#define PPCDBG_MM            PPCDBG_BITVAL(1)
+#define PPCDBG_SYS32         PPCDBG_BITVAL(2)
+#define PPCDBG_SYS32NI       PPCDBG_BITVAL(3)
+#define PPCDBG_SYS32X	     PPCDBG_BITVAL(4)
+#define PPCDBG_SYS32M	     PPCDBG_BITVAL(5)
+#define PPCDBG_SYS64         PPCDBG_BITVAL(6)
+#define PPCDBG_SYS64NI       PPCDBG_BITVAL(7)
+#define PPCDBG_SYS64X	     PPCDBG_BITVAL(8)
+#define PPCDBG_SIGNAL        PPCDBG_BITVAL(9)
+#define PPCDBG_SIGNALXMON    PPCDBG_BITVAL(10)
+#define PPCDBG_BINFMT32      PPCDBG_BITVAL(11)
+#define PPCDBG_BINFMT64      PPCDBG_BITVAL(12)
+#define PPCDBG_BINFMTXMON    PPCDBG_BITVAL(13)
+#define PPCDBG_BINFMT_32ADDR PPCDBG_BITVAL(14)
+#define PPCDBG_ALIGNFIXUP    PPCDBG_BITVAL(15)
+#define PPCDBG_TCEINIT       PPCDBG_BITVAL(16)
+#define PPCDBG_TCE           PPCDBG_BITVAL(17)
+#define PPCDBG_PHBINIT       PPCDBG_BITVAL(18)
+#define PPCDBG_SMP           PPCDBG_BITVAL(19)
+#define PPCDBG_BOOT          PPCDBG_BITVAL(20)
+#define PPCDBG_BUSWALK       PPCDBG_BITVAL(21)
+#define PPCDBG_HTABSTRESS    PPCDBG_BITVAL(62)
+#define PPCDBG_HTABSIZE      PPCDBG_BITVAL(63)
+#define PPCDBG_NONE          (0UL)
+#define PPCDBG_ALL           (0xffffffffUL)
+
+/* The default initial value for the debug switch */
+#define PPC_DEBUG_DEFAULT    0 
+/* #define PPC_DEBUG_DEFAULT    PPCDBG_ALL        */
+
+#define PPCDBG_NUM_FLAGS     64
+
+#ifdef WANT_PPCDBG_TAB
+/* A table of debug switch names to allow name lookup in xmon 
+ * (and whoever else wants it.
+ */
+char *trace_names[PPCDBG_NUM_FLAGS] = {
+	/* Known debug names */
+	"mminit", 	"mm",
+	"syscall32", 	"syscall32_ni", "syscall32x",	"syscall32m",
+	"syscall64", 	"syscall64_ni", "syscall64x",
+	"signal",	"signal_xmon",
+	"binfmt32",	"binfmt64",	"binfmt_xmon",	"binfmt_32addr",
+	"alignfixup",   "tceinit",      "tce",          "phb_init",     
+	"smp",          "boot",         "buswalk"
+};
+#else
+extern char *trace_names[64];
+#endif /* WANT_PPCDBG_TAB */
+
+#ifdef CONFIG_PPCDBG
+/* Macro to conditionally print debug based on debug_switch */
+#define PPCDBG(...) udbg_ppcdbg(__VA_ARGS__)
+
+/* Macro to conditionally call a debug routine based on debug_switch */
+#define PPCDBGCALL(FLAGS,FUNCTION) ifppcdebug(FLAGS) FUNCTION
+
+/* Macros to test for debug states */
+#define ifppcdebug(FLAGS) if (udbg_ifdebug(FLAGS))
+#define ppcdebugset(FLAGS) (udbg_ifdebug(FLAGS))
+#define PPCDBG_BINFMT ((current->thread.flags & PPC_FLAG_32BIT) ? PPCDBG_BINFMT32 : PPCDBG_BINFMT64)
+
+#ifdef CONFIG_XMON
+#define PPCDBG_ENTER_DEBUGGER() xmon(0)
+#define PPCDBG_ENTER_DEBUGGER_REGS(X) xmon(X)
+#endif
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#define PPCDBG_ENTER_DEBUGGER() kdb(KDB_REASON_CALL, 0, 0)
+#endif
+
+#else
+#define PPCDBG(...) do {;} while (0)
+#define PPCDBGCALL(FLAGS,FUNCTION) do {;} while (0)
+#define ifppcdebug(...) if (0)
+#define ppcdebugset(FLAGS) (0)
+#endif /* CONFIG_PPCDBG */
+
+#ifndef PPCDBG_ENTER_DEBUGGER
+#define PPCDBG_ENTER_DEBUGGER() do {;} while(0)
+#endif
+
+#endif /*__PPCDEBUG_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/proc_fs.h linux-2.4.19-pre5/include/asm-ppc64/proc_fs.h
--- linux-2.4.19-pre4/include/asm-ppc64/proc_fs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/proc_fs.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,33 @@
+#ifndef _PPC64_PROC_FS_H
+#define _PPC64_PROC_FS_H
+/*
+ * proc_fs.h
+ * Copyright (C) 2001  Mike Corrigan  IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/* Change Activity: */
+/* tgall -- merge of iSeries/iSeries_proc.h and proc_pmc.h */
+/* End Change Activity */
+
+#include <linux/proc_fs.h>
+
+void pmc_proc_init(struct proc_dir_entry *iSeries_proc);
+void proc_ppc64_init(void);
+
+#include <asm/iSeries/iSeries_proc.h>
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/proc_pmc.h linux-2.4.19-pre5/include/asm-ppc64/proc_pmc.h
--- linux-2.4.19-pre4/include/asm-ppc64/proc_pmc.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/proc_pmc.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,33 @@
+/*
+ * pmc_proc.h
+ * Copyright (C) 2001  Mike Corrigan  IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/* Change Activity: */
+/* End Change Activity */
+
+#ifndef _PMC_PROC_H
+#define _PMC_PROC_H
+
+#include <linux/proc_fs.h>
+
+void pmc_proc_init(struct proc_dir_entry *iSeries_proc);
+void proc_ppc64_init(void);
+
+#endif /* _PMC_PROC_H */
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/processor.h linux-2.4.19-pre5/include/asm-ppc64/processor.h
--- linux-2.4.19-pre4/include/asm-ppc64/processor.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/processor.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,753 @@
+#ifndef __ASM_PPC64_PROCESSOR_H
+#define __ASM_PPC64_PROCESSOR_H
+
+/*
+ * Copyright (C) 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __ASSEMBLY__
+#include <asm/atomic.h>
+#include <asm/ppcdebug.h>
+#include <asm/a.out.h>
+#endif
+#include <asm/ptrace.h>
+#include <asm/types.h>
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+/* Machine State Register (MSR) Fields */
+#define MSR_SF_LG	63              /* Enable 64 bit mode */
+#define MSR_ISF_LG	61              /* Interrupt 64b mode valid on 630 */
+#define MSR_HV_LG 	60              /* Hypervisor state */
+#define MSR_VEC_LG	25	        /* Enable AltiVec */
+#define MSR_POW_LG	18		/* Enable Power Management */
+#define MSR_WE_LG	18		/* Wait State Enable */
+#define MSR_TGPR_LG	17		/* TLB Update registers in use */
+#define MSR_CE_LG	17		/* Critical Interrupt Enable */
+#define MSR_ILE_LG	16		/* Interrupt Little Endian */
+#define MSR_EE_LG	15		/* External Interrupt Enable */
+#define MSR_PR_LG	14		/* Problem State / Privilege Level */
+#define MSR_FP_LG	13		/* Floating Point enable */
+#define MSR_ME_LG	12		/* Machine Check Enable */
+#define MSR_FE0_LG	11		/* Floating Exception mode 0 */
+#define MSR_SE_LG	10		/* Single Step */
+#define MSR_BE_LG	9		/* Branch Trace */
+#define MSR_DE_LG	9 		/* Debug Exception Enable */
+#define MSR_FE1_LG	8		/* Floating Exception mode 1 */
+#define MSR_IP_LG	6		/* Exception prefix 0x000/0xFFF */
+#define MSR_IR_LG	5 		/* Instruction Relocate */
+#define MSR_DR_LG	4 		/* Data Relocate */
+#define MSR_PE_LG	3		/* Protection Enable */
+#define MSR_PX_LG	2		/* Protection Exclusive Mode */
+#define MSR_RI_LG	1		/* Recoverable Exception */
+#define MSR_LE_LG	0 		/* Little Endian */
+
+#ifdef __ASSEMBLY__
+#define MASK(X)		(1<<(X))
+#else
+#define MASK(X)		(1UL<<(X))
+#endif
+
+#define MSR_SF		MASK(MSR_SF_LG)  /* Enable 64 bit mode */
+#define MSR_ISF		MASK(MSR_ISF_LG) /* Interrupt 64b mode valid on 630 */
+#define MSR_HV 		MASK(MSR_HV_LG)	 /* Hypervisor state */
+#define MSR_VEC		MASK(MSR_VEC_LG) /* Enable AltiVec */
+#define MSR_POW		MASK(MSR_POW_LG) /* Enable Power Management */
+#define MSR_WE		MASK(MSR_WE_LG)	 /* Wait State Enable */
+#define MSR_TGPR	MASK(MSR_TGPR_LG)/* TLB Update registers in use */
+#define MSR_CE		MASK(MSR_CE_LG)	 /* Critical Interrupt Enable */
+#define MSR_ILE		MASK(MSR_ILE_LG) /* Interrupt Little Endian */
+#define MSR_EE		MASK(MSR_EE_LG)	 /* External Interrupt Enable */
+#define MSR_PR		MASK(MSR_PR_LG)	 /* Problem State / Privilege Level */
+#define MSR_FP		MASK(MSR_FP_LG)	 /* Floating Point enable */
+#define MSR_ME		MASK(MSR_ME_LG)	 /* Machine Check Enable */
+#define MSR_FE0		MASK(MSR_FE0_LG) /* Floating Exception mode 0 */
+#define MSR_SE		MASK(MSR_SE_LG)	 /* Single Step */
+#define MSR_BE		MASK(MSR_BE_LG)	 /* Branch Trace */
+#define MSR_DE		MASK(MSR_DE_LG)	 /* Debug Exception Enable */
+#define MSR_FE1		MASK(MSR_FE1_LG) /* Floating Exception mode 1 */
+#define MSR_IP		MASK(MSR_IP_LG)	 /* Exception prefix 0x000/0xFFF */
+#define MSR_IR		MASK(MSR_IR_LG)	 /* Instruction Relocate */
+#define MSR_DR		MASK(MSR_DR_LG)	 /* Data Relocate */
+#define MSR_PE		MASK(MSR_PE_LG)	 /* Protection Enable */
+#define MSR_PX		MASK(MSR_PX_LG)	 /* Protection Exclusive Mode */
+#define MSR_RI		MASK(MSR_RI_LG)	 /* Recoverable Exception */
+#define MSR_LE		MASK(MSR_LE_LG)	 /* Little Endian */
+
+#define MSR_		MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF
+#define MSR_KERNEL      MSR_ | MSR_SF | MSR_HV
+
+#define MSR_USER32	MSR_ | MSR_PR | MSR_EE
+#define MSR_USER64	MSR_USER32 | MSR_SF
+
+/* Floating Point Status and Control Register (FPSCR) Fields */
+
+#define FPSCR_FX	0x80000000	/* FPU exception summary */
+#define FPSCR_FEX	0x40000000	/* FPU enabled exception summary */
+#define FPSCR_VX	0x20000000	/* Invalid operation summary */
+#define FPSCR_OX	0x10000000	/* Overflow exception summary */
+#define FPSCR_UX	0x08000000	/* Underflow exception summary */
+#define FPSCR_ZX	0x04000000	/* Zero-devide exception summary */
+#define FPSCR_XX	0x02000000	/* Inexact exception summary */
+#define FPSCR_VXSNAN	0x01000000	/* Invalid op for SNaN */
+#define FPSCR_VXISI	0x00800000	/* Invalid op for Inv - Inv */
+#define FPSCR_VXIDI	0x00400000	/* Invalid op for Inv / Inv */
+#define FPSCR_VXZDZ	0x00200000	/* Invalid op for Zero / Zero */
+#define FPSCR_VXIMZ	0x00100000	/* Invalid op for Inv * Zero */
+#define FPSCR_VXVC	0x00080000	/* Invalid op for Compare */
+#define FPSCR_FR	0x00040000	/* Fraction rounded */
+#define FPSCR_FI	0x00020000	/* Fraction inexact */
+#define FPSCR_FPRF	0x0001f000	/* FPU Result Flags */
+#define FPSCR_FPCC	0x0000f000	/* FPU Condition Codes */
+#define FPSCR_VXSOFT	0x00000400	/* Invalid op for software request */
+#define FPSCR_VXSQRT	0x00000200	/* Invalid op for square root */
+#define FPSCR_VXCVI	0x00000100	/* Invalid op for integer convert */
+#define FPSCR_VE	0x00000080	/* Invalid op exception enable */
+#define FPSCR_OE	0x00000040	/* IEEE overflow exception enable */
+#define FPSCR_UE	0x00000020	/* IEEE underflow exception enable */
+#define FPSCR_ZE	0x00000010	/* IEEE zero divide exception enable */
+#define FPSCR_XE	0x00000008	/* FP inexact exception enable */
+#define FPSCR_NI	0x00000004	/* FPU non IEEE-Mode */
+#define FPSCR_RN	0x00000003	/* FPU rounding control */
+
+/* Special Purpose Registers (SPRNs)*/
+
+#define	SPRN_CDBCR	0x3D7	/* Cache Debug Control Register */
+#define	SPRN_CTR	0x009	/* Count Register */
+#define	SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
+#define	SPRN_DAC1	0x3F6	/* Data Address Compare 1 */
+#define	SPRN_DAC2	0x3F7	/* Data Address Compare 2 */
+#define	SPRN_DAR	0x013	/* Data Address Register */
+#define	SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
+#define	SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
+#define	SPRN_DBAT1L	0x21B	/* Data BAT 1 Lower Register */
+#define	SPRN_DBAT1U	0x21A	/* Data BAT 1 Upper Register */
+#define	SPRN_DBAT2L	0x21D	/* Data BAT 2 Lower Register */
+#define	SPRN_DBAT2U	0x21C	/* Data BAT 2 Upper Register */
+#define	SPRN_DBAT3L	0x21F	/* Data BAT 3 Lower Register */
+#define	SPRN_DBAT3U	0x21E	/* Data BAT 3 Upper Register */
+#define	SPRN_DBCR	0x3F2	/* Debug Control Regsiter */
+#define	  DBCR_EDM	0x80000000
+#define	  DBCR_IDM	0x40000000
+#define	  DBCR_RST(x)	(((x) & 0x3) << 28)
+#define	    DBCR_RST_NONE       	0
+#define	    DBCR_RST_CORE       	1
+#define	    DBCR_RST_CHIP       	2
+#define	    DBCR_RST_SYSTEM		3
+#define	  DBCR_IC	0x08000000	/* Instruction Completion Debug Evnt */
+#define	  DBCR_BT	0x04000000	/* Branch Taken Debug Event */
+#define	  DBCR_EDE	0x02000000	/* Exception Debug Event */
+#define	  DBCR_TDE	0x01000000	/* TRAP Debug Event */
+#define	  DBCR_FER	0x00F80000	/* First Events Remaining Mask */
+#define	  DBCR_FT	0x00040000	/* Freeze Timers on Debug Event */
+#define	  DBCR_IA1	0x00020000	/* Instr. Addr. Compare 1 Enable */
+#define	  DBCR_IA2	0x00010000	/* Instr. Addr. Compare 2 Enable */
+#define	  DBCR_D1R	0x00008000	/* Data Addr. Compare 1 Read Enable */
+#define	  DBCR_D1W	0x00004000	/* Data Addr. Compare 1 Write Enable */
+#define	  DBCR_D1S(x)	(((x) & 0x3) << 12)	/* Data Adrr. Compare 1 Size */
+#define	    DAC_BYTE	0
+#define	    DAC_HALF	1
+#define	    DAC_WORD	2
+#define	    DAC_QUAD	3
+#define	  DBCR_D2R	0x00000800	/* Data Addr. Compare 2 Read Enable */
+#define	  DBCR_D2W	0x00000400	/* Data Addr. Compare 2 Write Enable */
+#define	  DBCR_D2S(x)	(((x) & 0x3) << 8)	/* Data Addr. Compare 2 Size */
+#define	  DBCR_SBT	0x00000040	/* Second Branch Taken Debug Event */
+#define	  DBCR_SED	0x00000020	/* Second Exception Debug Event */
+#define	  DBCR_STD	0x00000010	/* Second Trap Debug Event */
+#define	  DBCR_SIA	0x00000008	/* Second IAC Enable */
+#define	  DBCR_SDA	0x00000004	/* Second DAC Enable */
+#define	  DBCR_JOI	0x00000002	/* JTAG Serial Outbound Int. Enable */
+#define	  DBCR_JII	0x00000001	/* JTAG Serial Inbound Int. Enable */
+#define	SPRN_DBCR0	0x3F2	/* Debug Control Register 0 */
+#define	SPRN_DBCR1	0x3BD	/* Debug Control Register 1 */
+#define	SPRN_DBSR	0x3F0	/* Debug Status Register */
+#define	SPRN_DCCR	0x3FA	/* Data Cache Cacheability Register */
+#define	  DCCR_NOCACHE		0	/* Noncacheable */
+#define	  DCCR_CACHE		1	/* Cacheable */
+#define	SPRN_DCMP	0x3D1	/* Data TLB Compare Register */
+#define	SPRN_DCWR	0x3BA	/* Data Cache Write-thru Register */
+#define	  DCWR_COPY		0	/* Copy-back */
+#define	  DCWR_WRITE		1	/* Write-through */
+#define	SPRN_DEAR	0x3D5	/* Data Error Address Register */
+#define	SPRN_DEC	0x016	/* Decrement Register */
+#define	SPRN_DMISS	0x3D0	/* Data TLB Miss Register */
+#define	SPRN_DSISR	0x012	/* Data Storage Interrupt Status Register */
+#define	SPRN_EAR	0x11A	/* External Address Register */
+#define	SPRN_ESR	0x3D4	/* Exception Syndrome Register */
+#define	  ESR_IMCP	0x80000000	/* Instr. Machine Check - Protection */
+#define	  ESR_IMCN	0x40000000	/* Instr. Machine Check - Non-config */
+#define	  ESR_IMCB	0x20000000	/* Instr. Machine Check - Bus error */
+#define	  ESR_IMCT	0x10000000	/* Instr. Machine Check - Timeout */
+#define	  ESR_PIL	0x08000000	/* Program Exception - Illegal */
+#define	  ESR_PPR	0x04000000	/* Program Exception - Priveleged */
+#define	  ESR_PTR	0x02000000	/* Program Exception - Trap */
+#define	  ESR_DST	0x00800000	/* Storage Exception - Data miss */
+#define	  ESR_DIZ	0x00400000	/* Storage Exception - Zone fault */
+#define	SPRN_EVPR	0x3D6	/* Exception Vector Prefix Register */
+#define	SPRN_HASH1	0x3D2	/* Primary Hash Address Register */
+#define	SPRN_HASH2	0x3D3	/* Secondary Hash Address Resgister */
+#define	SPRN_HID0	0x3F0	/* Hardware Implementation Register 0 */
+#define	  HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
+#define	  HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
+#define	  HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
+#define	  HID0_SBCLK	(1<<27)
+#define	  HID0_EICE	(1<<26)
+#define	  HID0_ECLK	(1<<25)
+#define	  HID0_PAR	(1<<24)
+#define	  HID0_DOZE	(1<<23)
+#define	  HID0_NAP	(1<<22)
+#define	  HID0_SLEEP	(1<<21)
+#define	  HID0_DPM	(1<<20)
+#define	  HID0_ICE	(1<<15)		/* Instruction Cache Enable */
+#define	  HID0_DCE	(1<<14)		/* Data Cache Enable */
+#define	  HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
+#define	  HID0_DLOCK	(1<<12)		/* Data Cache Lock */
+#define	  HID0_ICFI	(1<<11)		/* Instr. Cache Flash Invalidate */
+#define	  HID0_DCI	(1<<10)		/* Data Cache Invalidate */
+#define   HID0_SPD	(1<<9)		/* Speculative disable */
+#define   HID0_SGE	(1<<7)		/* Store Gathering Enable */
+#define	  HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
+#define   HID0_BTIC	(1<<5)		/* Branch Target Instruction Cache Enable */
+#define   HID0_ABE	(1<<3)		/* Address Broadcast Enable */
+#define	  HID0_BHTE	(1<<2)		/* Branch History Table Enable */
+#define	  HID0_BTCD	(1<<1)		/* Branch target cache disable */
+#define	SPRN_MSRDORM	0x3F1	/* Hardware Implementation Register 1 */
+#define	SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
+#define	SPRN_NIADORM	0x3F3	/* Hardware Implementation Register 2 */
+#define	SPRN_TSC 	0x3FD	/* Thread switch control */
+#define	SPRN_TST 	0x3FC	/* Thread switch timeout */
+#define	SPRN_IAC1	0x3F4	/* Instruction Address Compare 1 */
+#define	SPRN_IAC2	0x3F5	/* Instruction Address Compare 2 */
+#define	SPRN_IBAT0L	0x211	/* Instruction BAT 0 Lower Register */
+#define	SPRN_IBAT0U	0x210	/* Instruction BAT 0 Upper Register */
+#define	SPRN_IBAT1L	0x213	/* Instruction BAT 1 Lower Register */
+#define	SPRN_IBAT1U	0x212	/* Instruction BAT 1 Upper Register */
+#define	SPRN_IBAT2L	0x215	/* Instruction BAT 2 Lower Register */
+#define	SPRN_IBAT2U	0x214	/* Instruction BAT 2 Upper Register */
+#define	SPRN_IBAT3L	0x217	/* Instruction BAT 3 Lower Register */
+#define	SPRN_IBAT3U	0x216	/* Instruction BAT 3 Upper Register */
+#define	SPRN_ICCR	0x3FB	/* Instruction Cache Cacheability Register */
+#define	  ICCR_NOCACHE		0	/* Noncacheable */
+#define	  ICCR_CACHE		1	/* Cacheable */
+#define	SPRN_ICDBDR	0x3D3	/* Instruction Cache Debug Data Register */
+#define	SPRN_ICMP	0x3D5	/* Instruction TLB Compare Register */
+#define	SPRN_ICTC	0x3FB	/* Instruction Cache Throttling Control Reg */
+#define	SPRN_IMISS	0x3D4	/* Instruction TLB Miss Register */
+#define	SPRN_IMMR	0x27E  	/* Internal Memory Map Register */
+#define	SPRN_L2CR	0x3F9	/* Level 2 Cache Control Regsiter */
+#define	SPRN_LR		0x008	/* Link Register */
+#define	SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
+#define	SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
+#define	SPRN_PBL1	0x3FC	/* Protection Bound Lower 1 */
+#define	SPRN_PBL2	0x3FE	/* Protection Bound Lower 2 */
+#define	SPRN_PBU1	0x3FD	/* Protection Bound Upper 1 */
+#define	SPRN_PBU2	0x3FF	/* Protection Bound Upper 2 */
+#define	SPRN_PID	0x3B1	/* Process ID */
+#define	SPRN_PIR	0x3FF	/* Processor Identification Register */
+#define	SPRN_PIT	0x3DB	/* Programmable Interval Timer */
+#define	SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
+#define	SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
+#define	SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
+#define	SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
+#define	SPRN_PVR	0x11F	/* Processor Version Register */
+#define	SPRN_RPA	0x3D6	/* Required Physical Address Register */
+#define	SPRN_SDA	0x3BF	/* Sampled Data Address Register */
+#define	SPRN_SDR1	0x019	/* MMU Hash Base Register */
+#define	SPRN_SGR	0x3B9	/* Storage Guarded Register */
+#define	  SGR_NORMAL		0
+#define	  SGR_GUARDED		1
+#define	SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
+#define	SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
+#define	SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
+#define	SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
+#define	SPRN_SPRG3	0x113	/* Special Purpose Register General 3 */
+#define	SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
+#define	SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
+#define	SPRN_SRR2	0x3DE	/* Save/Restore Register 2 */
+#define	SPRN_SRR3 	0x3DF	/* Save/Restore Register 3 */
+#define	SPRN_TBHI	0x3DC	/* Time Base High */
+#define	SPRN_TBHU	0x3CC	/* Time Base High User-mode */
+#define	SPRN_TBLO	0x3DD	/* Time Base Low */
+#define	SPRN_TBLU	0x3CD	/* Time Base Low User-mode */
+#define	SPRN_TBRL	0x10D	/* Time Base Read Lower Register */
+#define	SPRN_TBRU	0x10C	/* Time Base Read Upper Register */
+#define	SPRN_TBWL	0x11D	/* Time Base Write Lower Register */
+#define	SPRN_TBWU	0x11C	/* Time Base Write Upper Register */
+#define	SPRN_TCR	0x3DA	/* Timer Control Register */
+#define	  TCR_WP(x)		(((x)&0x3)<<30)	/* WDT Period */
+#define	    WP_2_17		0		/* 2^17 clocks */
+#define	    WP_2_21		1		/* 2^21 clocks */
+#define	    WP_2_25		2		/* 2^25 clocks */
+#define	    WP_2_29		3		/* 2^29 clocks */
+#define	  TCR_WRC(x)		(((x)&0x3)<<28)	/* WDT Reset Control */
+#define	    WRC_NONE		0		/* No reset will occur */
+#define	    WRC_CORE		1		/* Core reset will occur */
+#define	    WRC_CHIP		2		/* Chip reset will occur */
+#define	    WRC_SYSTEM		3		/* System reset will occur */
+#define	  TCR_WIE		0x08000000	/* WDT Interrupt Enable */
+#define	  TCR_PIE		0x04000000	/* PIT Interrupt Enable */
+#define	  TCR_FP(x)		(((x)&0x3)<<24)	/* FIT Period */
+#define	    FP_2_9		0		/* 2^9 clocks */
+#define	    FP_2_13		1		/* 2^13 clocks */
+#define	    FP_2_17		2		/* 2^17 clocks */
+#define	    FP_2_21		3		/* 2^21 clocks */
+#define	  TCR_FIE		0x00800000	/* FIT Interrupt Enable */
+#define	  TCR_ARE		0x00400000	/* Auto Reload Enable */
+#define	SPRN_THRM1	0x3FC	/* Thermal Management Register 1 */
+#define	  THRM1_TIN		(1<<0)
+#define	  THRM1_TIV		(1<<1)
+#define	  THRM1_THRES		(0x7f<<2)
+#define	  THRM1_TID		(1<<29)
+#define	  THRM1_TIE		(1<<30)
+#define	  THRM1_V		(1<<31)
+#define	SPRN_THRM2	0x3FD	/* Thermal Management Register 2 */
+#define	SPRN_THRM3	0x3FE	/* Thermal Management Register 3 */
+#define	  THRM3_E		(1<<31)
+#define	SPRN_TSR	0x3D8	/* Timer Status Register */
+#define	  TSR_ENW		0x80000000	/* Enable Next Watchdog */
+#define	  TSR_WIS		0x40000000	/* WDT Interrupt Status */
+#define	  TSR_WRS(x)		(((x)&0x3)<<28)	/* WDT Reset Status */
+#define	    WRS_NONE		0		/* No WDT reset occurred */
+#define	    WRS_CORE		1		/* WDT forced core reset */
+#define	    WRS_CHIP		2		/* WDT forced chip reset */
+#define	    WRS_SYSTEM		3		/* WDT forced system reset */
+#define	  TSR_PIS		0x08000000	/* PIT Interrupt Status */
+#define	  TSR_FIS		0x04000000	/* FIT Interrupt Status */
+#define	SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
+#define	SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
+#define	SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 */
+#define	SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 */
+#define	SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 */
+#define	SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 */
+#define	SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
+#define	SPRN_XER	0x001	/* Fixed Point Exception Register */
+#define	SPRN_ZPR	0x3B0	/* Zone Protection Register */
+
+/* Short-hand versions for a number of the above SPRNs */
+
+#define	CTR	SPRN_CTR	/* Counter Register */
+#define	DAR	SPRN_DAR	/* Data Address Register */
+#define	DABR	SPRN_DABR	/* Data Address Breakpoint Register */
+#define	DBAT0L	SPRN_DBAT0L	/* Data BAT 0 Lower Register */
+#define	DBAT0U	SPRN_DBAT0U	/* Data BAT 0 Upper Register */
+#define	DBAT1L	SPRN_DBAT1L	/* Data BAT 1 Lower Register */
+#define	DBAT1U	SPRN_DBAT1U	/* Data BAT 1 Upper Register */
+#define	DBAT2L	SPRN_DBAT2L	/* Data BAT 2 Lower Register */
+#define	DBAT2U	SPRN_DBAT2U	/* Data BAT 2 Upper Register */
+#define	DBAT3L	SPRN_DBAT3L	/* Data BAT 3 Lower Register */
+#define	DBAT3U	SPRN_DBAT3U	/* Data BAT 3 Upper Register */
+#define	DCMP	SPRN_DCMP      	/* Data TLB Compare Register */
+#define	DEC	SPRN_DEC       	/* Decrement Register */
+#define	DMISS	SPRN_DMISS     	/* Data TLB Miss Register */
+#define	DSISR	SPRN_DSISR	/* Data Storage Interrupt Status Register */
+#define	EAR	SPRN_EAR       	/* External Address Register */
+#define	HASH1	SPRN_HASH1	/* Primary Hash Address Register */
+#define	HASH2	SPRN_HASH2	/* Secondary Hash Address Register */
+#define	HID0	SPRN_HID0	/* Hardware Implementation Register 0 */
+#define	MSRDORM	SPRN_MSRDORM	/* MSR Dormant Register */
+#define	NIADORM	SPRN_NIADORM	/* NIA Dormant Register */
+#define	TSC    	SPRN_TSC 	/* Thread switch control */
+#define	TST    	SPRN_TST 	/* Thread switch timeout */
+#define	IABR	SPRN_IABR      	/* Instruction Address Breakpoint Register */
+#define	IBAT0L	SPRN_IBAT0L	/* Instruction BAT 0 Lower Register */
+#define	IBAT0U	SPRN_IBAT0U	/* Instruction BAT 0 Upper Register */
+#define	IBAT1L	SPRN_IBAT1L	/* Instruction BAT 1 Lower Register */
+#define	IBAT1U	SPRN_IBAT1U	/* Instruction BAT 1 Upper Register */
+#define	IBAT2L	SPRN_IBAT2L	/* Instruction BAT 2 Lower Register */
+#define	IBAT2U	SPRN_IBAT2U	/* Instruction BAT 2 Upper Register */
+#define	IBAT3L	SPRN_IBAT3L	/* Instruction BAT 3 Lower Register */
+#define	IBAT3U	SPRN_IBAT3U	/* Instruction BAT 3 Upper Register */
+#define	ICMP	SPRN_ICMP	/* Instruction TLB Compare Register */
+#define	IMISS	SPRN_IMISS	/* Instruction TLB Miss Register */
+#define	IMMR	SPRN_IMMR      	/* PPC 860/821 Internal Memory Map Register */
+#define	L2CR	SPRN_L2CR    	/* PPC 750 L2 control register */
+#define	LR	SPRN_LR
+#define	PVR	SPRN_PVR	/* Processor Version */
+#define	PIR	SPRN_PIR	/* Processor ID */
+#define	RPA	SPRN_RPA	/* Required Physical Address Register */
+#define	SDR1	SPRN_SDR1      	/* MMU hash base register */
+#define	SPR0	SPRN_SPRG0	/* Supervisor Private Registers */
+#define	SPR1	SPRN_SPRG1
+#define	SPR2	SPRN_SPRG2
+#define	SPR3	SPRN_SPRG3
+#define	SPRG0   SPRN_SPRG0
+#define	SPRG1   SPRN_SPRG1
+#define	SPRG2   SPRN_SPRG2
+#define	SPRG3   SPRN_SPRG3
+#define	SRR0	SPRN_SRR0	/* Save and Restore Register 0 */
+#define	SRR1	SPRN_SRR1	/* Save and Restore Register 1 */
+#define	TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
+#define	TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
+#define	TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
+#define	TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
+#define ICTC	1019
+#define	THRM1	SPRN_THRM1	/* Thermal Management Register 1 */
+#define	THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
+#define	THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
+#define	XER	SPRN_XER
+
+
+/* Device Control Registers */
+
+#define	DCRN_BEAR	0x090	/* Bus Error Address Register */
+#define	DCRN_BESR	0x091	/* Bus Error Syndrome Register */
+#define	  BESR_DSES    	0x80000000	/* Data-Side Error Status */
+#define	  BESR_DMES	0x40000000	/* DMA Error Status */
+#define	  BESR_RWS	0x20000000	/* Read/Write Status */
+#define	  BESR_ETMASK	0x1C000000	/* Error Type */
+#define	    ET_PROT	0
+#define	    ET_PARITY	1
+#define	    ET_NCFG	2
+#define	    ET_BUSERR	4
+#define	    ET_BUSTO	6
+#define	DCRN_DMACC0	0x0C4	/* DMA Chained Count Register 0 */
+#define	DCRN_DMACC1	0x0CC	/* DMA Chained Count Register 1 */
+#define	DCRN_DMACC2	0x0D4	/* DMA Chained Count Register 2 */
+#define	DCRN_DMACC3	0x0DC    /* DMA Chained Count Register 3 */
+#define	DCRN_DMACR0	0x0C0    /* DMA Channel Control Register 0 */
+#define	DCRN_DMACR1	0x0C8    /* DMA Channel Control Register 1 */
+#define	DCRN_DMACR2	0x0D0    /* DMA Channel Control Register 2 */
+#define	DCRN_DMACR3	0x0D8    /* DMA Channel Control Register 3 */
+#define	DCRN_DMACT0	0x0C1    /* DMA Count Register 0 */
+#define	DCRN_DMACT1	0x0C9    /* DMA Count Register 1 */
+#define	DCRN_DMACT2	0x0D1    /* DMA Count Register 2 */
+#define	DCRN_DMACT3	0x0D9    /* DMA Count Register 3 */
+#define	DCRN_DMADA0	0x0C2    /* DMA Destination Address Register 0 */
+#define	DCRN_DMADA1	0x0CA    /* DMA Destination Address Register 1 */
+#define	DCRN_DMADA2	0x0D2    /* DMA Destination Address Register 2 */
+#define	DCRN_DMADA3	0x0DA    /* DMA Destination Address Register 3 */
+#define	DCRN_DMASA0	0x0C3    /* DMA Source Address Register 0 */
+#define	DCRN_DMASA1	0x0CB    /* DMA Source Address Register 1 */
+#define	DCRN_DMASA2	0x0D3    /* DMA Source Address Register 2 */
+#define	DCRN_DMASA3	0x0DB    /* DMA Source Address Register 3 */
+#define	DCRN_DMASR	0x0E0    /* DMA Status Register */
+#define	DCRN_EXIER	0x042    /* External Interrupt Enable Register */
+#define	  EXIER_CIE	0x80000000	/* Critical Interrupt Enable */
+#define	  EXIER_SRIE	0x08000000	/* Serial Port Rx Int. Enable */
+#define	  EXIER_STIE	0x04000000	/* Serial Port Tx Int. Enable */
+#define	  EXIER_JRIE	0x02000000	/* JTAG Serial Port Rx Int. Enable */
+#define	  EXIER_JTIE	0x01000000	/* JTAG Serial Port Tx Int. Enable */
+#define	  EXIER_D0IE	0x00800000	/* DMA Channel 0 Interrupt Enable */
+#define	  EXIER_D1IE	0x00400000	/* DMA Channel 1 Interrupt Enable */
+#define	  EXIER_D2IE	0x00200000	/* DMA Channel 2 Interrupt Enable */
+#define	  EXIER_D3IE	0x00100000	/* DMA Channel 3 Interrupt Enable */
+#define	  EXIER_E0IE	0x00000010	/* External Interrupt 0 Enable */
+#define	  EXIER_E1IE	0x00000008	/* External Interrupt 1 Enable */
+#define	  EXIER_E2IE	0x00000004	/* External Interrupt 2 Enable */
+#define	  EXIER_E3IE	0x00000002	/* External Interrupt 3 Enable */
+#define	  EXIER_E4IE	0x00000001	/* External Interrupt 4 Enable */
+#define	DCRN_EXISR	0x040    /* External Interrupt Status Register */
+#define	DCRN_IOCR	0x0A0    /* Input/Output Configuration Register */
+#define	  IOCR_E0TE	0x80000000
+#define	  IOCR_E0LP	0x40000000
+#define	  IOCR_E1TE	0x20000000
+#define	  IOCR_E1LP	0x10000000
+#define	  IOCR_E2TE	0x08000000
+#define	  IOCR_E2LP	0x04000000
+#define	  IOCR_E3TE	0x02000000
+#define	  IOCR_E3LP	0x01000000
+#define	  IOCR_E4TE	0x00800000
+#define	  IOCR_E4LP	0x00400000
+#define	  IOCR_EDT     	0x00080000
+#define	  IOCR_SOR     	0x00040000
+#define	  IOCR_EDO	0x00008000
+#define	  IOCR_2XC	0x00004000
+#define	  IOCR_ATC	0x00002000
+#define	  IOCR_SPD	0x00001000
+#define	  IOCR_BEM	0x00000800
+#define	  IOCR_PTD	0x00000400
+#define	  IOCR_ARE	0x00000080
+#define	  IOCR_DRC	0x00000020
+#define	  IOCR_RDM(x)	(((x) & 0x3) << 3)
+#define	  IOCR_TCS	0x00000004
+#define	  IOCR_SCS	0x00000002
+#define	  IOCR_SPC	0x00000001
+
+
+/* Processor Version Register */
+
+/* Processor Version Register (PVR) field extraction */
+
+#define	PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF)	/* Version field */
+#define	PVR_REV(pvr)  (((pvr) >>   0) & 0xFFFF)	/* Revison field */
+
+/* Processor Version Numbers */
+#define	PV_PULSAR	0x0034
+#define	PV_POWER4	0x0035
+#define	PV_ICESTAR	0x0036
+#define	PV_SSTAR	0x0037
+#define	PV_630        	0x0040
+#define	PV_630p	        0x0041
+
+/* Platforms supported by PPC64.  _machine is actually a set of flags */
+#define _MACH_pSeriesHW 0x00010000
+#define _MACH_iSeriesHW 0x00020000
+#define _MACH_LPAR	0x00000001
+
+#define _MACH_unknown	0x00000000
+#define _MACH_pSeries	(_MACH_pSeriesHW)
+#define _MACH_pSeriesLP	(_MACH_pSeriesHW | _MACH_LPAR)
+#define _MACH_iSeries	(_MACH_iSeriesHW | _MACH_LPAR)
+
+/* Compat defines for drivers */
+#define _MACH_Pmac	0xf0000000	/* bogus value */
+	
+/*
+ * List of interrupt controllers.
+ */
+#define IC_INVALID    0
+#define IC_OPEN_PIC   1
+#define IC_PPC_XIC    2
+
+#define stringify(s)	tostring(s)
+#define tostring(s)	#s
+#define XGLUE(a,b) a##b
+#define GLUE(a,b) XGLUE(a,b)
+
+/*
+ * Begining of traceback info work for asm functions.
+ */
+#define TB_ASM		0x000C000000000000
+#define TB_GLOBALLINK	0x0000800000000000
+#define TB_IS_EPROL	0x0000400000000000
+#define TB_HAS_TBOFF	0x0000200000000000
+#define TB_INT_PROC	0x0000100000000000
+#define TB_HAS_CTL	0x0000080000000000
+#define TB_TOCLESS	0x0000040000000000
+#define TB_FP_PRESENT	0x0000020000000000
+#define TB_LOG_ABORT	0x0000010000000000
+#define TB_INT_HNDL	0x0000008000000000
+#define TB_NAME_PRESENT	0x0000004000000000
+#define TB_SAVES_CR	0x0000000200000000
+#define TB_SAVES_LR	0x0000000100000000
+#define TB_STORES_BC	0x0000000080000000
+#define TB_PARMINFO	0x000000000000FFFF
+#define TB_DEFAULT	TB_ASM | TB_HAS_TBOFF | TB_NAME_PRESENT
+
+#ifdef __ASSEMBLY__
+
+#define _GLOBAL(name) \
+	.section ".text"; \
+	.align 2 ; \
+	.globl name; \
+	.globl GLUE(.,name); \
+	.section ".opd","aw"; \
+name: \
+	.quad GLUE(.,name); \
+	.quad .TOC.@tocbase; \
+	.quad 0; \
+	.previous; \
+	.type GLUE(.,name),@function; \
+GLUE(.,name):
+
+#define _STATIC(name) \
+	.section ".text"; \
+	.align 2 ; \
+	.section ".opd","aw"; \
+name: \
+	.quad GLUE(.,name); \
+	.quad .TOC.@tocbase; \
+	.quad 0; \
+	.previous; \
+	.type GLUE(.,name),@function; \
+GLUE(.,name):
+
+#define _TRACEBACK(NAME) \
+GLUE(.LT,NAME): ;\
+	.long 0 ;\
+	.llong TB_DEFAULT ;\
+	.long GLUE(.LT,NAME)-GLUE(.,NAME) ;\
+	.short GLUE(GLUE(.LT,NAME),_procname_end)-GLUE(GLUE(.LT,NAME),_procname_start) ;\
+GLUE(GLUE(.LT,NAME),_procname_start): ;\
+	.ascii stringify(NAME) ;\
+GLUE(GLUE(.LT,NAME),_procname_end):
+
+#endif /* __ASSEMBLY__ */
+
+
+/* Macros for setting and retrieving special purpose registers */
+
+#define mfmsr()		({unsigned long rval; \
+			asm volatile("mfmsr %0" : "=r" (rval)); rval;})
+
+#define mtmsrd(v)	asm volatile("mtmsrd %0" : : "r" (v))
+
+#define mfspr(rn)	({unsigned long rval; \
+			asm volatile("mfspr %0," stringify(rn) \
+				     : "=r" (rval)); rval;})
+#define mtspr(rn, v)	asm volatile("mtspr " stringify(rn) ",%0" : : "r" (v))
+
+#define mftb()		({unsigned long rval;	\
+			asm volatile("mftb %0" : "=r" (rval)); rval;})
+
+/* iSeries CTRL register (for runlatch) */
+
+#define CTRLT		0x098
+#define CTRLF		0x088
+#define RUNLATCH	0x0001
+#define RUN_FLAG	0x0002
+
+/* Macros for adjusting thread priority (hardware multi-threading) */
+#define HMT_low()	asm volatile("or 1,1,1")
+#define HMT_medium()	asm volatile("or 2,2,2")
+#define HMT_high()	asm volatile("or 3,3,3")
+
+/* Size of an exception stack frame contained in the paca. */
+#define EXC_FRAME_SIZE 64
+
+#define mfasr()		({unsigned long rval; \
+			asm volatile("mfasr %0" : "=r" (rval)); rval;})
+
+#ifndef __ASSEMBLY__
+extern int _machine;
+extern int have_of;
+
+struct task_struct;
+void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
+void release_thread(struct task_struct *);
+
+/*
+ * Create a new kernel thread.
+ */
+extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+/*
+ * 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 */
+
+/* Lazy FPU handling on uni-processor */
+extern struct task_struct *last_task_used_math;
+
+
+#ifdef __KERNEL__
+/* 64-bit user address space is 41-bits (2TBs user VM) */
+#define TASK_SIZE_USER64 (0x0000020000000000UL)
+
+/* 
+ * 32-bit user address space is 4GB - 1 page 
+ * (this 1 page is needed so referencing of 0xFFFFFFFF generates EFAULT
+ */
+#define TASK_SIZE_USER32 (0x0000000100000000UL - (1*PAGE_SIZE))
+
+#define TASK_SIZE ((current->thread.flags & PPC_FLAG_32BIT) ? \
+		TASK_SIZE_USER32 : TASK_SIZE_USER64)
+#endif /* __KERNEL__ */
+
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE_USER32 (STACK_TOP_USER32 / 4)
+#define TASK_UNMAPPED_BASE_USER64 (STACK_TOP_USER64 / 4)
+
+#define TASK_UNMAPPED_BASE (((current->thread.flags & PPC_FLAG_32BIT)||(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \
+		TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 )
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+struct thread_struct {
+	unsigned long	ksp;		/* Kernel stack pointer */
+	struct pt_regs	*regs;		/* Pointer to saved register state */
+	mm_segment_t	fs;		/* for get_fs() validation */
+	void		*pgdir;		/* root of page-table tree */
+	signed long     last_syscall;
+	unsigned long	flags;
+	double		fpr[32];	/* Complete floating point set */
+	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
+	unsigned long	fpscr;		/* Floating point status */
+};
+
+#define PPC_FLAG_32BIT		0x01
+#define PPC_FLAG_RUN_LIGHT	RUN_FLAG
+
+#define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
+
+#define INIT_THREAD  { \
+	INIT_SP, /* ksp */ \
+	(struct pt_regs *)INIT_SP - 1, /* regs */ \
+	KERNEL_DS, /*fs*/ \
+	swapper_pg_dir, /* pgdir */ \
+	0, /* last_syscall */ \
+	PPC_FLAG_RUN_LIGHT, /* flags */ \
+	{0}, 0, 0 \
+}
+
+/*
+ * Note: the vm_start and vm_end fields here should *not*
+ * be in kernel space.  (Could vm_end == vm_start perhaps?)
+ */
+#define IOREMAP_MMAP { &ioremap_mm, 0, 0x1000, NULL, \
+		    PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, \
+		    1, NULL, NULL }
+
+extern struct mm_struct ioremap_mm;
+
+/*
+ * Return saved PC of a blocked thread. For now, this is the "user" PC
+ */
+static inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+	return (t->regs) ? t->regs->nip : 0;
+}
+
+#define copy_segments(tsk, mm)		do { } while (0)
+#define release_segments(mm)		do { } while (0)
+#define forget_segments()		do { } while (0)
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
+#define KSTK_ESP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
+
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define THREAD_SIZE (4*PAGE_SIZE)
+struct task_struct * alloc_task_struct(void);
+        
+void free_task_struct(struct task_struct *);
+#define get_task_struct(tsk)	atomic_inc(&virt_to_page(tsk)->count)
+
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
+
+#define cpu_relax()     do { } while (0)
+
+/*
+ * Prefetch macros.
+ */
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+#define ARCH_HAS_SPINLOCK_PREFETCH
+
+extern inline void prefetch(const void *x)
+{
+	__asm__ __volatile__ ("dcbt 0,%0" : : "r" (x));
+}
+
+extern inline void prefetchw(const void *x)
+{
+	__asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
+}
+
+#define spin_lock_prefetch(x)	prefetchw(x)
+
+#endif /* ASSEMBLY */
+
+#endif /* __ASM_PPC64_PROCESSOR_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/prom.h linux-2.4.19-pre5/include/asm-ppc64/prom.h
--- linux-2.4.19-pre4/include/asm-ppc64/prom.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/prom.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,202 @@
+#ifndef _PPC64_PROM_H
+#define _PPC64_PROM_H
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define PTRRELOC(x)     ((typeof(x))((unsigned long)(x) - offset))
+#define PTRUNRELOC(x)   ((typeof(x))((unsigned long)(x) + offset))
+#define RELOC(x)        (*PTRRELOC(&(x)))
+
+#define LONG_LSW(X) (((unsigned long)X) & 0xffffffff)
+#define LONG_MSW(X) (((unsigned long)X) >> 32)
+
+typedef u32 phandle;
+typedef void *ihandle;
+typedef u32 phandle32;
+typedef u32 ihandle32;
+
+extern char *prom_display_paths[];
+extern unsigned int prom_num_displays;
+
+struct address_range {
+	unsigned long space;
+	unsigned long address;
+	unsigned long size;
+};
+
+struct interrupt_info {
+	int	line;
+	int	sense;		/* +ve/-ve logic, edge or level, etc. */
+};
+
+struct pci_address {
+	u32 a_hi;
+	u32 a_mid;
+	u32 a_lo;
+};
+
+struct pci_range32 {
+	struct pci_address child_addr;
+	unsigned int  parent_addr;
+  	unsigned long size; 
+};
+
+struct pci_range64 {
+	struct pci_address child_addr;
+  	unsigned long parent_addr;
+        unsigned long size; 
+};
+
+union pci_range {
+	struct {
+		struct pci_address addr;
+		u32 phys;
+		u32 size_hi;
+	} pci32;
+	struct {
+		struct pci_address addr;
+		u32 phys_hi;
+		u32 phys_lo;
+		u32 size_hi;
+		u32 size_lo;
+	} pci64;
+};
+
+struct _of_tce_table {
+	phandle node;
+	unsigned long base;
+	unsigned long size;
+};
+
+struct reg_property {
+	unsigned long address;
+	unsigned long size;
+};
+
+struct reg_property32 {
+	unsigned int address;
+	unsigned int size;
+};
+
+struct reg_property64 {
+	unsigned long address;
+	unsigned long size;
+};
+
+struct translation_property {
+	unsigned long virt;
+	unsigned long size;
+	unsigned long phys;
+	unsigned int flags;
+};
+
+struct property {
+	char	*name;
+	int	length;
+	unsigned char *value;
+	struct property *next;
+};
+
+/* NOTE: the device_node contains PCI specific info for pci devices.
+ * This perhaps could be hung off the device_node with another struct,
+ * but for now it is directly in the node.  The phb ptr is a good
+ * indication of a real PCI node.  Other nodes leave these fields zeroed.
+ */
+struct pci_controller;
+struct TceTable;
+struct device_node {
+	char	*name;
+	char	*type;
+	phandle	node;
+	int	n_addrs;
+	struct	address_range *addrs;
+	int	n_intrs;
+	struct	interrupt_info *intrs;
+	char	*full_name;
+	int	busno;			/* for pci devices */
+	int	devfn;			/* for pci devices */
+	struct  pci_controller *phb;	/* for pci devices */
+	int	status;			/* current status of device */
+	struct	TceTable *tce_table;	/* for phb's or bridges */
+#define DN_STATUS_BIST_FAILED (1<<0)
+	struct	property *properties;
+	struct	device_node *parent;
+	struct	device_node *child;
+	struct	device_node *sibling;
+	struct	device_node *next;	/* next device of same type */
+	struct	device_node *allnext;	/* next in list of all nodes */
+};
+
+typedef u32 prom_arg_t;
+
+struct prom_args {
+        u32 service;
+        u32 nargs;
+        u32 nret;
+        prom_arg_t args[10];
+        prom_arg_t *rets;     /* Pointer to return values in args[16]. */
+};
+
+typedef struct {
+	u32  printf;	/* void (*printf)(char *, ...); */
+	u32  memdump;	/* void (*memdump)(unsigned char *, unsigned long); */
+	u32  dummy;		/* void (*dummy)(void); */
+} yaboot_debug_t;
+
+struct prom_t {
+	unsigned long entry;
+	ihandle chosen;
+	int cpu;
+	ihandle stdout;
+	ihandle disp_node;
+	struct prom_args args;
+	unsigned long version;
+	unsigned long encode_phys_size;
+	struct bi_record *bi_recs;
+#ifdef DEBUG_YABOOT
+	yaboot_debug_t *yaboot;
+#endif
+};
+
+extern struct prom_t prom;
+
+/* Prototypes */
+extern void abort(void);
+extern unsigned long prom_init(unsigned long, unsigned long, unsigned long,
+    unsigned long, unsigned long, yaboot_debug_t *);
+extern void prom_print(const char *msg);
+extern void relocate_nodes(void);
+extern void finish_device_tree(void);
+extern struct device_node *find_devices(const char *name);
+extern struct device_node *find_type_devices(const char *type);
+extern struct device_node *find_path_device(const char *path);
+extern struct device_node *find_compatible_devices(const char *type,
+						   const char *compat);
+extern struct device_node *find_pci_device_OFnode(unsigned char bus,
+	unsigned char dev_fn);
+extern struct device_node *find_all_nodes(void);
+extern int device_is_compatible(struct device_node *device, const char *);
+extern int machine_is_compatible(const char *compat);
+extern unsigned char *get_property(struct device_node *node, const char *name,
+				   int *lenp);
+extern void print_properties(struct device_node *node);
+extern int prom_n_addr_cells(struct device_node* np);
+extern int prom_n_size_cells(struct device_node* np);
+extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
+extern void prom_drawstring(const char *c);
+extern void prom_drawhex(unsigned long v);
+extern void prom_drawchar(char c);
+
+#endif /* _PPC64_PROM_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ptrace.h linux-2.4.19-pre5/include/asm-ppc64/ptrace.h
--- linux-2.4.19-pre4/include/asm-ppc64/ptrace.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ptrace.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,146 @@
+#ifndef _PPC64_PTRACE_H
+#define _PPC64_PTRACE_H
+
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ *
+ * this should only contain volatile regs
+ * since we can keep non-volatile in the thread_struct
+ * should set this up when only volatiles are saved
+ * by intr code.
+ *
+ * Since this is going on the stack, *CARE MUST BE TAKEN* to insure
+ * that the overall structure is a multiple of 16 bytes in length.
+ *
+ * Note that the offsets of the fields in this struct correspond with
+ * the PT_* values below.  This simplifies arch/ppc/kernel/ptrace.c.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define INIT_TASK_SIZE			4*PAGE_SIZE
+
+#ifndef __ASSEMBLY__
+#define PPC_REG unsigned long
+struct pt_regs {
+	PPC_REG gpr[32];
+	PPC_REG nip;
+	PPC_REG msr;
+	PPC_REG orig_gpr3;	/* Used for restarting system calls */
+	PPC_REG ctr;
+	PPC_REG link;
+	PPC_REG xer;
+	PPC_REG ccr;
+	PPC_REG softe;		/* Soft enabled/disabled */
+	PPC_REG trap;		/* Reason for being here */
+	PPC_REG dar;		/* Fault registers */
+	PPC_REG dsisr;
+	PPC_REG result; 	/* Result of a system call */
+};
+
+#define PPC_REG_32 unsigned int
+struct pt_regs32 {
+	PPC_REG_32 gpr[32];
+	PPC_REG_32 nip;
+	PPC_REG_32 msr;
+	PPC_REG_32 orig_gpr3;	/* Used for restarting system calls */
+	PPC_REG_32 ctr;
+	PPC_REG_32 link;
+	PPC_REG_32 xer;
+	PPC_REG_32 ccr;
+	PPC_REG_32 mq;		/* 601 only (not used at present) */
+				/* Used on APUS to hold IPL value. */
+	PPC_REG_32 trap;		/* Reason for being here */
+	PPC_REG_32 dar;		/* Fault registers */
+	PPC_REG_32 dsisr;
+	PPC_REG_32 result; 	/* Result of a system call */
+};
+
+#endif
+
+#define STACK_FRAME_OVERHEAD	112	/* size of minimum stack frame */
+
+/* Size of stack frame allocated when calling signal handler. */
+/* FIXME: What should this be on 64-bit kernel (64 for 32-bit) */
+#define __SIGNAL_FRAMESIZE	64
+#define __SIGNAL_FRAMESIZE32	64
+
+#define instruction_pointer(regs) ((regs)->nip)
+#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
+
+/*
+ * Offsets used by 'ptrace' system call interface.
+ */
+#define PT_R0	0
+#define PT_R1	1
+#define PT_R2	2
+#define PT_R3	3
+#define PT_R4	4
+#define PT_R5	5
+#define PT_R6	6
+#define PT_R7	7
+#define PT_R8	8
+#define PT_R9	9
+#define PT_R10	10
+#define PT_R11	11
+#define PT_R12	12
+#define PT_R13	13
+#define PT_R14	14
+#define PT_R15	15
+#define PT_R16	16
+#define PT_R17	17
+#define PT_R18	18
+#define PT_R19	19
+#define PT_R20	20
+#define PT_R21	21
+#define PT_R22	22
+#define PT_R23	23
+#define PT_R24	24
+#define PT_R25	25
+#define PT_R26	26
+#define PT_R27	27
+#define PT_R28	28
+#define PT_R29	29
+#define PT_R30	30
+#define PT_R31	31
+
+#define PT_NIP	32
+#define PT_MSR	33
+#ifdef __KERNEL__
+#define PT_ORIG_R3 34
+#endif
+#define PT_CTR	35
+#define PT_LNK	36
+#define PT_XER	37
+#define PT_CCR	38
+#define PT_SOFTE 39
+#define PT_RESULT 43
+
+#define PT_FPR0	48
+#ifdef __KERNEL__
+#define PT_FPSCR (PT_FPR0 + 32 + 1)	  /* each FP reg occupies 1 slot in this space */
+#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1)	  /* To the 32-bit user - each FP reg occupies 2 slots in this space */
+#else
+#define PT_FPSCR (PT_FPR0 + 2*32 + 1)	/* each FP reg occupies 2 slots in this space -- Fix when 64-bit apps. */
+#endif
+
+/* Additional PTRACE requests implemented on PowerPC. */
+#define PPC_PTRACE_GETREGS	      0x99  /* Get GPRs 0 - 31 */
+#define PPC_PTRACE_SETREGS	      0x98  /* Set GPRs 0 - 31 */
+#define PPC_PTRACE_GETFPREGS	    0x97  /* Get FPRs 0 - 31 */
+#define PPC_PTRACE_SETFPREGS	    0x96  /* Set FPRs 0 - 31 */
+#define PPC_PTRACE_PEEKTEXT_3264  0x95  /* Read word at location ADDR on a 64-bit process from a 32-bit process. */
+#define PPC_PTRACE_PEEKDATA_3264  0x94  /* Read word at location ADDR on a 64-bit process from a 32-bit process. */
+#define PPC_PTRACE_POKETEXT_3264  0x93  /* Write word at location ADDR on a 64-bit process from a 32-bit process. */
+#define PPC_PTRACE_POKEDATA_3264  0x92  /* Write word at location ADDR on a 64-bit process from a 32-bit process. */
+#define PPC_PTRACE_PEEKUSR_3264   0x91  /* Read a register (specified by ADDR) out of the "user area" on a 64-bit process from a 32-bit process. */
+#define PPC_PTRACE_POKEUSR_3264   0x90  /* Write DATA into location ADDR within the "user area" on a 64-bit process from a 32-bit process. */
+
+
+#endif /* _PPC64_PTRACE_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/resource.h linux-2.4.19-pre5/include/asm-ppc64/resource.h
--- linux-2.4.19-pre4/include/asm-ppc64/resource.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/resource.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,53 @@
+#ifndef _PPC64_RESOURCE_H
+#define _PPC64_RESOURCE_H
+
+/*
+ * Copyright (C) 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define RLIMIT_CPU	0		/* CPU time in ms */
+#define RLIMIT_FSIZE	1		/* Maximum filesize */
+#define RLIMIT_DATA	2		/* max data size */
+#define RLIMIT_STACK	3		/* max stack size */
+#define RLIMIT_CORE	4		/* max core file size */
+#define RLIMIT_RSS	5		/* max resident set size */
+#define RLIMIT_NPROC	6		/* max number of processes */
+#define RLIMIT_NOFILE	7		/* max number of open files */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit(?) */
+#define RLIMIT_LOCKS	10		/* maximum file locks held */
+
+#define RLIM_NLIMITS	11
+
+#ifdef __KERNEL__
+
+/*
+ * SuS says limits have to be unsigned.
+ * Which makes a ton more sense anyway.
+ */
+#define RLIM_INFINITY	(~0UL)
+
+
+#define INIT_RLIMITS							\
+{									\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{      _STK_LIM, RLIM_INFINITY },		\
+	{             0, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{             0,             0 },		\
+	{      INR_OPEN,     INR_OPEN  },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _PPC64_RESOURCE_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/rtas.h linux-2.4.19-pre5/include/asm-ppc64/rtas.h
--- linux-2.4.19-pre4/include/asm-ppc64/rtas.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/rtas.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,141 @@
+#ifndef _PPC64_RTAS_H
+#define _PPC64_RTAS_H
+
+#include <linux/spinlock.h>
+
+/*
+ * Definitions for talking to the RTAS on CHRP machines.
+ *
+ * Copyright (C) 2001 Peter Bergner
+ * Copyright (C) 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define RTAS_UNKNOWN_SERVICE (-1)
+/*
+ * In general to call RTAS use rtas_token("string") to lookup
+ * an RTAS token for the given string (e.g. "event-scan").
+ * To actually perform the call use
+ *    ret = rtas_call(token, n_in, n_out, ...)
+ * Where n_in is the number of input parameters and
+ *       n_out is the number of output parameters
+ *
+ * If the "string" is invalid on this system, RTAS_UNKOWN_SERVICE
+ * will be returned as a token.  rtas_call() does look for this
+ * token and error out gracefully so rtas_call(rtas_token("str"), ...)
+ * may be safely used for one-shot calls to RTAS.
+ *
+ */
+
+typedef u32 rtas_arg_t;
+
+struct rtas_args {
+	u32 token;
+	u32 nargs;
+	u32 nret; 
+	rtas_arg_t args[16];
+	spinlock_t lock;
+	rtas_arg_t *rets;     /* Pointer to return values in args[]. */
+};  
+
+struct rtas_t {
+	unsigned long entry;		/* physical address pointer */
+	unsigned long base;		/* physical address pointer */
+	unsigned long size;
+	spinlock_t lock;
+
+	struct device_node *dev;	/* virtual address pointer */
+};
+
+/* Event classes */
+#define INTERNAL_ERROR		0x80000000 /* set bit 0 */
+#define EPOW_WARNING		0x40000000 /* set bit 1 */
+#define POWERMGM_EVENTS		0x20000000 /* set bit 2 */
+#define HOTPLUG_EVENTS		0x10000000 /* set bit 3 */
+#define EVENT_SCAN_ALL_EVENTS	0xf0000000
+
+/* event-scan returns */
+#define SEVERITY_FATAL		0x5
+#define SEVERITY_ERROR		0x4
+#define SEVERITY_ERROR_SYNC	0x3
+#define SEVERITY_WARNING	0x2
+#define SEVERITY_EVENT		0x1
+#define SEVERITY_NO_ERROR	0x0
+#define DISP_FULLY_RECOVERED	0x0
+#define DISP_LIMITED_RECOVERY	0x1
+#define DISP_NOT_RECOVERED	0x2
+#define PART_PRESENT		0x0
+#define PART_NOT_PRESENT	0x1
+#define INITIATOR_UNKNOWN	0x0
+#define INITIATOR_CPU		0x1
+#define INITIATOR_PCI		0x2
+#define INITIATOR_ISA		0x3
+#define INITIATOR_MEMORY	0x4
+#define INITIATOR_POWERMGM	0x5
+#define TARGET_UNKNOWN		0x0
+#define TARGET_CPU		0x1
+#define TARGET_PCI		0x2
+#define TARGET_ISA		0x3
+#define TARGET_MEMORY		0x4
+#define TARGET_POWERMGM		0x5
+#define TYPE_RETRY		0x01
+#define TYPE_TCE_ERR		0x02
+#define TYPE_INTERN_DEV_FAIL	0x03
+#define TYPE_TIMEOUT		0x04
+#define TYPE_DATA_PARITY	0x05
+#define TYPE_ADDR_PARITY	0x06
+#define TYPE_CACHE_PARITY	0x07
+#define TYPE_ADDR_INVALID	0x08
+#define TYPE_ECC_UNCORR		0x09
+#define TYPE_ECC_CORR		0x0a
+#define TYPE_EPOW		0x40
+/* I don't add PowerMGM events right now, this is a different topic */ 
+#define TYPE_PMGM_POWER_SW_ON	0x60
+#define TYPE_PMGM_POWER_SW_OFF	0x61
+#define TYPE_PMGM_LID_OPEN	0x62
+#define TYPE_PMGM_LID_CLOSE	0x63
+#define TYPE_PMGM_SLEEP_BTN	0x64
+#define TYPE_PMGM_WAKE_BTN	0x65
+#define TYPE_PMGM_BATTERY_WARN	0x66
+#define TYPE_PMGM_BATTERY_CRIT	0x67
+#define TYPE_PMGM_SWITCH_TO_BAT	0x68
+#define TYPE_PMGM_SWITCH_TO_AC	0x69
+#define TYPE_PMGM_KBD_OR_MOUSE	0x6a
+#define TYPE_PMGM_ENCLOS_OPEN	0x6b
+#define TYPE_PMGM_ENCLOS_CLOSED	0x6c
+#define TYPE_PMGM_RING_INDICATE	0x6d
+#define TYPE_PMGM_LAN_ATTENTION	0x6e
+#define TYPE_PMGM_TIME_ALARM	0x6f
+#define TYPE_PMGM_CONFIG_CHANGE	0x70
+#define TYPE_PMGM_SERVICE_PROC	0x71
+
+struct rtas_error_log {
+	unsigned long version:8;		/* Architectural version */
+	unsigned long severity:3;		/* Severity level of error */
+	unsigned long disposition:2;		/* Degree of recovery */
+	unsigned long extended:1;		/* extended log present? */
+	unsigned long /* reserved */ :2;	/* Reserved for future use */
+	unsigned long initiator:4;		/* Initiator of event */
+	unsigned long target:4;			/* Target of failed operation */
+	unsigned long type:8;			/* General event or error*/
+	unsigned long extended_log_length:32;	/* length in bytes */
+	unsigned char buffer[1];		/* allocated by klimit bump */
+};
+
+extern struct rtas_t rtas;
+
+extern void enter_rtas(struct rtas_args *);
+extern int rtas_token(const char *service);
+extern long rtas_call(int token, int, int, unsigned long *, ...);
+extern void phys_call_rtas(int, int, int, ...);
+extern void phys_call_rtas_display_status(char);
+extern void call_rtas_display_status(char);
+extern void rtas_restart(char *cmd);
+extern void rtas_power_off(void);
+extern void rtas_halt(void);
+
+#endif /* _PPC64_RTAS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/rwsem.h linux-2.4.19-pre5/include/asm-ppc64/rwsem.h
--- linux-2.4.19-pre4/include/asm-ppc64/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/rwsem.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,139 @@
+/*
+ * include/asm-ppc/rwsem.h: R/W semaphores for PPC using the stuff
+ * in lib/rwsem.c.  Adapted largely from include/asm-i386/rwsem.h
+ * by Paul Mackerras <paulus@samba.org>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _PPC64_RWSEM_H
+#define _PPC64_RWSEM_H
+
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	/* XXX this should be able to be an atomic_t  -- paulus */
+	signed int		count;
+#define RWSEM_UNLOCKED_VALUE		0x00000000
+#define RWSEM_ACTIVE_BIAS		0x00000001
+#define RWSEM_ACTIVE_MASK		0x0000ffff
+#define RWSEM_WAITING_BIAS		(-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+#if RWSEM_DEBUG
+	int			debug;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+	{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
+	  LIST_HEAD_INIT((name).wait_list) \
+	  __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name)		\
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+	sem->debug = 0;
+#endif
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	if (atomic_inc_return((atomic_t *)(&sem->count)) >= 0)
+		smp_wmb();
+	else
+		rwsem_down_read_failed(sem);
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+				(atomic_t *)(&sem->count));
+	if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
+		smp_wmb();
+	else
+		rwsem_down_write_failed(sem);
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	smp_wmb();
+	tmp = atomic_dec_return((atomic_t *)(&sem->count));
+	if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
+		rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	smp_wmb();
+	if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+			      (atomic_t *)(&sem->count)) < 0)
+		rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+{
+	atomic_add(delta, (atomic_t *)(&sem->count));
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+	smp_mb();
+	return atomic_add_return(delta, (atomic_t *)(&sem->count));
+}
+
+#endif /* __KERNEL__ */
+#endif /* _PPC_RWSEM_XADD_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/scatterlist.h linux-2.4.19-pre5/include/asm-ppc64/scatterlist.h
--- linux-2.4.19-pre4/include/asm-ppc64/scatterlist.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/scatterlist.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,29 @@
+#ifndef _PPC64_SCATTERLIST_H
+#define _PPC64_SCATTERLIST_H
+
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/dma.h>
+
+struct scatterlist {
+	char *address;		/* Virtual addr data is to be transferred to */
+	struct page *page;	/* Location for highmem page, if any */
+	unsigned int offset;	/* for highmem, page offset */
+	unsigned int length;
+
+	/* For TCE support */
+	u32 dma_address;
+	u32 dma_length;
+};
+
+#define ISA_DMA_THRESHOLD	(~0UL)
+
+#endif /* !(_PPC64_SCATTERLIST_H) */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/segment.h linux-2.4.19-pre5/include/asm-ppc64/segment.h
--- linux-2.4.19-pre4/include/asm-ppc64/segment.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/segment.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,6 @@
+#ifndef __PPC64_SEGMENT_H
+#define __PPC64_SEGMENT_H
+
+/* Only here because we have some old header files that expect it.. */
+
+#endif /* __PPC64_SEGMENT_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/semaphore.h linux-2.4.19-pre5/include/asm-ppc64/semaphore.h
--- linux-2.4.19-pre4/include/asm-ppc64/semaphore.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/semaphore.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,135 @@
+#ifndef _PPC64_SEMAPHORE_H
+#define _PPC64_SEMAPHORE_H
+
+/*
+ * Swiped from asm-sparc/semaphore.h and modified
+ * -- Cort (cort@cs.nmt.edu)
+ *
+ * Stole some rw spinlock-based semaphore stuff from asm-alpha/semaphore.h
+ * -- Ani Joshi (ajoshi@unixbox.com)
+ *
+ * Remove spinlock-based RW semaphores; RW semaphore definitions are
+ * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * Rework semaphores to use atomic_dec_if_positive.
+ * -- Paul Mackerras (paulus@samba.org)
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
+
+struct semaphore {
+	/*
+	 * Note that any negative value of count is equivalent to 0,
+	 * but additionally indicates that some process(es) might be
+	 * sleeping on `wait'.
+	 */
+	atomic_t count;
+	wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+	long __magic;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+		, (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name, count) \
+	{ ATOMIC_INIT(count), \
+	  __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+	  __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+	__SEMAPHORE_INITIALIZER(name, 1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name, count) \
+	struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name)		__DECLARE_SEMAPHORE_GENERIC(name, 1)
+#define DECLARE_MUTEX_LOCKED(name)	__DECLARE_SEMAPHORE_GENERIC(name, 0)
+
+static inline void sema_init (struct semaphore *sem, int val)
+{
+	atomic_set(&sem->count, val);
+	init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (long)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+	sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+	sema_init(sem, 0);
+}
+
+extern void __down(struct semaphore * sem);
+extern int  __down_interruptible(struct semaphore * sem);
+extern void __up(struct semaphore * sem);
+
+extern inline void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	/*
+	 * Try to get the semaphore, take the slow path if we fail.
+	 */
+	if (atomic_dec_return(&sem->count) < 0)
+		__down(sem);
+	smp_wmb();
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	smp_wmb();
+	return ret;
+}
+
+extern inline int down_trylock(struct semaphore * sem)
+{
+	int ret;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	ret = atomic_dec_if_positive(&sem->count) < 0;
+	smp_wmb();
+	return ret;
+}
+
+extern inline void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	smp_wmb();
+	if (atomic_inc_return(&sem->count) <= 0)
+		__up(sem);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* !(_PPC64_SEMAPHORE_H) */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/sembuf.h linux-2.4.19-pre5/include/asm-ppc64/sembuf.h
--- linux-2.4.19-pre4/include/asm-ppc64/sembuf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/sembuf.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,27 @@
+#ifndef _PPC64_SEMBUF_H
+#define _PPC64_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for PPC architecture.
+ *
+ *
+ * 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.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;	/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;	/* last semop time */
+	__kernel_time_t	sem_ctime;	/* last change time */
+	unsigned long	sem_nsems;	/* no. of semaphores in array */
+
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
+
+#endif /* _PPC64_SEMBUF_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/serial.h linux-2.4.19-pre5/include/asm-ppc64/serial.h
--- linux-2.4.19-pre4/include/asm-ppc64/serial.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/serial.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,128 @@
+/*
+ * include/asm-ppc/serial.h
+ */
+
+#include <linux/config.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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
+#endif
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
+#define HUB6_FLAGS 0
+#endif
+	
+/*
+ * The following define the access methods for the HUB6 card. All
+ * access is through two ports for all 24 possible chips. The card is
+ * selected through the high 2 bits, the port on that card with the
+ * "middle" 3 bits, and the register on that port with the bottom
+ * 3 bits.
+ *
+ * While the access port and interrupt is configurable, the default
+ * port locations are 0x302 for the port control register, and 0x303
+ * for the data read/write register. Normally, the interrupt is at irq3
+ * but can be anything from 3 to 7 inclusive. Note that using 3 will
+ * require disabling com2.
+ */
+
+#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
+
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS			\
+	{ 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, 	/* ttyS4 */	\
+	{ 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },	/* ttyS5 */	\
+	{ 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },	/* ttyS6 */	\
+	{ 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },	/* ttyS7 */	\
+	{ 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },	/* ttyS8 */	\
+	{ 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },	/* ttyS9 */	\
+	{ 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },	/* ttyS10 */	\
+	{ 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },	/* ttyS11 */	\
+	{ 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },	/* ttyS12 */	\
+	{ 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },	/* ttyS13 */	\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS14 (spare) */		\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS15 (spare) */		\
+	{ 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },	/* ttyS16 */	\
+	{ 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },	/* ttyS17 */	\
+	{ 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },	/* ttyS18 */	\
+	{ 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },	/* ttyS19 */	\
+	{ 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },	/* ttyS20 */	\
+	{ 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },	/* ttyS21 */	\
+	{ 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },	/* ttyS22 */	\
+	{ 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },	/* ttyS23 */	\
+	{ 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },	/* ttyS24 */	\
+	{ 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },	/* ttyS25 */	\
+	{ 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },	/* ttyS26 */	\
+	{ 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },	/* ttyS27 */	\
+	{ 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },	/* ttyS28 */	\
+	{ 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },	/* ttyS29 */	\
+	{ 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },	/* ttyS30 */	\
+	{ 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },	/* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
+#endif
+
+/* You can have up to four HUB6's in the system, but I've only
+ * included two cards here for a total of twelve ports.
+ */
+#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
+#define HUB6_SERIAL_PORT_DFNS		\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
+#else
+#define HUB6_SERIAL_PORT_DFNS
+#endif
+
+#define MCA_SERIAL_PORT_DFNS
+
+#define SERIAL_PORT_DFNS		\
+	STD_SERIAL_PORT_DEFNS		\
+	EXTRA_SERIAL_PORT_DEFNS		\
+	HUB6_SERIAL_PORT_DFNS		\
+	MCA_SERIAL_PORT_DFNS
diff -urN linux-2.4.19-pre4/include/asm-ppc64/setup.h linux-2.4.19-pre5/include/asm-ppc64/setup.h
--- linux-2.4.19-pre4/include/asm-ppc64/setup.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/setup.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,6 @@
+#ifndef _PPC_SETUP_H
+#define _PPC_SETUP_H
+
+/* This is a place holder include */
+
+#endif /* _PPC_SETUP_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/shmbuf.h linux-2.4.19-pre5/include/asm-ppc64/shmbuf.h
--- linux-2.4.19-pre4/include/asm-ppc64/shmbuf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/shmbuf.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,43 @@
+#ifndef _PPC64_SHMBUF_H
+#define _PPC64_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for PPC64 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ *
+ * 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.
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	__kernel_time_t		shm_ctime;	/* last change time */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _PPC64_SHMBUF_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/shmparam.h linux-2.4.19-pre5/include/asm-ppc64/shmparam.h
--- linux-2.4.19-pre4/include/asm-ppc64/shmparam.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/shmparam.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,13 @@
+#ifndef _PPC64_SHMPARAM_H
+#define _PPC64_SHMPARAM_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define	SHMLBA PAGE_SIZE		 /* attach addr a multiple of this */
+
+#endif /* _PPC64_SHMPARAM_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/sigcontext.h linux-2.4.19-pre5/include/asm-ppc64/sigcontext.h
--- linux-2.4.19-pre4/include/asm-ppc64/sigcontext.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/sigcontext.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,34 @@
+#ifndef _ASM_PPC64_SIGCONTEXT_H
+#define _ASM_PPC64_SIGCONTEXT_H
+
+/*
+ * 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 <asm/ptrace.h>
+
+struct sigcontext_struct {
+	unsigned long	_unused[4];
+	int		signal;
+	unsigned long	handler;
+	unsigned long	oldmask;
+	struct pt_regs 	*regs;
+};
+
+#ifdef __KERNEL__
+
+struct sigcontext32_struct {
+	unsigned int	_unused[4];
+	int		signal;
+	unsigned int	handler;
+	unsigned int	oldmask;
+	u32 regs;  /* 4 byte pointer to the pt_regs32 structure. */
+};
+
+#endif /* __KERNEL__ */
+
+
+#endif /* _ASM_PPC64_SIGCONTEXT_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/siginfo.h linux-2.4.19-pre5/include/asm-ppc64/siginfo.h
--- linux-2.4.19-pre4/include/asm-ppc64/siginfo.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/siginfo.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,306 @@
+#ifndef _PPC64_SIGINFO_H
+#define _PPC64_SIGINFO_H
+
+/* Copied from i386 from alpha. */
+/*
+ * 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/types.h>
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+
+#ifdef __KERNEL__
+
+typedef union sigval32 {
+	int sival_int;
+	unsigned int sival_ptr;
+} sigval_t32;
+
+
+#endif /* __KERNEL__ */
+
+
+#define SI_MAX_SIZE	128
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
+			int _status;		/* exit code */
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			void *_addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+
+#ifdef __KERNEL__
+                
+typedef struct siginfo32 {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			__kernel_pid_t32 _pid;		/* sender's pid */
+			unsigned int _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			__kernel_pid_t32 _pid;		/* sender's pid */
+			unsigned int _uid;		/* sender's uid */
+			sigval_t32 _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			__kernel_pid_t32 _pid;		/* which child */
+			unsigned int _uid;		/* sender's uid */
+			int _status;			/* exit code */
+			__kernel_clock_t32 _utime;
+			__kernel_clock_t32 _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
+		struct {
+			u32 _addr; /* faulting insn/memory ref. */
+			int _trapno;
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t32;
+
+#endif /* __KERNEL__ */
+
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid		_sifields._kill._pid
+#define si_uid		_sifields._kill._uid
+#define si_status	_sifields._sigchld._status
+#define si_utime	_sifields._sigchld._utime
+#define si_stime	_sifields._sigchld._stime
+#define si_value	_sifields._rt._sigval
+#define si_int		_sifields._rt._sigval.sival_int
+#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_addr		_sifields._sigfault._addr
+#define si_band		_sifields._sigpoll._band
+#define si_fd		_sifields._sigpoll._fd
+
+#ifdef __KERNEL__
+#define __SI_MASK	0xffff0000
+#define __SI_KILL	(0 << 16)
+#define __SI_TIMER	(1 << 16)
+#define __SI_POLL	(2 << 16)
+#define __SI_FAULT	(3 << 16)
+#define __SI_CHLD	(4 << 16)
+#define __SI_RT		(5 << 16)
+#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
+#else
+#define __SI_KILL	0
+#define __SI_TIMER	0
+#define __SI_POLL	0
+#define __SI_FAULT	0
+#define __SI_CHLD	0
+#define __SI_RT		0
+#define __SI_CODE(T,N)	(N)
+#endif
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER		0		/* sent by kill, sigsend, raise */
+#define SI_KERNEL	0x80		/* sent by the kernel from somewhere */
+#define SI_QUEUE	-1		/* sent by sigqueue */
+#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
+#define SI_MESGQ	-3		/* sent by real time mesq state change */
+#define SI_ASYNCIO	-4		/* sent by AIO completion */
+#define SI_SIGIO	-5		/* sent by queued SIGIO */
+
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
+#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
+#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
+#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
+#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
+#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
+#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
+#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
+#define NSIGILL		8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
+#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
+#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
+#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
+#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
+#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
+#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
+#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
+#define NSIGFPE		8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
+#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
+#define NSIGSEGV	2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
+#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
+#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
+#define NSIGBUS		3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
+#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
+#define NSIGTRAP	2
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
+#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
+#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
+#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
+#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
+#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
+#define NSIGCHLD	6
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN		(__SI_POLL|1)	/* data input available */
+#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
+#define POLL_MSG	(__SI_POLL|3)	/* input message available */
+#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
+#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
+#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
+#define NSIGPOLL	6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL	0	/* notify via signal */
+#define SIGEV_NONE	1	/* other notification: meaningless */
+#define SIGEV_THREAD	2	/* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE	64
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[SIGEV_PAD_SIZE];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function	_sigev_un._sigev_thread._function
+#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+
+extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(siginfo_t));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+}
+
+extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
+
+#endif /* __KERNEL__ */
+
+#endif /* _PPC64_SIGINFO_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/signal.h linux-2.4.19-pre5/include/asm-ppc64/signal.h
--- linux-2.4.19-pre4/include/asm-ppc64/signal.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/signal.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,202 @@
+#ifndef _ASMPPC64_SIGNAL_H
+#define _ASMPPC64_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#define _NSIG		64
+#define _NSIG_BPW	64
+#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t;		/* at least 32 bits */
+
+typedef struct {
+	unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define SIGHUP		 1
+#define SIGINT		 2
+#define SIGQUIT		 3
+#define SIGILL		 4
+#define SIGTRAP		 5
+#define SIGABRT		 6
+#define SIGIOT		 6
+#define SIGBUS		 7
+#define SIGFPE		 8
+#define SIGKILL		 9
+#define SIGUSR1		10
+#define SIGSEGV		11
+#define SIGUSR2		12
+#define SIGPIPE		13
+#define SIGALRM		14
+#define SIGTERM		15
+#define SIGSTKFLT	16
+#define SIGCHLD		17
+#define SIGCONT		18
+#define SIGSTOP		19
+#define SIGTSTP		20
+#define SIGTTIN		21
+#define SIGTTOU		22
+#define SIGURG		23
+#define SIGXCPU		24
+#define SIGXFSZ		25
+#define SIGVTALRM	26
+#define SIGPROF		27
+#define SIGWINCH	28
+#define SIGIO		29
+#define SIGPOLL		SIGIO
+/*
+#define SIGLOST		29
+*/
+#define SIGPWR		30
+#define SIGSYS		31
+#define	SIGUNUSED	31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN	32
+#define SIGRTMAX	(_NSIG-1)
+
+
+
+#if defined(__KERNEL__) || defined(__WANT_POSIX1B_SIGNALS__)
+#define __old_sigset_t32	old_sigset_t32
+#define __old_sigaction32	old_sigaction32
+#else
+#endif
+
+
+
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP	0x00000001
+#define SA_NOCLDWAIT	0x00000002 /* not supported yet */
+#define SA_SIGINFO	0x00000004
+#define SA_ONSTACK	0x08000000
+#define SA_RESTART	0x10000000
+#define SA_NODEFER	0x40000000
+#define SA_RESETHAND	0x80000000
+
+#define SA_NOMASK	SA_NODEFER
+#define SA_ONESHOT	SA_RESETHAND
+#define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
+
+#define SA_RESTORER	0x04000000
+
+/* 
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	2048
+#define SIGSTKSZ	8192
+#ifdef __KERNEL__
+
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ */
+#define SA_PROBE		SA_ONESHOT
+#define SA_SAMPLE_RANDOM	SA_RESTART
+#define SA_SHIRQ		0x04000000
+#endif
+
+#define SIG_BLOCK          0	/* for blocking signals */
+#define SIG_UNBLOCK        1	/* for unblocking signals */
+#define SIG_SETMASK        2	/* for setting the signal mask */
+
+/* Type of a signal handler.  */
+typedef void (*__sighandler_t)(int);
+
+#define SIG_DFL	((__sighandler_t)0)	/* default signal handling */
+#define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
+#define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
+
+struct old_sigaction {
+	__sighandler_t sa_handler;
+	old_sigset_t sa_mask;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+};
+
+struct sigaction {
+	__sighandler_t sa_handler;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+	sigset_t sa_mask;		/* mask last for extensibility */
+};
+
+struct k_sigaction {
+	struct sigaction sa;
+};
+
+#ifdef __KERNEL__
+
+typedef unsigned int __old_sigset_t32;
+struct __old_sigaction32 {
+	unsigned		sa_handler;
+	__old_sigset_t32  	sa_mask;
+	unsigned int    	sa_flags;
+	unsigned		sa_restorer;     /* not used by Linux/SPARC yet */
+};
+
+
+
+#define _PPC32_NSIG	       64
+#define _PPC32_NSIG_BPW	       32
+#define _PPC32_NSIG_WORDS	       (_PPC32_NSIG / _PPC32_NSIG_BPW)
+
+typedef struct {
+       unsigned int sig[_PPC32_NSIG_WORDS];
+} sigset32_t;
+
+struct sigaction32 {
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+					     with 32 bits */
+       unsigned int sa_flags;
+       unsigned int sa_restorer;	/* Another 32 bit pointer */
+       sigset32_t sa_mask;		/* A 32 bit mask */
+};
+
+#endif /* __KERNEL__ */
+
+
+typedef struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+    
+typedef struct sigaltstack_32 {
+	unsigned int ss_sp;
+	int ss_flags;
+	__kernel_size_t32 ss_size;
+} stack_32_t;
+
+
+
+
+#endif
+
+#endif /* _ASMPPC64_SIGNAL_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/smp.h linux-2.4.19-pre5/include/asm-ppc64/smp.h
--- linux-2.4.19-pre4/include/asm-ppc64/smp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/smp.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,74 @@
+/* 
+ * smp.h: PPC64 specific SMP code.
+ *
+ * Original was a copy of sparc smp.h.  Now heavily modified
+ * for PPC.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996-2001 Cort Dougan <cort@fsmlabs.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.
+ */
+
+#ifdef __KERNEL__
+#ifndef _PPC64_SMP_H
+#define _PPC64_SMP_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+
+
+#ifdef CONFIG_SMP
+
+#ifndef __ASSEMBLY__
+
+#include <asm/Paca.h>
+
+struct current_set_struct {
+	struct task_struct *task;
+	unsigned long *sp_real;
+};
+
+extern unsigned long cpu_online_map;
+
+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_send_tlb_invalidate(int);
+extern void smp_send_xmon_break(int cpu);
+struct pt_regs;
+extern void smp_message_recv(int, struct pt_regs *);
+
+#define NO_PROC_ID		0xFF            /* No processor magic marker */
+#define PROC_CHANGE_PENALTY	20
+
+/* 1 to 1 mapping on PPC -- Cort */
+#define cpu_logical_map(cpu) (cpu)
+#define cpu_number_map(x) (x)
+extern volatile unsigned long cpu_callin_map[NR_CPUS];
+
+#define smp_processor_id() (get_paca()->xPacaIndex)
+#define hard_smp_processor_id() (get_paca()->xHwProcNum)
+#define get_hard_smp_processor_id(CPU) (xPaca[(CPU)].xHwProcNum)
+
+
+
+/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
+ *
+ * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
+ * in /proc/interrupts will be wrong!!! --Troy */
+#define PPC_MSG_CALL_FUNCTION   0
+#define PPC_MSG_RESCHEDULE      1
+#define PPC_MSG_INVALIDATE_TLB  2
+#define PPC_MSG_XMON_BREAK      3
+
+void smp_init_iSeries(void);
+void smp_init_pSeries(void);
+
+#endif /* __ASSEMBLY__ */
+#endif /* !(CONFIG_SMP) */
+#endif /* !(_PPC64_SMP_H) */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/smplock.h linux-2.4.19-pre5/include/asm-ppc64/smplock.h
--- linux-2.4.19-pre4/include/asm-ppc64/smplock.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/smplock.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,56 @@
+/*
+ * <asm/smplock.h>
+ *
+ * Default SMP lock implementation
+ *
+ * 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/interrupt.h>
+#include <linux/spinlock.h>
+
+extern spinlock_t kernel_flag;
+
+#define kernel_locked()		spin_is_locked(&kernel_flag)
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu) \
+do { \
+	if (task->lock_depth >= 0) \
+		spin_unlock(&kernel_flag); \
+	release_irqlock(cpu); \
+	__sti(); \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task) \
+do { \
+	if (task->lock_depth >= 0) \
+		spin_lock(&kernel_flag); \
+} while (0)
+
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+	if (!++current->lock_depth)
+		spin_lock(&kernel_flag);
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+	if (--current->lock_depth < 0)
+		spin_unlock(&kernel_flag);
+}
diff -urN linux-2.4.19-pre4/include/asm-ppc64/socket.h linux-2.4.19-pre5/include/asm-ppc64/socket.h
--- linux-2.4.19-pre4/include/asm-ppc64/socket.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/socket.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,71 @@
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+/*
+ * 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 <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET	1
+
+#define SO_DEBUG	1
+#define SO_REUSEADDR	2
+#define SO_TYPE		3
+#define SO_ERROR	4
+#define SO_DONTROUTE	5
+#define SO_BROADCAST	6
+#define SO_SNDBUF	7
+#define SO_RCVBUF	8
+#define SO_KEEPALIVE	9
+#define SO_OOBINLINE	10
+#define SO_NO_CHECK	11
+#define SO_PRIORITY	12
+#define SO_LINGER	13
+#define SO_BSDCOMPAT	14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_RCVLOWAT	16
+#define SO_SNDLOWAT	17
+#define SO_RCVTIMEO	18
+#define SO_SNDTIMEO	19
+#define SO_PASSCRED	20
+#define SO_PEERCRED	21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION		22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT	23
+#define SO_SECURITY_ENCRYPTION_NETWORK		24
+
+#define SO_BINDTODEVICE	25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER	26
+#define SO_DETACH_FILTER	27
+
+#define SO_PEERNAME		28
+#define SO_TIMESTAMP		29
+#define SCM_TIMESTAMP		SO_TIMESTAMP
+
+#define SO_ACCEPTCONN           30
+
+/* Nast libc5 fixup - bletch */
+#if defined(__KERNEL__)
+/* Socket types. */
+#define SOCK_STREAM	1		/* stream (connection) socket	*/
+#define SOCK_DGRAM	2		/* datagram (conn.less) socket	*/
+#define SOCK_RAW	3		/* raw socket			*/
+#define SOCK_RDM	4		/* reliably-delivered message	*/
+#define SOCK_SEQPACKET	5		/* sequential packet socket	*/
+#define SOCK_PACKET	10		/* linux specific way of	*/
+					/* getting packets at the dev	*/
+					/* level.  For writing rarp and	*/
+					/* other similar things on the	*/
+					/* user level.			*/
+#define	SOCK_MAX	(SOCK_PACKET+1)
+#endif
+
+#endif /* _ASM_SOCKET_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/sockios.h linux-2.4.19-pre5/include/asm-ppc64/sockios.h
--- linux-2.4.19-pre4/include/asm-ppc64/sockios.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/sockios.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,19 @@
+#ifndef _ASM_PPC64_SOCKIOS_H
+#define _ASM_PPC64_SOCKIOS_H
+
+/*
+ * 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.
+ */
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN 	0x8901
+#define SIOCSPGRP	0x8902
+#define FIOGETOWN	0x8903
+#define SIOCGPGRP	0x8904
+#define SIOCATMARK	0x8905
+#define SIOCGSTAMP	0x8906		/* Get stamp */
+
+#endif /* _ASM_PPC64_SOCKIOS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/softirq.h linux-2.4.19-pre5/include/asm-ppc64/softirq.h
--- linux-2.4.19-pre4/include/asm-ppc64/softirq.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/softirq.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,29 @@
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+/*
+ * 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 <asm/atomic.h>
+#include <asm/hardirq.h>
+
+
+#define local_bh_disable()	do { local_bh_count(smp_processor_id())++; barrier(); } while (0)
+#define __local_bh_enable()	do { barrier(); local_bh_count(smp_processor_id())--; } while (0)
+
+#define local_bh_enable()  \
+do {                                                    \
+        if (!--local_bh_count(smp_processor_id())       \
+            && softirq_pending(smp_processor_id())) {   \
+                do_softirq();                           \
+        }                                               \
+} while (0)
+
+
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+
+#endif	/* __ASM_SOFTIRQ_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/spinlock.h linux-2.4.19-pre5/include/asm-ppc64/spinlock.h
--- linux-2.4.19-pre4/include/asm-ppc64/spinlock.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/spinlock.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,215 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+/*
+ * Simple spin lock operations.  
+ *
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * Type of int is used as a full 64b word is not necessary.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+typedef struct {
+	volatile unsigned int lock;
+} spinlock_t;
+
+#ifdef __KERNEL__
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
+
+#define spin_is_locked(x)	((x)->lock != 0)
+
+static __inline__ int spin_trylock(spinlock_t *lock)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+"1:	lwarx		%0,0,%1		# spin_trylock\n\
+	cmpwi		0,%0,0\n\
+	li		%0,0\n\
+	bne-		2f\n\
+	li		%0,1\n\
+	stwcx.		%0,0,%1\n\
+	bne-		1b\n\
+	isync\n\
+2:"	: "=&r"(tmp)
+	: "r"(&lock->lock)
+	: "cr0", "memory");
+
+	return tmp;
+}
+
+static __inline__ void spin_lock(spinlock_t *lock)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"b		2f		# spin_lock\n\
+1:	or		1,1,1		# spin at low priority\n\
+	lwzx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne+		1b\n\
+	or		2,2,2		# back to medium priority\n\
+2:	lwarx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne-		1b\n\
+	stwcx.		%2,0,%1\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp)
+	: "r"(&lock->lock), "r"(1)
+	: "cr0", "memory");
+}
+
+static __inline__ void spin_unlock(spinlock_t *lock)
+{
+	__asm__ __volatile__("eieio	# spin_unlock": : :"memory");
+	lock->lock = 0;
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct {
+	volatile signed int lock;
+} rwlock_t;
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+
+static __inline__ int read_trylock(rwlock_t *rw)
+{
+	unsigned int tmp;
+	unsigned int ret;
+
+	__asm__ __volatile__(
+"1:	lwarx		%0,0,%2		# read_trylock\n\
+	li		%1,0\n\
+	extsw		%0,%0\n\
+	addic.		%0,%0,1\n\
+	ble-		2f\n\
+	stwcx.		%0,0,%2\n\
+	bne-		1b\n\
+	li		%1,1\n\
+	isync\n\
+2:"	: "=&r"(tmp), "=&r"(ret)
+	: "r"(&rw->lock)
+	: "cr0", "memory");
+
+	return ret;
+}
+
+static __inline__ void read_lock(rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"b		2f		# read_lock\n\
+1:	or		1,1,1		# spin at low priority\n\
+	lwax		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	blt+		1b\n\
+	or		2,2,2		# back to medium priority\n\
+2:	lwarx		%0,0,%1\n\
+	extsw		%0,%0\n\
+	addic.		%0,%0,1\n\
+	ble-		1b\n\
+	stwcx.		%0,0,%1\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp)
+	: "r"(&rw->lock)
+	: "cr0", "memory");
+}
+
+static __inline__ void read_unlock(rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"eieio				# read_unlock\n\
+1:	lwarx		%0,0,%1\n\
+	addic		%0,%0,-1\n\
+	stwcx.		%0,0,%1\n\
+	bne-		1b"
+	: "=&r"(tmp)
+	: "r"(&rw->lock)
+	: "cr0", "memory");
+}
+
+static __inline__ int write_trylock(rwlock_t *rw)
+{
+	unsigned int tmp;
+	unsigned int ret;
+
+	__asm__ __volatile__(
+"1:	lwarx		%0,0,%2		# write_trylock\n\
+	cmpwi		0,%0,0\n\
+	li		%1,0\n\
+	bne-		2f\n\
+	stwcx.		%3,0,%2\n\
+	bne-		1b\n\
+	li		%1,1\n\
+	isync\n\
+2:"	: "=&r"(tmp), "=&r"(ret)
+	: "r"(&rw->lock), "r"(-1)
+	: "cr0", "memory");
+
+	return ret;
+}
+
+static __inline__ void write_lock(rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"b		2f		# write_lock\n\
+1:	or		1,1,1		# spin at low priority\n\
+	lwax		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne+		1b\n\
+	or		2,2,2		# back to medium priority\n\
+2:	lwarx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne-		1b\n\
+	stwcx.		%2,0,%1\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp)
+	: "r"(&rw->lock), "r"(-1)
+	: "cr0", "memory");
+}
+
+static __inline__ void write_unlock(rwlock_t *rw)
+{
+	__asm__ __volatile__("eieio		# write_unlock": : :"memory");
+	rw->lock = 0;
+}
+
+static __inline__ int is_read_locked(rwlock_t *rw)
+{
+	return rw->lock > 0;
+}
+
+static __inline__ int is_write_locked(rwlock_t *rw)
+{
+	return rw->lock < 0;
+}
+
+#define spin_lock_init(x)      do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_unlock_wait(x)    do { barrier(); } while(spin_is_locked(x))
+
+#define rwlock_init(x)         do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_SPINLOCK_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/stat.h linux-2.4.19-pre5/include/asm-ppc64/stat.h
--- linux-2.4.19-pre4/include/asm-ppc64/stat.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/stat.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,108 @@
+#ifndef _PPC64_STAT_H
+#define _PPC64_STAT_H
+
+/*
+ * 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/types.h>
+
+struct stat32 {
+	__kernel_dev_t32   st_dev; /* 2 */
+	/* __kernel_dev_t32 __pad1; */ /* 2 */
+	__kernel_ino_t32   st_ino; /* 4  */
+	__kernel_mode_t32  st_mode; /* 2  */
+	short   	   st_nlink; /* 2 */
+	__kernel_uid_t32   st_uid; /* 2 */
+	__kernel_gid_t32   st_gid; /* 2 */
+	__kernel_dev_t32   st_rdev; /* 2 */
+	/* __kernel_dev_t32 __pad2; */ /* 2 */
+	__kernel_off_t32   st_size; /* 4 */
+	__kernel_off_t32   st_blksize; /* 4 */
+	__kernel_off_t32   st_blocks; /* 4 */
+	__kernel_time_t32  st_atime; /* 4 */
+	unsigned int       __unused1; /* 4 */
+	__kernel_time_t32  st_mtime; /* 4 */
+	unsigned int       __unused2; /* 4 */
+	__kernel_time_t32  st_ctime; /* 4 */
+	unsigned int       __unused3; /* 4 */
+	unsigned int  __unused4[2]; /* 2*4 */
+};
+
+struct __old_kernel_stat {
+	unsigned short st_dev;
+	unsigned short st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned long  st_size;
+	unsigned long  st_atime;
+	unsigned long  st_mtime;
+	unsigned long  st_ctime;
+};
+
+struct __old_kernel_stat32
+{
+	unsigned short st_dev;
+	unsigned short st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned int   st_size;
+	unsigned int   st_atime;
+	unsigned int   st_mtime;
+	unsigned int   st_ctime;
+};
+
+struct stat {
+	dev_t		st_dev;
+	ino_t		st_ino;
+	mode_t		st_mode;
+	nlink_t		st_nlink;
+	uid_t 		st_uid;
+	gid_t 		st_gid;
+	dev_t		st_rdev;
+	off_t		st_size;
+	unsigned long  	st_blksize;
+	unsigned long  	st_blocks;
+	unsigned long  	st_atime;
+	unsigned long  	__unused1;
+	unsigned long  	st_mtime;
+	unsigned long  	__unused2;
+	unsigned long  	st_ctime;
+	unsigned long  	__unused3;
+	unsigned long  	__unused4;
+	unsigned long  	__unused5;
+};
+
+/* This matches struct stat64 in glibc2.1. */
+struct stat64 {
+	unsigned long st_dev; 		/* Device.  */
+	unsigned long st_ino;		/* File serial number.  */
+	unsigned int st_mode;		/* File mode.  */
+	unsigned int st_nlink;		/* Link count.  */
+	unsigned int st_uid;		/* User ID of the file's owner.  */
+	unsigned int st_gid;		/* Group ID of the file's group. */
+	unsigned long st_rdev; 		/* Device number, if device.  */
+	unsigned short __pad2;
+	long st_size;			/* Size of file, in bytes.  */
+	int  st_blksize;		/* Optimal block size for I/O.  */
+
+	long st_blocks;			/* Number 512-byte blocks allocated. */
+	int   st_atime;			/* Time of last access.  */
+	unsigned int  __unused1;
+	int   st_mtime;			/* Time of last modification.  */
+	unsigned int  __unused2;
+	int   st_ctime;			/* Time of last status change.  */
+	unsigned int   __unused3;
+	unsigned int   __unused4;
+	unsigned int   __unused5;
+};
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/statfs.h linux-2.4.19-pre5/include/asm-ppc64/statfs.h
--- linux-2.4.19-pre4/include/asm-ppc64/statfs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/statfs.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,53 @@
+#ifndef _PPC64_STATFS_H
+#define _PPC64_STATFS_H
+
+/*
+ * 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.
+ */
+
+#ifndef __KERNEL_STRICT_NAMES
+
+#include <linux/types.h>
+
+typedef __kernel_fsid_t	fsid_t;
+typedef __kernel_fsid_t __kernel_fsid_t32;
+
+#endif
+
+/* 
+ * Both SPARC64 & IA64 also define the following -
+ */
+
+struct statfs32 {
+	int f_type;
+	int f_bsize;
+	int f_blocks;
+	int f_bfree;
+	int f_bavail;
+	int f_files;
+	int f_ffree;
+	__kernel_fsid_t32 f_fsid;
+	int f_namelen;  /* SunOS ignores this field. */
+	int f_spare[6];
+};
+
+struct statfs {
+	long f_type;
+	long f_bsize;
+	long f_blocks;
+	long f_bfree;
+	long f_bavail;
+	long f_files;
+	long f_ffree;
+	__kernel_fsid_t f_fsid;
+	long f_namelen;
+	long f_spare[6];
+};
+
+#endif  /* _PPC64_STATFS_H */
+
+
+
diff -urN linux-2.4.19-pre4/include/asm-ppc64/string.h linux-2.4.19-pre5/include/asm-ppc64/string.h
--- linux-2.4.19-pre4/include/asm-ppc64/string.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/string.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,36 @@
+#ifndef _PPC64_STRING_H_
+#define _PPC64_STRING_H_
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRNCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCHR
+
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, int);
+extern char * strcpy(char *,const char *);
+extern char * strncpy(char *,const char *, __kernel_size_t);
+extern __kernel_size_t strlen(const char *);
+extern int strcmp(const char *,const char *);
+extern char * strcat(char *, const char *);
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memmove(void *,const void *,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t);
+extern void * memchr(const void *,int,__kernel_size_t);
+
+#endif /* _PPC64_STRING_H_ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/system.h linux-2.4.19-pre5/include/asm-ppc64/system.h
--- linux-2.4.19-pre4/include/asm-ppc64/system.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/system.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,274 @@
+#ifndef __PPC64_SYSTEM_H
+#define __PPC64_SYSTEM_H
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kdev_t.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/hw_irq.h>
+#include <asm/memory.h>
+
+/*
+ * System defines.
+ */
+#define KERNEL_START_PHYS	0x800000 
+#define KERNEL_START	        (PAGE_OFFSET+KERNEL_START_PHYS)
+#define START_ADDR	        (PAGE_OFFSET+KERNEL_START_PHYS+0x00000)
+
+/*
+ * Memory barrier.
+ * The sync instruction guarantees that all memory accesses initiated
+ * by this processor have been performed (with respect to all other
+ * mechanisms that access memory).  The eieio instruction is a barrier
+ * providing an ordering (separately) for (a) cacheable stores and (b)
+ * loads and stores to non-cacheable memory (e.g. I/O devices).
+ *
+ * mb() prevents loads and stores being reordered across this point.
+ * rmb() prevents loads being reordered across this point.
+ * wmb() prevents stores being reordered across this point.
+ *
+ * We can use the eieio instruction for wmb, but since it doesn't
+ * give any ordering guarantees about loads, we have to use the
+ * stronger but slower sync instruction for mb and rmb.
+ */
+#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define rmb()  __asm__ __volatile__ ("lwsync" : : : "memory")
+#define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")
+
+#define set_mb(var, value)	do { var = value; mb(); } while (0)
+#define set_wmb(var, value)	do { var = value; wmb(); } while (0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#else
+#define smp_mb()	__asm__ __volatile__("": : :"memory")
+#define smp_rmb()	__asm__ __volatile__("": : :"memory")
+#define smp_wmb()	__asm__ __volatile__("": : :"memory")
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_XMON
+extern void xmon_irq(int, void *, struct pt_regs *);
+extern void xmon(struct pt_regs *excp);
+#endif
+
+extern void print_backtrace(unsigned long *);
+extern void show_regs(struct pt_regs * regs);
+extern void flush_instruction_cache(void);
+extern void hard_reset_now(void);
+extern void poweroff_now(void);
+extern int _get_PVR(void);
+extern long _get_L2CR(void);
+extern void _set_L2CR(unsigned long);
+extern void via_cuda_init(void);
+extern void pmac_nvram_init(void);
+extern void pmac_find_display(void);
+extern void giveup_fpu(struct task_struct *);
+extern void enable_kernel_fp(void);
+extern void giveup_altivec(struct task_struct *);
+extern void load_up_altivec(struct task_struct *);
+extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
+extern void cvt_df(double *from, float *to, unsigned long *fpscr);
+extern int abs(int);
+extern void cacheable_memzero(void *p, unsigned int nb);
+
+struct device_node;
+
+struct task_struct;
+#define prepare_to_switch()	do { } while(0)
+#define switch_to(prev,next,last) _switch_to((prev),(next),&(last))
+extern void _switch_to(struct task_struct *, struct task_struct *,
+		       struct task_struct **);
+
+struct thread_struct;
+extern struct task_struct *_switch(struct thread_struct *prev,
+				   struct thread_struct *next);
+
+struct pt_regs;
+extern void dump_regs(struct pt_regs *);
+
+#ifndef CONFIG_SMP
+
+#define cli()	__cli()
+#define sti()	__sti()
+#define save_flags(flags)	__save_flags(flags)
+#define restore_flags(flags)	__restore_flags(flags)
+#define save_and_cli(flags)	__save_and_cli(flags)
+
+#else /* CONFIG_SMP */
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+
+#endif /* !CONFIG_SMP */
+
+#define local_irq_disable()		__cli()
+#define local_irq_enable()		__sti()
+#define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_restore(flags)	__restore_flags(flags)
+
+static __inline__ int __is_processor(unsigned long pv)
+{
+      unsigned long pvr;
+      asm volatile("mfspr %0, 0x11F" : "=r" (pvr)); 
+      return(PVR_VER(pvr) == pv);
+}
+
+/*
+ * Atomic exchange
+ *
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ *
+ * Inline asm pulled from arch/ppc/kernel/misc.S so ppc64
+ * is more like most of the other architectures.
+ */
+static __inline__ unsigned long
+__xchg_u32(volatile int *m, unsigned long val)
+{
+	unsigned long dummy;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	lwarx %0,0,%3		# __xchg_u32\n\
+	stwcx. %2,0,%3\n\
+2:	bne- 1b"
+	ISYNC_ON_SMP
+ 	: "=&r" (dummy), "=m" (*m)
+	: "r" (val), "r" (m)
+	: "cc", "memory");
+
+	return (dummy);
+}
+
+static __inline__ unsigned long
+__xchg_u64(volatile long *m, unsigned long val)
+{
+	unsigned long dummy;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx %0,0,%3		# __xchg_u64\n\
+	stdcx. %2,0,%3\n\
+2:	bne- 1b"
+	ISYNC_ON_SMP
+	: "=&r" (dummy), "=m" (*m)
+	: "r" (val), "r" (m)
+	: "cc", "memory");
+
+	return (dummy);
+}
+
+/*
+ * This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid xchg().
+ */
+extern void __xchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__xchg(volatile void *ptr, unsigned long x, int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32(ptr, x);
+	case 8:
+		return __xchg_u64(ptr, x);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+#define xchg(ptr,x)							     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
+  })
+
+#define tas(ptr) (xchg((ptr),1))
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+static __inline__ unsigned long
+__cmpxchg_u32(volatile int *p, int old, int new)
+{
+	int prev;
+
+	__asm__ __volatile__ (
+	EIEIO_ON_SMP
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
+	cmpw	0,%0,%3\n\
+	bne-	2f\n\
+	stwcx.	%4,0,%2\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	"\n\
+2:"
+	: "=&r" (prev), "=m" (*p)
+	: "r" (p), "r" (old), "r" (new), "m" (*p)
+	: "cc", "memory");
+
+	return prev;
+}
+
+static __inline__ unsigned long
+__cmpxchg_u64(volatile long *p, unsigned long old, unsigned long new)
+{
+	int prev;
+
+	__asm__ __volatile__ (
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
+	cmpd	0,%0,%3\n\
+	bne-	2f\n\
+	stdcx.	%4,0,%2\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	"\n\
+2:"
+	: "=&r" (prev), "=m" (*p)
+	: "r" (p), "r" (old), "r" (new), "m" (*p)
+	: "cc", "memory");
+
+	return prev;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	case 8:
+		return __cmpxchg_u64(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/termbits.h linux-2.4.19-pre5/include/asm-ppc64/termbits.h
--- linux-2.4.19-pre4/include/asm-ppc64/termbits.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/termbits.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,192 @@
+#ifndef _PPC64_TERMBITS_H
+#define _PPC64_TERMBITS_H
+
+/*
+ * 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/posix_types.h>
+
+typedef unsigned char	cc_t;
+typedef unsigned int	speed_t;
+typedef unsigned int	tcflag_t;
+
+/*
+ * termios type and macro definitions.  Be careful about adding stuff
+ * to this file since it's used in GNU libc and there are strict rules
+ * concerning namespace pollution.
+ */
+
+#define NCCS 19
+struct termios {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_cc[NCCS];		/* control characters */
+	cc_t c_line;			/* line discipline (== c_cc[19]) */
+	speed_t c_ispeed;		/* input speed */
+	speed_t c_ospeed;		/* output speed */
+};
+
+/* c_cc characters */
+#define VINTR 	         0
+#define VQUIT 	         1
+#define VERASE 	         2
+#define VKILL	         3
+#define VEOF	         4
+#define VMIN	         5
+#define VEOL	         6
+#define VTIME	         7
+#define VEOL2	         8
+#define VSWTC	         9
+#define VWERASE 	10
+#define VREPRINT	11
+#define VSUSP 		12
+#define VSTART		13
+#define VSTOP		14
+#define VLNEXT		15
+#define VDISCARD	16
+
+/* c_iflag bits */
+#define IGNBRK	0000001
+#define BRKINT	0000002
+#define IGNPAR	0000004
+#define PARMRK	0000010
+#define INPCK	0000020
+#define ISTRIP	0000040
+#define INLCR	0000100
+#define IGNCR	0000200
+#define ICRNL	0000400
+#define IXON	0001000
+#define IXOFF	0002000
+#define IXANY	0004000
+#define IUCLC	0010000
+#define IMAXBEL	0020000
+
+/* c_oflag bits */
+#define OPOST	0000001
+#define ONLCR	0000002
+#define OLCUC	0000004
+
+#define OCRNL	0000010
+#define ONOCR	0000020
+#define ONLRET	0000040
+
+#define OFILL	00000100
+#define OFDEL	00000200
+#define NLDLY	00001400
+#define   NL0	00000000
+#define   NL1	00000400
+#define   NL2	00001000
+#define   NL3	00001400
+#define TABDLY	00006000
+#define   TAB0	00000000
+#define   TAB1	00002000
+#define   TAB2	00004000
+#define   TAB3	00006000
+#define CRDLY	00030000
+#define   CR0	00000000
+#define   CR1	00010000
+#define   CR2	00020000
+#define   CR3	00030000
+#define FFDLY	00040000
+#define   FF0	00000000
+#define   FF1	00040000
+#define BSDLY	00100000
+#define   BS0	00000000
+#define   BS1	00100000
+#define VTDLY	00200000
+#define   VT0	00000000
+#define   VT1	00200000
+#define XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
+
+/* c_cflag bit meaning */
+#define CBAUD	0000377
+#define  B0	0000000		/* hang up */
+#define  B50	0000001
+#define  B75	0000002
+#define  B110	0000003
+#define  B134	0000004
+#define  B150	0000005
+#define  B200	0000006
+#define  B300	0000007
+#define  B600	0000010
+#define  B1200	0000011
+#define  B1800	0000012
+#define  B2400	0000013
+#define  B4800	0000014
+#define  B9600	0000015
+#define  B19200	0000016
+#define  B38400	0000017
+#define  EXTA   B19200
+#define  EXTB   B38400
+#define  CBAUDEX 0000000
+#define  B57600   00020
+#define  B115200  00021
+#define  B230400  00022
+#define  B460800  00023
+#define  B500000  00024
+#define  B576000  00025
+#define  B921600  00026
+#define B1000000  00027
+#define B1152000  00030
+#define B1500000  00031
+#define B2000000  00032
+#define B2500000  00033
+#define B3000000  00034
+#define B3500000  00035
+#define B4000000  00036
+
+#define CSIZE	00001400
+#define   CS5	00000000
+#define   CS6	00000400
+#define   CS7	00001000
+#define   CS8	00001400
+
+#define CSTOPB	00002000
+#define CREAD	00004000
+#define PARENB	00010000
+#define PARODD	00020000
+#define HUPCL	00040000
+
+#define CLOCAL	00100000
+#define CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define ISIG	0x00000080
+#define ICANON	0x00000100
+#define XCASE	0x00004000
+#define ECHO	0x00000008
+#define ECHOE	0x00000002
+#define ECHOK	0x00000004
+#define ECHONL	0x00000010
+#define NOFLSH	0x80000000
+#define TOSTOP	0x00400000
+#define ECHOCTL	0x00000040
+#define ECHOPRT	0x00000020
+#define ECHOKE	0x00000001
+#define FLUSHO	0x00800000
+#define PENDIN	0x20000000
+#define IEXTEN	0x00000400
+
+/* Values for the ACTION argument to `tcflow'.  */
+#define	TCOOFF		0
+#define	TCOON		1
+#define	TCIOFF		2
+#define	TCION		3
+
+/* Values for the QUEUE_SELECTOR argument to `tcflush'.  */
+#define	TCIFLUSH	0
+#define	TCOFLUSH	1
+#define	TCIOFLUSH	2
+
+/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'.  */
+#define	TCSANOW		0
+#define	TCSADRAIN	1
+#define	TCSAFLUSH	2
+
+#endif /* _PPC64_TERMBITS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/termios.h linux-2.4.19-pre5/include/asm-ppc64/termios.h
--- linux-2.4.19-pre4/include/asm-ppc64/termios.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/termios.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,236 @@
+#ifndef _PPC64_TERMIOS_H
+#define _PPC64_TERMIOS_H
+
+/*
+ * Liberally adapted from alpha/termios.h.  In particular, the c_cc[]
+ * fields have been reordered so that termio & termios share the
+ * common subset in the same order (for brain dead programs that don't
+ * know or care about the differences).
+ *
+ * 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 <asm/ioctls.h>
+#include <asm/termbits.h>
+
+struct sgttyb {
+	char	sg_ispeed;
+	char	sg_ospeed;
+	char	sg_erase;
+	char	sg_kill;
+	short	sg_flags;
+};
+
+struct tchars {
+	char	t_intrc;
+	char	t_quitc;
+	char	t_startc;
+	char	t_stopc;
+	char	t_eofc;
+	char	t_brkc;
+};
+
+struct ltchars {
+	char	t_suspc;
+	char	t_dsuspc;
+	char	t_rprntc;
+	char	t_flushc;
+	char	t_werasc;
+	char	t_lnextc;
+};
+
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#define NCC 10
+struct termio {
+	unsigned short c_iflag;		/* input mode flags */
+	unsigned short c_oflag;		/* output mode flags */
+	unsigned short c_cflag;		/* control mode flags */
+	unsigned short c_lflag;		/* local mode flags */
+	unsigned char c_line;		/* line discipline */
+	unsigned char c_cc[NCC];	/* control characters */
+};
+
+/* c_cc characters */
+#define _VINTR	0
+#define _VQUIT	1
+#define _VERASE	2
+#define _VKILL	3
+#define _VEOF	4
+#define _VMIN	5
+#define _VEOL	6
+#define _VTIME	7
+#define _VEOL2	8
+#define _VSWTC	9
+
+/* line disciplines */
+#define N_TTY		0
+#define N_SLIP		1
+#define N_MOUSE		2
+#define N_PPP		3
+#define N_STRIP		4
+#define N_AX25		5
+#define N_X25		6	/* X.25 async */
+#define N_6PACK		7
+#define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964		9	/* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA		11	/* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC		13	/* synchronous HDLC */
+#define N_SYNC_PPP	14
+
+#ifdef __KERNEL__
+/*                   ^C  ^\ del  ^U  ^D   1   0   0   0   0  ^W  ^R  ^Z  ^Q  ^S  ^V  ^U  */
+#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025" 
+#endif
+
+#define FIOCLEX		_IO('f', 1)
+#define FIONCLEX	_IO('f', 2)
+#define FIOASYNC	_IOW('f', 125, int)
+#define FIONBIO		_IOW('f', 126, int)
+#define FIONREAD	_IOR('f', 127, int)
+#define TIOCINQ		FIONREAD
+
+#define TIOCGETP	_IOR('t', 8, struct sgttyb)
+#define TIOCSETP	_IOW('t', 9, struct sgttyb)
+#define TIOCSETN	_IOW('t', 10, struct sgttyb)	/* TIOCSETP wo flush */
+
+#define TIOCSETC	_IOW('t', 17, struct tchars)
+#define TIOCGETC	_IOR('t', 18, struct tchars)
+#define TCGETS		_IOR('t', 19, struct termios)
+#define TCSETS		_IOW('t', 20, struct termios)
+#define TCSETSW		_IOW('t', 21, struct termios)
+#define TCSETSF		_IOW('t', 22, struct termios)
+
+#define TCGETA		_IOR('t', 23, struct termio)
+#define TCSETA		_IOW('t', 24, struct termio)
+#define TCSETAW		_IOW('t', 25, struct termio)
+#define TCSETAF		_IOW('t', 28, struct termio)
+
+#define TCSBRK		_IO('t', 29)
+#define TCXONC		_IO('t', 30)
+#define TCFLSH		_IO('t', 31)
+
+#define TIOCSWINSZ	_IOW('t', 103, struct winsize)
+#define TIOCGWINSZ	_IOR('t', 104, struct winsize)
+#define	TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
+#define	TIOCSTOP	_IO('t', 111)		/* stop output, like ^S */
+#define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
+
+#define TIOCGLTC	_IOR('t', 116, struct ltchars)
+#define TIOCSLTC	_IOW('t', 117, struct ltchars)
+#define TIOCSPGRP	_IOW('t', 118, int)
+#define TIOCGPGRP	_IOR('t', 119, int)
+
+#define TIOCEXCL	0x540C
+#define TIOCNXCL	0x540D
+#define TIOCSCTTY	0x540E
+
+#define TIOCSTI		0x5412
+#define TIOCMGET	0x5415
+#define TIOCMBIS	0x5416
+#define TIOCMBIC	0x5417
+#define TIOCMSET	0x5418
+#define TIOCGSOFTCAR	0x5419
+#define TIOCSSOFTCAR	0x541A
+#define TIOCLINUX	0x541C
+#define TIOCCONS	0x541D
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TIOCPKT		0x5420
+
+#define TIOCNOTTY	0x5422
+#define TIOCSETD	0x5423
+#define TIOCGETD	0x5424
+#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+
+#define TIOCSERCONFIG	0x5453
+#define TIOCSERGWILD	0x5454
+#define TIOCSERSWILD	0x5455
+#define TIOCGLCKTRMIOS	0x5456
+#define TIOCSLCKTRMIOS	0x5457
+#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA		 0
+#define TIOCPKT_FLUSHREAD	 1
+#define TIOCPKT_FLUSHWRITE	 2
+#define TIOCPKT_STOP		 4
+#define TIOCPKT_START		 8
+#define TIOCPKT_NOSTOP		16
+#define TIOCPKT_DOSTOP		32
+
+/* modem lines */
+#define TIOCM_LE	0x001
+#define TIOCM_DTR	0x002
+#define TIOCM_RTS	0x004
+#define TIOCM_ST	0x008
+#define TIOCM_SR	0x010
+#define TIOCM_CTS	0x020
+#define TIOCM_CAR	0x040
+#define TIOCM_RNG	0x080
+#define TIOCM_DSR	0x100
+#define TIOCM_CD	TIOCM_CAR
+#define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+
+#ifdef __KERNEL__
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+	unsigned short __tmp; \
+	get_user(__tmp,&(termio)->x); \
+	(termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+	put_user((termios)->c_iflag, &(termio)->c_iflag); \
+	put_user((termios)->c_oflag, &(termio)->c_oflag); \
+	put_user((termios)->c_cflag, &(termio)->c_cflag); \
+	put_user((termios)->c_lflag, &(termio)->c_lflag); \
+	put_user((termios)->c_line,  &(termio)->c_line); \
+	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _PPC64_TERMIOS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/time.h linux-2.4.19-pre5/include/asm-ppc64/time.h
--- linux-2.4.19-pre4/include/asm-ppc64/time.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/time.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,104 @@
+/*
+ * 
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ *
+ * 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.
+ */
+
+#ifndef __PPC64_TIME_H
+#define __PPC64_TIME_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/processor.h>
+#include <asm/Paca.h>
+#include <asm/iSeries/HvCall.h>
+
+/* time.c */
+extern unsigned long tb_ticks_per_jiffy;
+extern unsigned long tb_ticks_per_usec;
+extern unsigned long tb_ticks_per_sec;
+extern unsigned long tb_to_xs;
+extern unsigned      tb_to_us;
+extern unsigned long tb_last_stamp;
+
+struct rtc_time;
+extern void to_tm(int tim, struct rtc_time * tm);
+extern time_t last_rtc_update;
+
+/*
+ * By putting all of this stuff into a single struct we 
+ * reduce the number of cache lines touched by do_gettimeofday.
+ * Both by collecting all of the data in one cache line and
+ * by touching only one TOC entry
+ */
+struct gettimeofday_vars {
+	unsigned long tb_to_xs;
+	unsigned long stamp_xsec;
+};
+
+struct gettimeofday_struct {
+	unsigned long tb_orig_stamp;
+	unsigned long tb_ticks_per_sec;
+	struct gettimeofday_vars vars[2];
+	struct gettimeofday_vars * volatile varp;
+	unsigned      tb_to_us;
+};
+
+struct div_result {
+	unsigned long result_high;
+	unsigned long result_low;
+};
+
+int via_calibrate_decr(void);
+
+static __inline__ unsigned long get_tb(void)
+{
+	return mftb();
+}
+
+/* Accessor functions for the decrementer register. */
+static __inline__ unsigned int get_dec(void)
+{
+	return (mfspr(SPRN_DEC));
+}
+
+static __inline__ void set_dec(int val)
+{
+    struct Paca * paca;
+    int cur_dec;
+
+    paca = (struct Paca *)mfspr(SPRG3);
+    if ( paca->xLpPaca.xSharedProc ) {
+	paca->xLpPaca.xVirtualDecr = val;
+	cur_dec = get_dec();
+	if ( cur_dec > val )
+	    HvCall_setVirtualDecr();
+    }
+    else
+	mtspr(SPRN_DEC, val);
+}
+
+extern __inline__ unsigned long tb_ticks_since(unsigned long tstamp) {
+    return get_tb() - tstamp;
+}
+
+#define mulhwu(x,y) \
+({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
+#define mulhdu(x,y) \
+({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
+
+
+unsigned mulhwu_scale_factor(unsigned, unsigned);
+void div128_by_32( unsigned long dividend_high, unsigned long dividend_low,
+		   unsigned divisor, struct div_result *dr );
+#endif /* __KERNEL__ */
+#endif /* __PPC64_TIME_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/timex.h linux-2.4.19-pre5/include/asm-ppc64/timex.h
--- linux-2.4.19-pre4/include/asm-ppc64/timex.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/timex.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,31 @@
+/*
+ * linux/include/asm-ppc/timex.h
+ *
+ * PPC64 architecture timex specifications
+ *
+ * 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.
+ */
+#ifndef _ASMPPC64_TIMEX_H
+#define _ASMPPC64_TIMEX_H
+
+#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
+#define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
+#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
+	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
+		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
+
+typedef unsigned long cycles_t;
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles(void)
+{
+	cycles_t ret;
+
+	__asm__ __volatile__("mftb %0" : "=r" (ret) : );
+	return ret;
+}
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/tlb.h linux-2.4.19-pre5/include/asm-ppc64/tlb.h
--- linux-2.4.19-pre4/include/asm-ppc64/tlb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/tlb.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN linux-2.4.19-pre4/include/asm-ppc64/types.h linux-2.4.19-pre5/include/asm-ppc64/types.h
--- linux-2.4.19-pre4/include/asm-ppc64/types.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/types.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,69 @@
+#ifndef _PPC64_TYPES_H
+#define _PPC64_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+typedef unsigned int umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+typedef __signed__ long __s64;
+typedef unsigned long __u64;
+
+typedef struct {
+	__u32 u[4];
+} __attribute((aligned(16))) __vector128;
+
+#ifdef __KERNEL__
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long s64;
+typedef unsigned long u64;
+
+typedef __vector128 vector128;
+
+#define BITS_PER_LONG 64
+
+/* PCI dma addresses are 32-bits wide.  Ignore PCI64 for now, since
+   we'll typically be sending it all through iommu tables anyway.  */
+typedef u32 dma_addr_t;
+
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+
+#endif /* _PPC64_TYPES_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/uaccess.h linux-2.4.19-pre5/include/asm-ppc64/uaccess.h
--- linux-2.4.19-pre4/include/asm-ppc64/uaccess.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/uaccess.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,285 @@
+#ifndef _PPC64_UACCESS_H
+#define _PPC64_UACCESS_H
+
+/* 
+ * 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.
+ */
+
+#ifndef __ASSEMBLY__
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <asm/processor.h>
+
+#define VERIFY_READ	0
+#define VERIFY_WRITE	1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS	((mm_segment_t) { 0 })
+#define USER_DS		((mm_segment_t) { 1 })
+
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current->thread.fs)
+#define set_fs(val)	(current->thread.fs = (val))
+
+#define segment_eq(a,b)	((a).seg == (b).seg)
+
+#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
+#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
+#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
+#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+	return access_ok(type,addr,size) ? 0 : -EFAULT;
+}
+
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+	unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+extern void sort_exception_table(void);
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ *
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ *
+ * As we use the same address space for kernel and user data on the
+ * PowerPC, we can just do these as direct assignments.  (Of course, the
+ * exception handling means that it's no longer "just"...)
+ */
+#define get_user(x,ptr) \
+  __get_user_check((x),(ptr),sizeof(*(ptr)))
+#define put_user(x,ptr) \
+  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size)			\
+({							\
+	long __pu_err;					\
+	__put_user_size((x),(ptr),(size),__pu_err);	\
+	__pu_err;					\
+})
+
+#define __put_user_check(x,ptr,size)				\
+({								\
+	long __pu_err = -EFAULT;				\
+	__typeof__(*(ptr)) *__pu_addr = (ptr);			\
+	if (access_ok(VERIFY_WRITE,__pu_addr,size))		\
+		__put_user_size((x),__pu_addr,(size),__pu_err);	\
+	__pu_err;						\
+})
+
+#define __put_user_size(x,ptr,size,retval)			\
+do {								\
+	retval = 0;						\
+	switch (size) {						\
+	  case 1: __put_user_asm(x,ptr,retval,"stb"); break;	\
+	  case 2: __put_user_asm(x,ptr,retval,"sth"); break;	\
+	  case 4: __put_user_asm(x,ptr,retval,"stw"); break;	\
+	  case 8: __put_user_asm(x,ptr,retval,"std"); break; 	\
+	  default: __put_user_bad();				\
+	}							\
+} while (0)
+
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, op)			\
+	__asm__ __volatile__(					\
+		"1:	"op" %1,0(%2)\n"			\
+		"2:\n"						\
+		".section .fixup,\"ax\"\n"			\
+		"3:	li %0,%3\n"				\
+		"	b 2b\n"					\
+		".previous\n"					\
+		".section __ex_table,\"a\"\n"			\
+		"	.align 3\n"				\
+		"	.llong 1b,3b\n"				\
+		".previous"					\
+		: "=r"(err)					\
+		: "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size)				\
+({								\
+	long __gu_err, __gu_val;				\
+	__get_user_size(__gu_val,(ptr),(size),__gu_err);	\
+	(x) = (__typeof__(*(ptr)))__gu_val;			\
+	__gu_err;						\
+})
+
+#define __get_user_check(x,ptr,size)					\
+({									\
+	long __gu_err = -EFAULT, __gu_val = 0;				\
+	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
+	if (access_ok(VERIFY_READ,__gu_addr,size))			\
+		__get_user_size(__gu_val,__gu_addr,(size),__gu_err);	\
+	(x) = (__typeof__(*(ptr)))__gu_val;				\
+	__gu_err;							\
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)			\
+do {								\
+	retval = 0;						\
+	switch (size) {						\
+	  case 1: __get_user_asm(x,ptr,retval,"lbz"); break;	\
+	  case 2: __get_user_asm(x,ptr,retval,"lhz"); break;	\
+	  case 4: __get_user_asm(x,ptr,retval,"lwz"); break;	\
+	  case 8: __get_user_asm(x,ptr,retval,"ld");  break;    \
+	  default: (x) = __get_user_bad();			\
+	}							\
+} while (0)
+
+#define __get_user_asm(x, addr, err, op)		\
+	__asm__ __volatile__(				\
+		"1:	"op" %1,0(%2)\n"		\
+		"2:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"3:	li %0,%3\n"			\
+		"	li %1,0\n"			\
+		"	b 2b\n"				\
+		".previous\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 3\n"			\
+		"	.llong 1b,3b\n"			\
+		".previous"				\
+		: "=r"(err), "=r"(x)			\
+		: "b"(addr), "i"(-EFAULT), "0"(err))
+
+/* more complex routines */
+
+extern unsigned long __copy_tofrom_user(void *to, const void *from, unsigned long size);
+
+extern inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+	unsigned long over;
+
+	if (access_ok(VERIFY_READ, from, n))
+		return __copy_tofrom_user(to, from, n);
+	if ((unsigned long)from < TASK_SIZE) {
+		over = (unsigned long)from + n - TASK_SIZE;
+		return __copy_tofrom_user(to, from, n - over) + over;
+	}
+	return n;
+}
+
+extern inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+	unsigned long over;
+
+	if (access_ok(VERIFY_WRITE, to, n))
+		return __copy_tofrom_user(to, from, n);
+	if ((unsigned long)to < TASK_SIZE) {
+		over = (unsigned long)to + n - TASK_SIZE;
+		return __copy_tofrom_user(to, from, n - over) + over;
+	}
+	return n;
+}
+
+#define __copy_from_user(to, from, size) \
+	__copy_tofrom_user((to), (from), (size))
+#define __copy_to_user(to, from, size) \
+	__copy_tofrom_user((to), (from), (size))
+
+extern unsigned long __clear_user(void *addr, unsigned long size);
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+	if (access_ok(VERIFY_WRITE, addr, size))
+		return __clear_user(addr, size);
+	return size? -EFAULT: 0;
+}
+
+extern int __strncpy_from_user(char *dst, const char *src, long count);
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+	if (access_ok(VERIFY_READ, src, 1))
+		return __strncpy_from_user(dst, src, count);
+	return -EFAULT;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+
+extern int __strnlen_user(const char *str, long len, unsigned long top);
+
+/*
+ * Returns the length of the string at str (including the null byte),
+ * or 0 if we hit a page we can't access,
+ * or something > len if we didn't find a null byte.
+ *
+ * The `top' parameter to __strnlen_user is to make sure that
+ * we can never overflow from the user area into kernel space.
+ */
+extern __inline__ int strnlen_user(const char *str, long len)
+{
+	unsigned long top = __kernel_ok? ~0UL: TASK_SIZE - 1;
+
+	if ((unsigned long)str > top)
+		return 0;
+	return __strnlen_user(str, len, top);
+}
+
+#define strlen_user(str)	strnlen_user((str), 0x7ffffffe)
+
+#endif  /* __ASSEMBLY__ */
+
+#endif	/* _PPC64_UACCESS_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/ucontext.h linux-2.4.19-pre5/include/asm-ppc64/ucontext.h
--- linux-2.4.19-pre4/include/asm-ppc64/ucontext.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/ucontext.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,34 @@
+#ifndef _ASMPPC64_UCONTEXT_H
+#define _ASMPPC64_UCONTEXT_H
+
+/* Copied from i386. 
+ *
+ * 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.
+ */
+
+struct ucontext {
+	unsigned long	  uc_flags;
+	struct ucontext  *uc_link;
+	stack_t		  uc_stack;
+	struct sigcontext_struct uc_mcontext;
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+#ifdef __KERNEL__
+
+
+struct ucontext32 { 
+	unsigned int	  uc_flags;
+	unsigned int 	  uc_link;
+	stack_32_t	  uc_stack;
+	struct sigcontext32_struct uc_mcontext;
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+#endif /* __KERNEL__ */
+
+
+#endif /* _ASMPPC64_UCONTEXT_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/udbg.h linux-2.4.19-pre5/include/asm-ppc64/udbg.h
--- linux-2.4.19-pre4/include/asm-ppc64/udbg.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/udbg.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,27 @@
+#ifndef __UDBG_HDR
+#define __UDBG_HDR
+
+/*
+ * c 2001 PPC 64 Team, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+void udbg_init_uart(void *comport);
+void udbg_putc(unsigned char c);
+unsigned char udbg_getc(void);
+int udbg_getc_poll(void);
+void udbg_puts(const char *s);
+int udbg_write(const char *s, int n);
+int udbg_read(char *buf, int buflen);
+void udbg_puthex(unsigned long val);
+void udbg_printSP(const char *s);
+void udbg_printf(const char *fmt, ...);
+void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
+unsigned long udbg_ifdebug(unsigned long flags);
+
+void udbg_init_uart(void *comport);
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/unaligned.h linux-2.4.19-pre5/include/asm-ppc64/unaligned.h
--- linux-2.4.19-pre4/include/asm-ppc64/unaligned.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/unaligned.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,21 @@
+#ifndef __PPC64_UNALIGNED_H
+#define __PPC64_UNALIGNED_H
+
+/*
+ * The PowerPC can do unaligned accesses itself in big endian mode. 
+ *
+ * The strange macros are there to make sure these can't
+ * be misused in a way that makes them not work on other
+ * architectures where unaligned accesses aren't as simple.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define get_unaligned(ptr) (*(ptr))
+
+#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+#endif /* __PPC64_UNALIGNED_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/unistd.h linux-2.4.19-pre5/include/asm-ppc64/unistd.h
--- linux-2.4.19-pre4/include/asm-ppc64/unistd.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/unistd.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,422 @@
+#ifndef _ASM_PPC_UNISTD_H_
+#define _ASM_PPC_UNISTD_H_
+
+/*
+ * This file contains the system call numbers.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define __NR_exit		  1
+#define __NR_fork		  2
+#define __NR_read		  3
+#define __NR_write		  4
+#define __NR_open		  5
+#define __NR_close		  6
+#define __NR_waitpid		  7
+#define __NR_creat		  8
+#define __NR_link		  9
+#define __NR_unlink		 10
+#define __NR_execve		 11
+#define __NR_chdir		 12
+#define __NR_time		 13
+#define __NR_mknod		 14
+#define __NR_chmod		 15
+#define __NR_lchown		 16
+#define __NR_break		 17
+#define __NR_oldstat		 18
+#define __NR_lseek		 19
+#define __NR_getpid		 20
+#define __NR_mount		 21
+#define __NR_umount		 22
+#define __NR_setuid		 23
+#define __NR_getuid		 24
+#define __NR_stime		 25
+#define __NR_ptrace		 26
+#define __NR_alarm		 27
+#define __NR_oldfstat		 28
+#define __NR_pause		 29
+#define __NR_utime		 30
+#define __NR_stty		 31
+#define __NR_gtty		 32
+#define __NR_access		 33
+#define __NR_nice		 34
+#define __NR_ftime		 35
+#define __NR_sync		 36
+#define __NR_kill		 37
+#define __NR_rename		 38
+#define __NR_mkdir		 39
+#define __NR_rmdir		 40
+#define __NR_dup		 41
+#define __NR_pipe		 42
+#define __NR_times		 43
+#define __NR_prof		 44
+#define __NR_brk		 45
+#define __NR_setgid		 46
+#define __NR_getgid		 47
+#define __NR_signal		 48
+#define __NR_geteuid		 49
+#define __NR_getegid		 50
+#define __NR_acct		 51
+#define __NR_umount2		 52
+#define __NR_lock		 53
+#define __NR_ioctl		 54
+#define __NR_fcntl		 55
+#define __NR_mpx		 56
+#define __NR_setpgid		 57
+#define __NR_ulimit		 58
+#define __NR_oldolduname	 59
+#define __NR_umask		 60
+#define __NR_chroot		 61
+#define __NR_ustat		 62
+#define __NR_dup2		 63
+#define __NR_getppid		 64
+#define __NR_getpgrp		 65
+#define __NR_setsid		 66
+#define __NR_sigaction		 67
+#define __NR_sgetmask		 68
+#define __NR_ssetmask		 69
+#define __NR_setreuid		 70
+#define __NR_setregid		 71
+#define __NR_sigsuspend		 72
+#define __NR_sigpending		 73
+#define __NR_sethostname	 74
+#define __NR_setrlimit		 75
+#define __NR_getrlimit		 76
+#define __NR_getrusage		 77
+#define __NR_gettimeofday	 78
+#define __NR_settimeofday	 79
+#define __NR_getgroups		 80
+#define __NR_setgroups		 81
+#define __NR_select		 82
+#define __NR_symlink		 83
+#define __NR_oldlstat		 84
+#define __NR_readlink		 85
+#define __NR_uselib		 86
+#define __NR_swapon		 87
+#define __NR_reboot		 88
+#define __NR_readdir		 89
+#define __NR_mmap		 90
+#define __NR_munmap		 91
+#define __NR_truncate		 92
+#define __NR_ftruncate		 93
+#define __NR_fchmod		 94
+#define __NR_fchown		 95
+#define __NR_getpriority	 96
+#define __NR_setpriority	 97
+#define __NR_profil		 98
+#define __NR_statfs		 99
+#define __NR_fstatfs		100
+#define __NR_ioperm		101
+#define __NR_socketcall		102
+#define __NR_syslog		103
+#define __NR_setitimer		104
+#define __NR_getitimer		105
+#define __NR_stat		106
+#define __NR_lstat		107
+#define __NR_fstat		108
+#define __NR_olduname		109
+#define __NR_iopl		110
+#define __NR_vhangup		111
+#define __NR_idle		112
+#define __NR_vm86		113
+#define __NR_wait4		114
+#define __NR_swapoff		115
+#define __NR_sysinfo		116
+#define __NR_ipc		117
+#define __NR_fsync		118
+#define __NR_sigreturn		119
+#define __NR_clone		120
+#define __NR_setdomainname	121
+#define __NR_uname		122
+#define __NR_modify_ldt		123
+#define __NR_adjtimex		124
+#define __NR_mprotect		125
+#define __NR_sigprocmask	126
+#define __NR_create_module	127
+#define __NR_init_module	128
+#define __NR_delete_module	129
+#define __NR_get_kernel_syms	130
+#define __NR_quotactl		131
+#define __NR_getpgid		132
+#define __NR_fchdir		133
+#define __NR_bdflush		134
+#define __NR_sysfs		135
+#define __NR_personality	136
+#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define __NR_setfsuid		138
+#define __NR_setfsgid		139
+#define __NR__llseek		140
+#define __NR_getdents		141
+#define __NR__newselect		142
+#define __NR_flock		143
+#define __NR_msync		144
+#define __NR_readv		145
+#define __NR_writev		146
+#define __NR_getsid		147
+#define __NR_fdatasync		148
+#define __NR__sysctl		149
+#define __NR_mlock		150
+#define __NR_munlock		151
+#define __NR_mlockall		152
+#define __NR_munlockall		153
+#define __NR_sched_setparam		154
+#define __NR_sched_getparam		155
+#define __NR_sched_setscheduler		156
+#define __NR_sched_getscheduler		157
+#define __NR_sched_yield		158
+#define __NR_sched_get_priority_max	159
+#define __NR_sched_get_priority_min	160
+#define __NR_sched_rr_get_interval	161
+#define __NR_nanosleep		162
+#define __NR_mremap		163
+#define __NR_setresuid		164
+#define __NR_getresuid		165
+#define __NR_query_module	166
+#define __NR_poll		167
+#define __NR_nfsservctl		168
+#define __NR_setresgid		169
+#define __NR_getresgid		170
+#define __NR_prctl		171
+#define __NR_rt_sigreturn	172
+#define __NR_rt_sigaction	173
+#define __NR_rt_sigprocmask	174
+#define __NR_rt_sigpending	175
+#define __NR_rt_sigtimedwait	176
+#define __NR_rt_sigqueueinfo	177
+#define __NR_rt_sigsuspend	178
+#define __NR_pread		179
+#define __NR_pwrite		180
+#define __NR_chown		181
+#define __NR_getcwd		182
+#define __NR_capget		183
+#define __NR_capset		184
+#define __NR_sigaltstack	185
+#define __NR_sendfile		186
+#define __NR_getpmsg		187	/* some people actually want streams */
+#define __NR_putpmsg		188	/* some people actually want streams */
+#define __NR_vfork		189
+#define __NR_ugetrlimit		190	/* SuS compliant getrlimit */
+#define __NR_mmap2		192
+#define __NR_truncate64		193
+#define __NR_ftruncate64	194
+#define __NR_stat64		195
+#define __NR_lstat64		196
+#define __NR_fstat64		197
+#define __NR_pciconfig_read	198
+#define __NR_pciconfig_write	199
+#define __NR_pciconfig_iobase	200
+#define __NR_multiplexer	201
+#define __NR_getdents64		202
+
+#define __NR(n)	#n
+
+
+#define __syscall_return(type) \
+	return (__sc_err & 0x10000000 ? errno = __sc_ret, __sc_ret = -1 : 0), \
+	       (type) __sc_ret
+
+#define __syscall_clobbers \
+	"r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
+
+#define _syscall0(type,name)						\
+type name(void)								\
+{									\
+	unsigned long __sc_ret, __sc_err;				\
+	{								\
+		register unsigned long __sc_0 __asm__ ("r0");		\
+		register unsigned long __sc_3 __asm__ ("r3");		\
+									\
+		__sc_0 = __NR_##name;					\
+		__asm__ __volatile__					\
+			("sc           \n\t"				\
+			 "mfcr %1      "				\
+			: "=&r" (__sc_3), "=&r" (__sc_0)		\
+			: "0"   (__sc_3), "1"   (__sc_0)		\
+			: __syscall_clobbers);				\
+		__sc_ret = __sc_3;					\
+		__sc_err = __sc_0;					\
+	}								\
+	__syscall_return (type);					\
+}
+
+#define _syscall1(type,name,type1,arg1)					\
+type name(type1 arg1)							\
+{									\
+	unsigned long __sc_ret, __sc_err;				\
+	{								\
+		register unsigned long __sc_0 __asm__ ("r0");		\
+		register unsigned long __sc_3 __asm__ ("r3");		\
+									\
+		__sc_3 = (unsigned long) (arg1);			\
+		__sc_0 = __NR_##name;					\
+		__asm__ __volatile__					\
+			("sc           \n\t"				\
+			 "mfcr %1      "				\
+			: "=&r" (__sc_3), "=&r" (__sc_0)		\
+			: "0"   (__sc_3), "1"   (__sc_0)		\
+			: __syscall_clobbers);				\
+		__sc_ret = __sc_3;					\
+		__sc_err = __sc_0;					\
+	}								\
+	__syscall_return (type);					\
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)			\
+type name(type1 arg1, type2 arg2)					\
+{									\
+	unsigned long __sc_ret, __sc_err;				\
+	{								\
+		register unsigned long __sc_0 __asm__ ("r0");		\
+		register unsigned long __sc_3 __asm__ ("r3");		\
+		register unsigned long __sc_4 __asm__ ("r4");		\
+									\
+		__sc_3 = (unsigned long) (arg1);			\
+		__sc_4 = (unsigned long) (arg2);			\
+		__sc_0 = __NR_##name;					\
+		__asm__ __volatile__					\
+			("sc           \n\t"				\
+			 "mfcr %1      "				\
+			: "=&r" (__sc_3), "=&r" (__sc_0)		\
+			: "0"   (__sc_3), "1"   (__sc_0),		\
+			  "r"   (__sc_4)				\
+			: __syscall_clobbers);				\
+		__sc_ret = __sc_3;					\
+		__sc_err = __sc_0;					\
+	}								\
+	__syscall_return (type);					\
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
+type name(type1 arg1, type2 arg2, type3 arg3)				\
+{									\
+	unsigned long __sc_ret, __sc_err;				\
+	{								\
+		register unsigned long __sc_0 __asm__ ("r0");		\
+		register unsigned long __sc_3 __asm__ ("r3");		\
+		register unsigned long __sc_4 __asm__ ("r4");		\
+		register unsigned long __sc_5 __asm__ ("r5");		\
+									\
+		__sc_3 = (unsigned long) (arg1);			\
+		__sc_4 = (unsigned long) (arg2);			\
+		__sc_5 = (unsigned long) (arg3);			\
+		__sc_0 = __NR_##name;					\
+		__asm__ __volatile__					\
+			("sc           \n\t"				\
+			 "mfcr %1      "				\
+			: "=&r" (__sc_3), "=&r" (__sc_0)		\
+			: "0"   (__sc_3), "1"   (__sc_0),		\
+			  "r"   (__sc_4),				\
+			  "r"   (__sc_5)				\
+			: __syscall_clobbers);				\
+		__sc_ret = __sc_3;					\
+		__sc_err = __sc_0;					\
+	}								\
+	__syscall_return (type);					\
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4)		\
+{									\
+	unsigned long __sc_ret, __sc_err;				\
+	{								\
+		register unsigned long __sc_0 __asm__ ("r0");		\
+		register unsigned long __sc_3 __asm__ ("r3");		\
+		register unsigned long __sc_4 __asm__ ("r4");		\
+		register unsigned long __sc_5 __asm__ ("r5");		\
+		register unsigned long __sc_6 __asm__ ("r6");		\
+									\
+		__sc_3 = (unsigned long) (arg1);			\
+		__sc_4 = (unsigned long) (arg2);			\
+		__sc_5 = (unsigned long) (arg3);			\
+		__sc_6 = (unsigned long) (arg4);			\
+		__sc_0 = __NR_##name;					\
+		__asm__ __volatile__					\
+			("sc           \n\t"				\
+			 "mfcr %1      "				\
+			: "=&r" (__sc_3), "=&r" (__sc_0)		\
+			: "0"   (__sc_3), "1"   (__sc_0),		\
+			  "r"   (__sc_4),				\
+			  "r"   (__sc_5),				\
+			  "r"   (__sc_6)				\
+			: __syscall_clobbers);				\
+		__sc_ret = __sc_3;					\
+		__sc_err = __sc_0;					\
+	}								\
+	__syscall_return (type);					\
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)	\
+{									\
+	unsigned long __sc_ret, __sc_err;				\
+	{								\
+		register unsigned long __sc_0 __asm__ ("r0");		\
+		register unsigned long __sc_3 __asm__ ("r3");		\
+		register unsigned long __sc_4 __asm__ ("r4");		\
+		register unsigned long __sc_5 __asm__ ("r5");		\
+		register unsigned long __sc_6 __asm__ ("r6");		\
+		register unsigned long __sc_7 __asm__ ("r7");		\
+									\
+		__sc_3 = (unsigned long) (arg1);			\
+		__sc_4 = (unsigned long) (arg2);			\
+		__sc_5 = (unsigned long) (arg3);			\
+		__sc_6 = (unsigned long) (arg4);			\
+		__sc_7 = (unsigned long) (arg5);			\
+		__sc_0 = __NR_##name;					\
+		__asm__ __volatile__					\
+			("sc           \n\t"				\
+			 "mfcr %1      "				\
+			: "=&r" (__sc_3), "=&r" (__sc_0)		\
+			: "0"   (__sc_3), "1"   (__sc_0),		\
+			  "r"   (__sc_4),				\
+			  "r"   (__sc_5),				\
+			  "r"   (__sc_6),				\
+			  "r"   (__sc_7)				\
+			: __syscall_clobbers);				\
+		__sc_ret = __sc_3;					\
+		__sc_err = __sc_0;					\
+	}								\
+	__syscall_return (type);					\
+}
+
+
+#ifdef __KERNEL_SYSCALLS__
+
+/*
+ * Forking from kernel space will result in the child getting a new,
+ * empty kernel stack area.  Thus the child cannot access automatic
+ * variables set in the parent unless they are in registers, and the
+ * procedure where the fork was done cannot return to its caller in
+ * the child.
+ */
+
+/*
+ * System call prototypes.
+ */
+#define __NR__exit __NR_exit
+static inline _syscall0(int,pause)
+static inline _syscall0(int,sync)
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+static inline _syscall1(int,dup,int,fd)
+static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+static inline _syscall1(int,close,int,fd)
+static inline _syscall1(int,_exit,int,exitcode)
+static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+static inline _syscall1(int,delete_module,const char *,name)
+
+static inline pid_t wait(int * wait_stat) 
+{
+	return waitpid(-1,wait_stat,0);
+}
+
+#endif /* __KERNEL_SYSCALLS__ */
+
+#endif /* _ASM_PPC_UNISTD_H_ */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/user.h linux-2.4.19-pre5/include/asm-ppc64/user.h
--- linux-2.4.19-pre4/include/asm-ppc64/user.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/user.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,58 @@
+#ifndef _PPC_USER_H
+#define _PPC_USER_H
+
+/* Adapted from <asm-alpha/user.h> 
+ *
+ * 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/ptrace.h>
+#include <asm/page.h>
+
+/*
+ * Core file format: The core file is written in such a way that gdb
+ * can understand it and provide useful information to the user (under
+ * linux we use the `trad-core' bfd, NOT the osf-core).  The file contents
+ * are as follows:
+ *
+ *  upage: 1 page consisting of a user struct that tells gdb
+ *	what is present in the file.  Directly after this is a
+ *	copy of the task_struct, which is currently not used by gdb,
+ *	but it may come in handy at some point.  All of the registers
+ *	are stored as part of the upage.  The upage should always be
+ *	only one page long.
+ *  data: The data segment follows next.  We use current->end_text to
+ *	current->brk to pick up all of the user variables, plus any memory
+ *	that may have been sbrk'ed.  No attempt is made to determine if a
+ *	page is demand-zero or if a page is totally unused, we just cover
+ *	the entire range.  All of the addresses are rounded in such a way
+ *	that an integral number of pages is written.
+ *  stack: We need the stack information in order to get a meaningful
+ *	backtrace.  We need to write the data from usp to
+ *	current->start_stack, so we round each of these in order to be able
+ *	to write an integer number of pages.
+ */
+struct user {
+	struct pt_regs	regs;			/* entire machine state */
+	size_t		u_tsize;		/* text size (pages) */
+	size_t		u_dsize;		/* data size (pages) */
+	size_t		u_ssize;		/* stack size (pages) */
+	unsigned long	start_code;		/* text starting address */
+	unsigned long	start_data;		/* data starting address */
+	unsigned long	start_stack;		/* stack starting address */
+	long int	signal;			/* signal causing core dump */
+	struct regs *	u_ar0;			/* help gdb find registers */
+	unsigned long	magic;			/* identifies a core file */
+	char		u_comm[32];		/* user command name */
+};
+
+#define NBPG			PAGE_SIZE
+#define UPAGES			1
+#define HOST_TEXT_START_ADDR	(u.start_code)
+#define HOST_DATA_START_ADDR	(u.start_data)
+#define HOST_STACK_END_ADDR	(u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _PPC_USER_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/vc_ioctl.h linux-2.4.19-pre5/include/asm-ppc64/vc_ioctl.h
--- linux-2.4.19-pre4/include/asm-ppc64/vc_ioctl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/vc_ioctl.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,50 @@
+#ifndef _LINUX_VC_IOCTL_H
+#define _LINUX_VC_IOCTL_H
+
+/*
+ * 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.
+ */
+
+struct vc_mode {
+	int	height;
+	int	width;
+	int	depth;
+	int	pitch;
+	int	mode;
+	char	name[32];
+	unsigned long fb_address;
+	unsigned long cmap_adr_address;
+	unsigned long cmap_data_address;
+	unsigned long disp_reg_address;
+};
+
+#define VC_GETMODE	0x7667
+#define VC_SETMODE	0x7668
+#define VC_INQMODE	0x7669
+
+#define VC_SETCMAP      0x766a
+#define VC_GETCMAP      0x766b
+
+#define VC_POWERMODE	0x766c
+
+/* Values for the argument to the VC_POWERMODE ioctl */
+#define VC_POWERMODE_INQUIRY	(-1)
+#define VESA_NO_BLANKING	0
+#define VESA_VSYNC_SUSPEND	1
+#define VESA_HSYNC_SUSPEND	2
+#define VESA_POWERDOWN		3
+
+#ifdef __KERNEL__
+extern int console_getmode(struct vc_mode *);
+extern int console_setmode(struct vc_mode *, int);
+extern int console_setcmap(int, unsigned char *, unsigned char *,
+			   unsigned char *);
+extern int console_powermode(int);
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#endif
+
+#endif /* _LINUX_VC_IOCTL_H */
diff -urN linux-2.4.19-pre4/include/asm-ppc64/vga.h linux-2.4.19-pre5/include/asm-ppc64/vga.h
--- linux-2.4.19-pre4/include/asm-ppc64/vga.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/vga.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,50 @@
+/*
+ *	Access to VGA videoram
+ *
+ *	(c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_ASM_VGA_H_
+#define _LINUX_ASM_VGA_H_
+
+#include <asm/io.h>
+
+#include <linux/config.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE)
+
+#define VT_BUF_HAVE_RW
+/*
+ *  These are only needed for supporting VGA or MDA text mode, which use little
+ *  endian byte ordering.
+ *  In other cases, we can optimize by using native byte ordering and
+ *  <linux/vt_buffer.h> has already done the right job for us.
+ */
+
+extern inline void scr_writew(u16 val, volatile u16 *addr)
+{
+    st_le16(addr, val);
+}
+
+extern inline u16 scr_readw(volatile const u16 *addr)
+{
+    return ld_le16(addr);
+}
+
+#define VT_BUF_HAVE_MEMCPYW
+#define scr_memcpyw	memcpy
+
+#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */
+
+extern unsigned long vgacon_remap_base;
+#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0))
+
+#define vga_readb(x) (*(x))
+#define vga_writeb(x,y) (*(y) = (x))
+
+#endif
diff -urN linux-2.4.19-pre4/include/asm-ppc64/xor.h linux-2.4.19-pre5/include/asm-ppc64/xor.h
--- linux-2.4.19-pre4/include/asm-ppc64/xor.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/asm-ppc64/xor.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff -urN linux-2.4.19-pre4/include/asm-sparc/checksum.h linux-2.4.19-pre5/include/asm-sparc/checksum.h
--- linux-2.4.19-pre4/include/asm-sparc/checksum.h	Tue Oct 30 15:08:11 2001
+++ linux-2.4.19-pre5/include/asm-sparc/checksum.h	Fri Mar 29 14:50:08 2002
@@ -16,6 +16,7 @@
  *      RFC1071 Computing the Internet Checksum
  */
  
+#include <linux/in6.h>
 #include <asm/uaccess.h>
 #include <asm/cprefix.h>
 
diff -urN linux-2.4.19-pre4/include/asm-sparc/pgtable.h linux-2.4.19-pre5/include/asm-sparc/pgtable.h
--- linux-2.4.19-pre4/include/asm-sparc/pgtable.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/asm-sparc/pgtable.h	Fri Mar 29 14:50:08 2002
@@ -293,6 +293,9 @@
 #define page_pte_prot(page, prot)	mk_pte(page, prot)
 #define page_pte(page)			page_pte_prot(page, __pgprot(0))
 
+/* Permanent address of a page. */
+#define page_address(page)  ((page)->virtual)
+
 BTFIXUPDEF_CALL(struct page *, pte_page, pte_t)
 #define pte_page(pte) BTFIXUP_CALL(pte_page)(pte)
 
diff -urN linux-2.4.19-pre4/include/asm-sparc64/pgalloc.h linux-2.4.19-pre5/include/asm-sparc64/pgalloc.h
--- linux-2.4.19-pre4/include/asm-sparc64/pgalloc.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre5/include/asm-sparc64/pgalloc.h	Fri Mar 29 14:50:08 2002
@@ -100,13 +100,6 @@
 
 #endif /* ! CONFIG_SMP */
 
-#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start,
 					  unsigned long end)
 {
@@ -128,8 +121,6 @@
 			vpte_base + (s >> (PAGE_SHIFT - 3)),
 			vpte_base + (e >> (PAGE_SHIFT - 3)));
 }
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
 
 /* Page table allocation/freeing. */
 #ifdef CONFIG_SMP
diff -urN linux-2.4.19-pre4/include/asm-sparc64/processor.h linux-2.4.19-pre5/include/asm-sparc64/processor.h
--- linux-2.4.19-pre4/include/asm-sparc64/processor.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre5/include/asm-sparc64/processor.h	Fri Mar 29 14:50:08 2002
@@ -39,9 +39,25 @@
  * address that the kernel will allocate out.
  */
 #define VA_BITS		44
+#ifndef __ASSEMBLY__
 #define VPTE_SIZE	(1UL << (VA_BITS - PAGE_SHIFT + 3))
+#else
+#define VPTE_SIZE	(1 << (VA_BITS - PAGE_SHIFT + 3))
+#endif
 #define TASK_SIZE	((unsigned long)-VPTE_SIZE)
 
+/*
+ * The vpte base must be able to hold the entire vpte, half
+ * of which lives above, and half below, the base. And it
+ * is placed as close to the highest address range as possible.
+ */
+#define VPTE_BASE_SPITFIRE	(-(VPTE_SIZE/2))
+#if 1
+#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
+#else
+#define VPTE_BASE_CHEETAH	0xffe0000000000000
+#endif
+
 #ifndef __ASSEMBLY__
 
 #define NSWINS		7
diff -urN linux-2.4.19-pre4/include/linux/blkdev.h linux-2.4.19-pre5/include/linux/blkdev.h
--- linux-2.4.19-pre4/include/linux/blkdev.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/blkdev.h	Fri Mar 29 14:50:08 2002
@@ -79,6 +79,16 @@
 	struct request_list	rq[2];
 
 	/*
+	 * The total number of requests on each queue
+	 */
+	int nr_requests;
+
+	/*
+	 * Batching threshold for sleep/wakeup decisions
+	 */
+	int batch_requests;
+
+	/*
 	 * Together with queue_head for cacheline sharing
 	 */
 	struct list_head	queue_head;
@@ -157,6 +167,7 @@
 /*
  * Access functions for manipulating queue properties
  */
+extern int blk_grow_request_list(request_queue_t *q, int nr_requests);
 extern void blk_init_queue(request_queue_t *, request_fn_proc *);
 extern void blk_cleanup_queue(request_queue_t *);
 extern void blk_queue_headactive(request_queue_t *, int);
diff -urN linux-2.4.19-pre4/include/linux/coda_linux.h linux-2.4.19-pre5/include/linux/coda_linux.h
--- linux-2.4.19-pre4/include/linux/coda_linux.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre5/include/linux/coda_linux.h	Fri Mar 29 14:50:08 2002
@@ -54,7 +54,6 @@
 static __inline__ char *coda_i2s(struct inode *);
 static __inline__ void coda_flag_inode(struct inode *, int flag);
 char *coda_f2s(ViceFid *f);
-char *coda_f2s2(ViceFid *f);
 int coda_isroot(struct inode *i);
 int coda_iscontrol(const char *name, size_t length);
 
diff -urN linux-2.4.19-pre4/include/linux/devfs_fs_kernel.h linux-2.4.19-pre5/include/linux/devfs_fs_kernel.h
--- linux-2.4.19-pre4/include/linux/devfs_fs_kernel.h	Fri Dec 21 09:42:03 2001
+++ linux-2.4.19-pre5/include/linux/devfs_fs_kernel.h	Fri Mar 29 14:50:08 2002
@@ -46,14 +46,6 @@
 
 typedef struct devfs_entry * devfs_handle_t;
 
-
-#ifdef CONFIG_BLK_DEV_INITRD
-#  define ROOT_DEVICE_NAME ((real_root_dev ==ROOT_DEV) ? root_device_name:NULL)
-#else
-#  define ROOT_DEVICE_NAME root_device_name
-#endif
-
-
 #ifdef CONFIG_DEVFS_FS
 
 struct unique_numspace
diff -urN linux-2.4.19-pre4/include/linux/ext2_fs_i.h linux-2.4.19-pre5/include/linux/ext2_fs_i.h
--- linux-2.4.19-pre4/include/linux/ext2_fs_i.h	Mon Sep 17 13:16:30 2001
+++ linux-2.4.19-pre5/include/linux/ext2_fs_i.h	Fri Mar 29 14:50:08 2002
@@ -25,7 +25,6 @@
 	__u32	i_faddr;
 	__u8	i_frag_no;
 	__u8	i_frag_size;
-	__u16	i_osync;
 	__u32	i_file_acl;
 	__u32	i_dir_acl;
 	__u32	i_dtime;
diff -urN linux-2.4.19-pre4/include/linux/file.h linux-2.4.19-pre5/include/linux/file.h
--- linux-2.4.19-pre4/include/linux/file.h	Wed Aug 23 11:22:26 2000
+++ linux-2.4.19-pre5/include/linux/file.h	Fri Mar 29 14:50:08 2002
@@ -71,30 +71,7 @@
 	write_unlock(&files->file_lock);
 }
 
-/*
- * Install a file pointer in the fd array.  
- *
- * The VFS is full of places where we drop the files lock between
- * setting the open_fds bitmap and installing the file in the file
- * array.  At any such point, we are vulnerable to a dup2() race
- * installing a file in the array before us.  We need to detect this and
- * fput() the struct file we are about to overwrite in this case.
- *
- * It should never happen - if we allow dup2() do it, _really_ bad things
- * will follow.
- */
-
-static inline void fd_install(unsigned int fd, struct file * file)
-{
-	struct files_struct *files = current->files;
-	
-	write_lock(&files->file_lock);
-	if (files->fd[fd])
-		BUG();
-	files->fd[fd] = file;
-	write_unlock(&files->file_lock);
-}
-
+void fd_install(unsigned int fd, struct file * file);
 void put_files_struct(struct files_struct *fs);
 
 #endif /* __LINUX_FILE_H */
diff -urN linux-2.4.19-pre4/include/linux/fs.h linux-2.4.19-pre5/include/linux/fs.h
--- linux-2.4.19-pre4/include/linux/fs.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/fs.h	Fri Mar 29 14:50:08 2002
@@ -217,7 +217,7 @@
 	BH_New,		/* 1 if the buffer is new and not yet written out */
 	BH_Async,	/* 1 if the buffer is under end_buffer_io_async I/O */
 	BH_Wait_IO,	/* 1 if we should write out this buffer */
-	BH_launder,	/* 1 if we should throttle on this buffer */
+	BH_Launder,	/* 1 if we can throttle on this buffer */
 	BH_JBD,		/* 1 if it has an attached journal_head */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
@@ -279,6 +279,7 @@
 #define buffer_mapped(bh)	__buffer_state(bh,Mapped)
 #define buffer_new(bh)		__buffer_state(bh,New)
 #define buffer_async(bh)	__buffer_state(bh,Async)
+#define buffer_launder(bh)	__buffer_state(bh,Launder)
 
 #define bh_offset(bh)		((unsigned long)(bh)->b_data & ~PAGE_MASK)
 
@@ -1110,7 +1111,7 @@
 
 extern int fs_may_remount_ro(struct super_block *);
 
-extern int try_to_free_buffers(struct page *, unsigned int);
+extern int FASTCALL(try_to_free_buffers(struct page *, unsigned int));
 extern void refile_buffer(struct buffer_head * buf);
 extern void create_empty_buffers(struct page *, kdev_t, unsigned long);
 extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
diff -urN linux-2.4.19-pre4/include/linux/if_bonding.h linux-2.4.19-pre5/include/linux/if_bonding.h
--- linux-2.4.19-pre4/include/linux/if_bonding.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre5/include/linux/if_bonding.h	Fri Mar 29 14:50:08 2002
@@ -51,7 +51,7 @@
 #define BOND_STATE_ACTIVE       0   /* link is active */
 #define BOND_STATE_BACKUP       1   /* link is backup */
 
-#define MAX_BONDS               1   /* Maximum number of devices to support */
+#define BOND_DEFAULT_MAX_BONDS  1   /* Default maximum number of devices to support */
 
 typedef struct ifbond {
 	__s32 bond_mode;
@@ -76,6 +76,7 @@
 	short  delay;
 	char   link;    /* one of BOND_LINK_XXXX */
 	char   state;   /* one of BOND_STATE_XXXX */
+	unsigned short original_flags;
 	u32 link_failure_count;
 } slave_t;
 
diff -urN linux-2.4.19-pre4/include/linux/inetdevice.h linux-2.4.19-pre5/include/linux/inetdevice.h
--- linux-2.4.19-pre4/include/linux/inetdevice.h	Thu Jul 26 13:52:39 2001
+++ linux-2.4.19-pre5/include/linux/inetdevice.h	Fri Mar 29 14:50:08 2002
@@ -18,6 +18,7 @@
 	int	mc_forwarding;
 	int	tag;
 	int     arp_filter;
+	int	medium_id;
 	void	*sysctl;
 };
 
@@ -48,6 +49,7 @@
 #define IN_DEV_TX_REDIRECTS(in_dev)	(ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
 #define IN_DEV_SEC_REDIRECTS(in_dev)	(ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
 #define IN_DEV_IDTAG(in_dev)		((in_dev)->cnf.tag)
+#define IN_DEV_MEDIUM_ID(in_dev)	((in_dev)->cnf.medium_id)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff -urN linux-2.4.19-pre4/include/linux/kernel.h linux-2.4.19-pre5/include/linux/kernel.h
--- linux-2.4.19-pre4/include/linux/kernel.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre5/include/linux/kernel.h	Fri Mar 29 14:50:08 2002
@@ -11,6 +11,7 @@
 #include <linux/linkage.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
+#include <linux/compiler.h>
 
 /* Optimization barrier */
 /* The "volatile" is due to gcc bugs */
@@ -161,6 +162,8 @@
 #define max_t(type,x,y) \
 	({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
 
+extern void out_of_line_bug(void) ATTRIB_NORET;
+
 #endif /* __KERNEL__ */
 
 #define SI_LOAD_SHIFT	16
diff -urN linux-2.4.19-pre4/include/linux/miscdevice.h linux-2.4.19-pre5/include/linux/miscdevice.h
--- linux-2.4.19-pre4/include/linux/miscdevice.h	Thu Nov 22 11:47:07 2001
+++ linux-2.4.19-pre5/include/linux/miscdevice.h	Fri Mar 29 14:50:08 2002
@@ -13,6 +13,7 @@
 #define APOLLO_MOUSE_MINOR 7
 #define PC110PAD_MINOR 9
 #define ADB_MOUSE_MINOR 10
+#define MK712_MINOR 15			/* MK712 touch screen */
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
 #define RTC_MINOR 135
diff -urN linux-2.4.19-pre4/include/linux/mtd/concat.h linux-2.4.19-pre5/include/linux/mtd/concat.h
--- linux-2.4.19-pre4/include/linux/mtd/concat.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/linux/mtd/concat.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,23 @@
+/*
+ * MTD device concatenation layer definitions
+ *
+ * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
+ *
+ * This code is GPL
+ *
+ * $Id: concat.h,v 1.1 2002/03/08 16:34:36 rkaiser Exp $
+ */
+
+#ifndef MTD_CONCAT_H
+#define MTD_CONCAT_H
+
+
+struct mtd_info *mtd_concat_create(
+    struct mtd_info *subdev[],  /* subdevices to concatenate */
+    int num_devs,               /* number of subdevices      */
+    char *name);                /* name for the new device   */
+
+void mtd_concat_destroy(struct mtd_info *mtd);
+
+#endif
+
diff -urN linux-2.4.19-pre4/include/linux/mtd/partitions.h linux-2.4.19-pre5/include/linux/mtd/partitions.h
--- linux-2.4.19-pre4/include/linux/mtd/partitions.h	Tue Jun 12 10:30:27 2001
+++ linux-2.4.19-pre5/include/linux/mtd/partitions.h	Fri Mar 29 14:50:08 2002
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: partitions.h,v 1.6 2001/03/17 17:10:21 dwmw2 Exp $
+ * $Id: partitions.h,v 1.8 2002/03/08 16:34:36 rkaiser Exp $
  */
 
 #ifndef MTD_PARTITIONS_H
@@ -26,14 +26,14 @@
  * 	will extend to the end of the master MTD device.
  * offset: absolute starting position within the master MTD device; if 
  * 	defined as MTDPART_OFS_APPEND, the partition will start where the 
- * 	previous one ended.
+ * 	previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block.
  * mask_flags: contains flags that have to be masked (removed) from the 
  * 	master MTD flag set for the corresponding MTD partition.
  * 	For example, to force a read-only partition, simply adding 
  * 	MTD_WRITEABLE to the mask_flags will do the trick.
  *
  * Note: writeable partitions require their size and offset be 
- * erasesize aligned.
+ * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
  */ 
 
 struct mtd_partition {
@@ -41,8 +41,10 @@
 	u_int32_t size;		/* partition size */
 	u_int32_t offset;		/* offset within the master MTD space */
 	u_int32_t mask_flags;	/* master MTD flags to mask out for this partition */
+	struct mtd_info **mtdp;	/* pointer to store the MTD object */
 };
 
+#define MTDPART_OFS_NXTBLK	(-2)
 #define MTDPART_OFS_APPEND	(-1)
 #define MTDPART_SIZ_FULL	(0)
 
diff -urN linux-2.4.19-pre4/include/linux/netdevice.h linux-2.4.19-pre5/include/linux/netdevice.h
--- linux-2.4.19-pre4/include/linux/netdevice.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/netdevice.h	Fri Mar 29 14:50:08 2002
@@ -279,6 +279,10 @@
 	struct net_device_stats* (*get_stats)(struct net_device *dev);
 	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
 
+	/* List of functions to handle Wireless Extensions (instead of ioctl).
+	 * See <net/iw_handler.h> for details. Jean II */
+	struct iw_handler_def *	wireless_handlers;
+
 	/*
 	 * This marks the end of the "visible" part of the structure. All
 	 * fields hereafter are internal to the system, and may change at
diff -urN linux-2.4.19-pre4/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.4.19-pre5/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- linux-2.4.19-pre4/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Fri Apr 27 14:15:01 2001
+++ linux-2.4.19-pre5/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Fri Mar 29 14:50:08 2002
@@ -42,6 +42,9 @@
 	int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,
 		   size_t len);
 
+	/* Called when a conntrack entry is destroyed */
+	void (*destroy)(struct ip_conntrack *conntrack);
+
 	/* Module (if any) which this is connected to. */
 	struct module *me;
 };
diff -urN linux-2.4.19-pre4/include/linux/nfs_fs.h linux-2.4.19-pre5/include/linux/nfs_fs.h
--- linux-2.4.19-pre4/include/linux/nfs_fs.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/nfs_fs.h	Fri Mar 29 14:50:08 2002
@@ -171,7 +171,7 @@
 		cred = (struct rpc_cred *)file->private_data;
 #ifdef RPC_DEBUG
 	if (cred && cred->cr_magic != RPCAUTH_CRED_MAGIC)
-		BUG();
+		out_of_line_bug();
 #endif
 	return cred;
 }
diff -urN linux-2.4.19-pre4/include/linux/pagemap.h linux-2.4.19-pre5/include/linux/pagemap.h
--- linux-2.4.19-pre4/include/linux/pagemap.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/pagemap.h	Mon Feb 25 11:38:13 2002
@@ -97,8 +97,6 @@
 		___wait_on_page(page);
 }
 
-extern void wake_up_page(struct page *);
-
 extern struct page * grab_cache_page (struct address_space *, unsigned long);
 extern struct page * grab_cache_page_nowait (struct address_space *, unsigned long);
 
diff -urN linux-2.4.19-pre4/include/linux/pci.h linux-2.4.19-pre5/include/linux/pci.h
--- linux-2.4.19-pre4/include/linux/pci.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/pci.h	Fri Mar 29 14:50:08 2002
@@ -376,7 +376,7 @@
 	struct resource dma_resource[DEVICE_COUNT_DMA];
 	struct resource irq_resource[DEVICE_COUNT_IRQ];
 
-	char		name[80];	/* device name */
+	char		name[90];	/* device name */
 	char		slot_name[8];	/* slot name */
 	int		active;		/* ISAPnP: device is active */
 	int		ro;		/* ISAPnP: read only */
diff -urN linux-2.4.19-pre4/include/linux/pci_ids.h linux-2.4.19-pre5/include/linux/pci_ids.h
--- linux-2.4.19-pre4/include/linux/pci_ids.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/pci_ids.h	Fri Mar 29 14:50:08 2002
@@ -604,6 +604,7 @@
 #define PCI_DEVICE_ID_PROMISE_20268R	0x6268
 #define PCI_DEVICE_ID_PROMISE_20269	0x4d69
 #define PCI_DEVICE_ID_PROMISE_20275	0x1275
+#define PCI_DEVICE_ID_PROMISE_20276	0x5275
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
 
 #define PCI_VENDOR_ID_N9		0x105d
@@ -957,11 +958,12 @@
 #define PCI_DEVICE_ID_VIA_8233_7	0x3065
 #define PCI_DEVICE_ID_VIA_82C686_6	0x3068
 #define PCI_DEVICE_ID_VIA_8233_0	0x3074
+#define PCI_DEVICE_ID_VIA_8633_0	0x3091
+#define PCI_DEVICE_ID_VIA_8367_0	0x3099
 #define PCI_DEVICE_ID_VIA_8622		0x3102
 #define PCI_DEVICE_ID_VIA_8233C_0	0x3109
 #define PCI_DEVICE_ID_VIA_8361		0x3112
-#define PCI_DEVICE_ID_VIA_8633_0	0x3091
-#define PCI_DEVICE_ID_VIA_8367_0	0x3099
+#define PCI_DEVICE_ID_VIA_8233A		0x3147
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
 #define PCI_DEVICE_ID_VIA_8231		0x8231
 #define PCI_DEVICE_ID_VIA_8231_4	0x8235
@@ -971,7 +973,7 @@
 #define PCI_DEVICE_ID_VIA_82C597_1	0x8597
 #define PCI_DEVICE_ID_VIA_82C598_1	0x8598
 #define PCI_DEVICE_ID_VIA_8601_1	0x8601
-#define PCI_DEVICE_ID_VIA_8505_1	0X8605
+#define PCI_DEVICE_ID_VIA_8505_1	0x8605
 #define PCI_DEVICE_ID_VIA_8633_1	0xB091
 #define PCI_DEVICE_ID_VIA_8367_1	0xB099
 
@@ -1292,6 +1294,7 @@
 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
 #define PCI_DEVICE_ID_ITE_8872		0x8872
 
+#define PCI_DEVICE_ID_ITE_IT8330G_0    0xe886
 
 /* formerly Platform Tech */
 #define PCI_VENDOR_ID_ESS_OLD		0x1285
diff -urN linux-2.4.19-pre4/include/linux/proc_fs.h linux-2.4.19-pre5/include/linux/proc_fs.h
--- linux-2.4.19-pre4/include/linux/proc_fs.h	Thu Nov 22 11:46:23 2001
+++ linux-2.4.19-pre5/include/linux/proc_fs.h	Fri Mar 29 14:50:08 2002
@@ -132,6 +132,12 @@
  */
 extern void proc_rtas_init(void);
 
+/*
+ * PPC64
+ */ 
+extern void proc_ppc64_init(void);
+extern void iSeries_proc_create(void);
+
 extern struct proc_dir_entry *proc_symlink(const char *,
 		struct proc_dir_entry *, const char *);
 extern struct proc_dir_entry *proc_mknod(const char *,mode_t,
diff -urN linux-2.4.19-pre4/include/linux/skbuff.h linux-2.4.19-pre5/include/linux/skbuff.h
--- linux-2.4.19-pre4/include/linux/skbuff.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/skbuff.h	Fri Mar 29 14:50:08 2002
@@ -756,9 +756,9 @@
 	return skb->len - skb->data_len;
 }
 
-#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) BUG(); } while (0)
-#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) BUG(); } while (0)
-#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) BUG(); } while (0)
+#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) out_of_line_bug(); } while (0)
+#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) out_of_line_bug(); } while (0)
+#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) out_of_line_bug(); } while (0)
 
 /*
  *	Add data to an sk_buff
@@ -1094,7 +1094,7 @@
 {
 #ifdef CONFIG_HIGHMEM
 	if (in_irq())
-		BUG();
+		out_of_line_bug();
 
 	local_bh_disable();
 #endif
diff -urN linux-2.4.19-pre4/include/linux/sysctl.h linux-2.4.19-pre5/include/linux/sysctl.h
--- linux-2.4.19-pre4/include/linux/sysctl.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/sysctl.h	Fri Mar 29 14:50:08 2002
@@ -290,7 +290,8 @@
 	NET_TCP_ADV_WIN_SCALE=87,
 	NET_IPV4_NONLOCAL_BIND=88,
 	NET_IPV4_ICMP_RATELIMIT=89,
-	NET_IPV4_ICMP_RATEMASK=90
+	NET_IPV4_ICMP_RATEMASK=90,
+	NET_TCP_TW_REUSE=91
 };
 
 enum {
@@ -335,7 +336,8 @@
 	NET_IPV4_CONF_BOOTP_RELAY=10,
 	NET_IPV4_CONF_LOG_MARTIANS=11,
 	NET_IPV4_CONF_TAG=12,
-	NET_IPV4_CONF_ARPFILTER=13
+	NET_IPV4_CONF_ARPFILTER=13,
+	NET_IPV4_CONF_MEDIUM_ID=14,
 };
 
 /* /proc/sys/net/ipv6 */
diff -urN linux-2.4.19-pre4/include/linux/udf_fs.h linux-2.4.19-pre5/include/linux/udf_fs.h
--- linux-2.4.19-pre4/include/linux/udf_fs.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/linux/udf_fs.h	Fri Mar 29 14:50:08 2002
@@ -30,6 +30,7 @@
  * HISTORY
  *
  */
+#include <linux/config.h>
 
 #ifndef _UDF_FS_H
 #define _UDF_FS_H 1
diff -urN linux-2.4.19-pre4/include/linux/wireless.h linux-2.4.19-pre5/include/linux/wireless.h
--- linux-2.4.19-pre4/include/linux/wireless.h	Thu Nov 22 11:47:12 2001
+++ linux-2.4.19-pre5/include/linux/wireless.h	Fri Mar 29 14:50:08 2002
@@ -1,9 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	12	5.10.01
+ * Version :	13	6.12.01
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -11,6 +12,8 @@
 
 /************************** DOCUMENTATION **************************/
 /*
+ * Initial APIs (1996 -> onward) :
+ * -----------------------------
  * Basically, the wireless extensions are for now a set of standard ioctl
  * call + /proc/net/wireless
  *
@@ -27,16 +30,27 @@
  * We have the list of command plus a structure descibing the
  * data exchanged...
  * Note that to add these ioctl, I was obliged to modify :
- *	net/core/dev.c (two place + add include)
- *	net/ipv4/af_inet.c (one place + add include)
+ *	# net/core/dev.c (two place + add include)
+ *	# net/ipv4/af_inet.c (one place + add include)
  *
  * /proc/net/wireless is a copy of /proc/net/dev.
  * We have a structure for data passed from the driver to /proc/net/wireless
  * Too add this, I've modified :
- *	net/core/dev.c (two other places)
- *	include/linux/netdevice.h (one place)
- *	include/linux/proc_fs.h (one place)
+ *	# net/core/dev.c (two other places)
+ *	# include/linux/netdevice.h (one place)
+ *	# include/linux/proc_fs.h (one place)
+ *
+ * New driver API (2001 -> onward) :
+ * -------------------------------
+ * This file is only concerned with the user space API and common definitions.
+ * The new driver API is defined and documented in :
+ *	# include/net/iw_handler.h
  *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+ *	# include/linux/wireless.c
+ *
+ * Other comments :
+ * --------------
  * Do not add here things that are redundant with other mechanisms
  * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
  * wireless specific.
@@ -54,16 +68,14 @@
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 #include <linux/if.h>			/* for IFNAMSIZ and co... */
 
-/**************************** CONSTANTS ****************************/
-
-/* --------------------------- VERSION --------------------------- */
+/***************************** VERSION *****************************/
 /*
  * This constant is used to know the availability of the wireless
  * extensions and to know which version of wireless extensions it is
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	12
+#define WIRELESS_EXT	13
 
 /*
  * Changes :
@@ -123,12 +135,20 @@
  *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
  *	- Add new statistics (frag, retry, beacon)
  *	- Add average quality (for user space calibration)
+ *
+ * V12 to V13
+ * ----------
+ *	- Document creation of new driver API.
+ *	- Extract union iwreq_data from struct iwreq (for new driver API).
+ *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
  */
 
+/**************************** CONSTANTS ****************************/
+
 /* -------------------------- IOCTL LIST -------------------------- */
 
 /* Basic operations */
-#define SIOCSIWNAME	0x8B00		/* Unused */
+#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
 #define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
 #define SIOCGIWNWID	0x8B03		/* get network id */
@@ -414,13 +434,49 @@
 
 /* ------------------------ IOCTL REQUEST ------------------------ */
 /*
+ * This structure defines the payload of an ioctl, and is used 
+ * below.
+ *
+ * Note that this structure should fit on the memory footprint
+ * of iwreq (which is the same as ifreq), which mean a max size of
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * You should check this when increasing the structures defined
+ * above in this file...
+ */
+union	iwreq_data
+{
+	/* Config - generic */
+	char		name[IFNAMSIZ];
+	/* Name : used to verify the presence of  wireless extensions.
+	 * Name of the protocol/provider... */
+
+	struct iw_point	essid;		/* Extended network name */
+	struct iw_param	nwid;		/* network id (or domain - the cell) */
+	struct iw_freq	freq;		/* frequency or channel :
+					 * 0-1000 = channel
+					 * > 1000 = frequency in Hz */
+
+	struct iw_param	sens;		/* signal level threshold */
+	struct iw_param	bitrate;	/* default bit rate */
+	struct iw_param	txpower;	/* default transmit power */
+	struct iw_param	rts;		/* RTS threshold threshold */
+	struct iw_param	frag;		/* Fragmentation threshold */
+	__u32		mode;		/* Operation mode */
+	struct iw_param	retry;		/* Retry limits & lifetime */
+
+	struct iw_point	encoding;	/* Encoding stuff : tokens */
+	struct iw_param	power;		/* PM duration/timeout */
+
+	struct sockaddr	ap_addr;	/* Access point address */
+
+	struct iw_point	data;		/* Other large parameters */
+};
+
+/*
  * The structure to exchange data for ioctl.
  * This structure is the same as 'struct ifreq', but (re)defined for
  * convenience...
- *
- * Note that it should fit on the same memory footprint !
- * You should check this when increasing the above structures (16 octets)
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * Do I need to remind you about structure size (32 octets) ?
  */
 struct	iwreq 
 {
@@ -429,35 +485,8 @@
 		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
 	} ifr_ifrn;
 
-	/* Data part */
-	union
-	{
-		/* Config - generic */
-		char		name[IFNAMSIZ];
-		/* Name : used to verify the presence of  wireless extensions.
-		 * Name of the protocol/provider... */
-
-		struct iw_point	essid;	/* Extended network name */
-		struct iw_param	nwid;	/* network id (or domain - the cell) */
-		struct iw_freq	freq;	/* frequency or channel :
-					 * 0-1000 = channel
-					 * > 1000 = frequency in Hz */
-
-		struct iw_param	sens;		/* signal level threshold */
-		struct iw_param	bitrate;	/* default bit rate */
-		struct iw_param	txpower;	/* default transmit power */
-		struct iw_param	rts;		/* RTS threshold threshold */
-		struct iw_param	frag;		/* Fragmentation threshold */
-		__u32		mode;		/* Operation mode */
-		struct iw_param	retry;		/* Retry limits & lifetime */
-
-		struct iw_point	encoding;	/* Encoding stuff : tokens */
-		struct iw_param	power;		/* PM duration/timeout */
-
-		struct sockaddr	ap_addr;	/* Access point address */
-
-		struct iw_point	data;		/* Other large parameters */
-	}	u;
+	/* Data part (defined just above) */
+	union	iwreq_data	u;
 };
 
 /* -------------------------- IOCTL DATA -------------------------- */
diff -urN linux-2.4.19-pre4/include/net/iw_handler.h linux-2.4.19-pre5/include/net/iw_handler.h
--- linux-2.4.19-pre4/include/net/iw_handler.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/include/net/iw_handler.h	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,374 @@
+/*
+ * This file define the new driver API for Wireless Extensions
+ *
+ * Version :	2	6.12.01
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
+ */
+
+#ifndef _IW_HANDLER_H
+#define _IW_HANDLER_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Initial driver API (1996 -> onward) :
+ * -----------------------------------
+ * The initial API just sends the IOCTL request received from user space
+ * to the driver (via the driver ioctl handler). The driver has to
+ * handle all the rest...
+ *
+ * The initial API also defines a specific handler in struct net_device
+ * to handle wireless statistics.
+ *
+ * The initial APIs served us well and has proven a reasonably good design.
+ * However, there is a few shortcommings :
+ *	o No events, everything is a request to the driver.
+ *	o Large ioctl function in driver with gigantic switch statement
+ *	  (i.e. spaghetti code).
+ *	o Driver has to mess up with copy_to/from_user, and in many cases
+ *	  does it unproperly. Common mistakes are :
+ *		* buffer overflows (no checks or off by one checks)
+ *		* call copy_to/from_user with irq disabled
+ *	o The user space interface is tied to ioctl because of the use
+ *	  copy_to/from_user.
+ *
+ * New driver API (2001 -> onward) :
+ * -------------------------------
+ * The new driver API is just a bunch of standard functions (handlers),
+ * each handling a specific Wireless Extension. The driver just export
+ * the list of handler it supports, and those will be called apropriately.
+ *
+ * I tried to keep the main advantage of the previous API (simplicity,
+ * efficiency and light weight), and also I provide a good dose of backward
+ * compatibility (most structures are the same, driver can use both API
+ * simultaneously, ...).
+ * Hopefully, I've also addressed the shortcomming of the initial API.
+ *
+ * The advantage of the new API are :
+ *	o Handling of Extensions in driver broken in small contained functions
+ *	o Tighter checks of ioctl before calling the driver
+ *	o Flexible commit strategy (at least, the start of it)
+ *	o Backward compatibility (can be mixed with old API)
+ *	o Driver doesn't have to worry about memory and user-space issues
+ * The last point is important for the following reasons :
+ *	o You are now able to call the new driver API from any API you
+ *		want (including from within other parts of the kernel).
+ *	o Common mistakes are avoided (buffer overflow, user space copy
+ *		with irq disabled and so on).
+ *
+ * The Drawback of the new API are :
+ *	o bloat (especially kernel)
+ *	o need to migrate existing drivers to new API
+ * My initial testing shows that the new API adds around 3kB to the kernel
+ * and save between 0 and 5kB from a typical driver.
+ * Also, as all structures and data types are unchanged, the migration is
+ * quite straightforward (but tedious).
+ *
+ * ---
+ *
+ * The new driver API is defined below in this file. User space should
+ * not be aware of what's happening down there...
+ *
+ * A new kernel wrapper is in charge of validating the IOCTLs and calling
+ * the appropriate driver handler. This is implemented in :
+ *	# net/core/wireless.c
+ *
+ * The driver export the list of handlers in :
+ *	# include/linux/netdevice.h (one place)
+ *
+ * The new driver API is available for WIRELESS_EXT >= 13.
+ * Good luck with migration to the new API ;-)
+ */
+
+/* ---------------------- THE IMPLEMENTATION ---------------------- */
+/*
+ * Some of the choice I've made are pretty controversials. Defining an
+ * API is very much weighting compromises. This goes into some of the
+ * details and the thinking behind the implementation.
+ *
+ * Implementation goals :
+ * --------------------
+ * The implementation goals were as follow :
+ *	o Obvious : you should not need a PhD to understand what's happening,
+ *		the benefit is easier maintainance.
+ *	o Flexible : it should accomodate a wide variety of driver
+ *		implementations and be as flexible as the old API.
+ *	o Lean : it should be efficient memory wise to minimise the impact
+ *		on kernel footprint.
+ *	o Transparent to user space : the large number of user space
+ *		applications that use Wireless Extensions should not need
+ *		any modifications.
+ *
+ * Array of functions versus Struct of functions
+ * ---------------------------------------------
+ * 1) Having an array of functions allow the kernel code to access the
+ * handler in a single lookup, which is much more efficient (think hash
+ * table here).
+ * 2) The only drawback is that driver writer may put their handler in
+ * the wrong slot. This is trivial to test (I set the frequency, the
+ * bitrate changes). Once the handler is in the proper slot, it will be
+ * there forever, because the array is only extended at the end.
+ * 3) Backward/forward compatibility : adding new handler just require
+ * extending the array, so you can put newer driver in older kernel
+ * without having to patch the kernel code (and vice versa).
+ *
+ * All handler are of the same generic type
+ * ----------------------------------------
+ * That's a feature !!!
+ * 1) Having a generic handler allow to have generic code, which is more
+ * efficient. If each of the handler was individually typed I would need
+ * to add a big switch in the kernel (== more bloat). This solution is
+ * more scalable, adding new Wireless Extensions doesn't add new code.
+ * 2) You can use the same handler in different slots of the array. For
+ * hardware, it may be more efficient or logical to handle multiple
+ * Wireless Extensions with a single function, and the API allow you to
+ * do that. (An example would be a single record on the card to control
+ * both bitrate and frequency, the handler would read the old record,
+ * modify it according to info->cmd and rewrite it).
+ *
+ * Functions prototype uses union iwreq_data
+ * -----------------------------------------
+ * Some would have prefered functions defined this way :
+ *	static int mydriver_ioctl_setrate(struct net_device *dev, 
+ *					  long rate, int auto)
+ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
+ * can't do it (different hardware may have different notion of what a
+ * valid frequency is), so we don't pretend that we do it.
+ * 2) The above form is not extendable. If I want to add a flag (for
+ * example to distinguish setting max rate and basic rate), I would
+ * break the prototype. Using iwreq_data is more flexible.
+ * 3) Also, the above form is not generic (see above).
+ * 4) I don't expect driver developper using the wrong field of the
+ * union (Doh !), so static typechecking doesn't add much value.
+ * 5) Lastly, you can skip the union by doing :
+ *	static int mydriver_ioctl_setrate(struct net_device *dev,
+ *					  struct iw_request_info *info,
+ *					  struct iw_param *rrq,
+ *					  char *extra)
+ * And then adding the handler in the array like this :
+ *        (iw_handler) mydriver_ioctl_setrate,             // SIOCSIWRATE
+ *
+ * Using functions and not a registry
+ * ----------------------------------
+ * Another implementation option would have been for every instance to
+ * define a registry (a struct containing all the Wireless Extensions)
+ * and only have a function to commit the registry to the hardware.
+ * 1) This approach can be emulated by the current code, but not
+ * vice versa.
+ * 2) Some drivers don't keep any configuration in the driver, for them
+ * adding such a registry would be a significant bloat.
+ * 3) The code to translate from Wireless Extension to native format is
+ * needed anyway, so it would not reduce significantely the amount of code.
+ * 4) The current approach only selectively translate Wireless Extensions
+ * to native format and only selectively set, whereas the registry approach
+ * would require to translate all WE and set all parameters for any single
+ * change.
+ * 5) For many Wireless Extensions, the GET operation return the current
+ * dynamic value, not the value that was set.
+ *
+ * This header is <net/iw_handler.h>
+ * ---------------------------------
+ * 1) This header is kernel space only and should not be exported to
+ * user space. Headers in "include/linux/" are exported, headers in
+ * "include/net/" are not.
+ *
+ * Mixed 32/64 bit issues
+ * ----------------------
+ * The Wireless Extensions are designed to be 64 bit clean, by using only
+ * datatypes with explicit storage size.
+ * There are some issues related to kernel and user space using different
+ * memory model, and in particular 64bit kernel with 32bit user space.
+ * The problem is related to struct iw_point, that contains a pointer
+ * that *may* need to be translated.
+ * This is quite messy. The new API doesn't solve this problem (it can't),
+ * but is a step in the right direction :
+ * 1) Meta data about each ioctl is easily available, so we know what type
+ * of translation is needed.
+ * 2) The move of data between kernel and user space is only done in a single
+ * place in the kernel, so adding specific hooks in there is possible.
+ * 3) In the long term, it allows to move away from using ioctl as the
+ * user space API.
+ *
+ * So many comments and so few code
+ * --------------------------------
+ * That's a feature. Comments won't bloat the resulting kernel binary.
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/wireless.h>		/* IOCTL user space API */
+
+/***************************** VERSION *****************************/
+/*
+ * This constant is used to know which version of the driver API is
+ * available. Hopefully, this will be pretty stable and no changes
+ * will be needed...
+ * I just plan to increment with each new version.
+ */
+#define IW_HANDLER_VERSION	2
+
+/**************************** CONSTANTS ****************************/
+
+/* Special error message for the driver to indicate that we
+ * should do a commit after return from the iw_handler */
+#define EIWCOMMIT	EINPROGRESS
+
+/* Flags available in struct iw_request_info */
+#define IW_REQUEST_FLAG_NONE	0x0000	/* No flag so far */
+
+/* Type of headers we know about (basically union iwreq_data) */
+#define IW_HEADER_TYPE_NULL	0	/* Not available */
+#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+#define IW_HEADER_TYPE_UINT	4	/* __u32 */
+#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+
+/* Handling flags */
+/* Most are not implemented. I just use them as a reminder of some
+ * cool features we might need one day ;-) */
+#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
+/* Wrapper level flags */
+#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
+/* Driver level flags */
+#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+
+/****************************** TYPES ******************************/
+
+/* ----------------------- WIRELESS HANDLER ----------------------- */
+/*
+ * A wireless handler is just a standard function, that looks like the
+ * ioctl handler.
+ * We also define there how a handler list look like... As the Wireless
+ * Extension space is quite dense, we use a simple array, which is faster
+ * (that's the perfect hash table ;-).
+ */
+
+/*
+ * Meta data about the request passed to the iw_handler.
+ * Most handlers can safely ignore what's in there.
+ * The 'cmd' field might come handy if you want to use the same handler
+ * for multiple command...
+ * This struct is also my long term insurance. I can add new fields here
+ * without breaking the prototype of iw_handler...
+ */
+struct iw_request_info
+{
+	__u16		cmd;		/* Wireless Extension command */
+	__u16		flags;		/* More to come ;-) */
+};
+
+/*
+ * This is how a function handling a Wireless Extension should look
+ * like (both get and set, standard and private).
+ */
+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
+			  union iwreq_data *wrqu, char *extra);
+
+/*
+ * This define all the handler that the driver export.
+ * As you need only one per driver type, please use a static const
+ * shared by all driver instances... Same for the members...
+ * This will be linked from net_device in <linux/netdevice.h>
+ */
+struct iw_handler_def
+{
+	/* Number of handlers defined (more precisely, index of the
+	 * last defined handler + 1) */
+	__u16			num_standard;
+	__u16			num_private;
+	/* Number of private arg description */
+	__u16			num_private_args;
+
+	/* Array of handlers for standard ioctls
+	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
+	 */
+	iw_handler *		standard;
+
+	/* Array of handlers for private ioctls
+	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
+	 */
+	iw_handler *		private;
+
+	/* Arguments of private handler. This one is just a list, so you
+	 * can put it in any order you want and should not leave holes...
+	 * We will automatically export that to user space... */
+	struct iw_priv_args *	private_args;
+
+	/* In the long term, get_wireless_stats will move from
+	 * 'struct net_device' to here, to minimise bloat. */
+};
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Currently we don't support events, so let's just plan for the
+ * future...
+ */
+
+/*
+ * A Wireless Event.
+ */
+// How do we define short header ? We don't want a flag on length.
+// Probably a flag on event ? Highest bit to zero...
+struct iw_event
+{
+	__u16		length;			/* Lenght of this stuff */
+	__u16		event;			/* Wireless IOCTL */
+	union	iwreq_data	header;		/* IOCTL fixed payload */
+	char		extra[0];		/* Optional IOCTL data */
+};
+
+/* ---------------------- IOCTL DESCRIPTION ---------------------- */
+/*
+ * One of the main goal of the new interface is to deal entirely with
+ * user space/kernel space memory move.
+ * For that, we need to know :
+ *	o if iwreq is a pointer or contain the full data
+ *	o what is the size of the data to copy
+ *
+ * For private IOCTLs, we use the same rules as used by iwpriv and
+ * defined in struct iw_priv_args.
+ *
+ * For standard IOCTLs, things are quite different and we need to
+ * use the stuctures below. Actually, this struct is also more
+ * efficient, but that's another story...
+ */
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+	__u8	header_type;		/* NULL, iw_point or other */
+	__u8	token_type;		/* Future */
+	__u16	token_size;		/* Granularity of payload */
+	__u16	min_tokens;		/* Min acceptable token number */
+	__u16	max_tokens;		/* Max acceptable token number */
+	__u32	flags;			/* Special handling of the request */
+};
+
+/* Need to think of short header translation table. Later. */
+
+/**************************** PROTOTYPES ****************************/
+/*
+ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
+ * Those may be called only within the kernel.
+ */
+
+/* First : function strictly used inside the kernel */
+
+/* Handle /proc/net/wireless, called in net/code/dev.c */
+extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+				 int length);
+
+/* Handle IOCTLs, called in net/code/dev.c */
+extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+
+/* Second : functions that may be called by driver modules */
+/* None yet */
+
+#endif	/* _LINUX_WIRELESS_H */
diff -urN linux-2.4.19-pre4/include/net/ndisc.h linux-2.4.19-pre5/include/net/ndisc.h
--- linux-2.4.19-pre4/include/net/ndisc.h	Thu Nov 22 11:47:42 2001
+++ linux-2.4.19-pre5/include/net/ndisc.h	Fri Mar 29 14:50:08 2002
@@ -42,11 +42,7 @@
 struct nd_msg {
         struct icmp6hdr	icmph;
         struct in6_addr	target;
-        struct {
-                __u8	opt_type;
-                __u8	opt_len;
-                __u8	link_addr[MAX_ADDR_LEN];
-        } opt;
+	__u8		opt[0];
 };
 
 struct ra_msg {
diff -urN linux-2.4.19-pre4/include/net/pkt_sched.h linux-2.4.19-pre5/include/net/pkt_sched.h
--- linux-2.4.19-pre4/include/net/pkt_sched.h	Thu Nov 22 11:47:12 2001
+++ linux-2.4.19-pre5/include/net/pkt_sched.h	Fri Mar 29 14:50:08 2002
@@ -358,8 +358,8 @@
 #define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
 #define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
 ({ \
-	   long __delta = (tv1) - (tv2); \
-	   if ( __delta > (bound)) {  __delta = (bound); guard; } \
+	   long long __delta = (tv1) - (tv2); \
+	   if ( __delta > (long long)(bound)) {  __delta = (bound); guard; } \
 	   __delta; \
 })
 
diff -urN linux-2.4.19-pre4/include/net/tcp.h linux-2.4.19-pre5/include/net/tcp.h
--- linux-2.4.19-pre4/include/net/tcp.h	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/include/net/tcp.h	Fri Mar 29 14:50:08 2002
@@ -75,7 +75,7 @@
  */
 struct tcp_bind_bucket {
 	unsigned short		port;
-	unsigned short		fastreuse;
+	signed short		fastreuse;
 	struct tcp_bind_bucket	*next;
 	struct sock		*owners;
 	struct tcp_bind_bucket	**pprev;
@@ -460,6 +460,7 @@
 extern int sysctl_tcp_rmem[3];
 extern int sysctl_tcp_app_win;
 extern int sysctl_tcp_adv_win_scale;
+extern int sysctl_tcp_tw_reuse;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -498,7 +499,7 @@
 	__u16			rmt_port;
 	__u16			mss;
 	__u8			retrans;
-	__u8			index;
+	__u8			__pad;
 	__u16	snd_wscale : 4, 
 		rcv_wscale : 4, 
 		tstamp_ok : 1,
@@ -568,9 +569,7 @@
 							 struct sk_buff *skb,
 							 struct open_request *req,
 							 struct dst_entry *dst);
-	
-	int			(*hash_connecting)	(struct sock *sk);
-
+    
 	int			(*remember_stamp)	(struct sock *sk);
 
 	__u16			net_header_len;
@@ -772,8 +771,7 @@
 					       struct sockaddr *uaddr,
 					       int addr_len);
 
-extern int			tcp_connect(struct sock *sk,
-					    struct sk_buff *skb);
+extern int			tcp_connect(struct sock *sk);
 
 extern struct sk_buff *		tcp_make_synack(struct sock *sk,
 						struct dst_entry *dst,
diff -urN linux-2.4.19-pre4/include/scsi/sg.h linux-2.4.19-pre5/include/scsi/sg.h
--- linux-2.4.19-pre4/include/scsi/sg.h	Fri Dec 21 09:42:04 2001
+++ linux-2.4.19-pre5/include/scsi/sg.h	Fri Mar 29 14:50:08 2002
@@ -9,11 +9,15 @@
 Original driver (sg.h):
 *       Copyright (C) 1992 Lawrence Foard
 Version 2 and 3 extensions to driver:
-*       Copyright (C) 1998 - 2001 Douglas Gilbert
+*       Copyright (C) 1998 - 2002 Douglas Gilbert
 
-    Version: 3.1.22 (20011208)
+    Version: 3.1.23 (20020318)
     This version is for 2.4 series kernels.
 
+    Changes since 3.1.22 (20011208)
+	- change EACCES to EPERM when O_RDONLY is insufficient
+	- suppress newlines in host string ( /proc/scsi/sg/host_strs output)
+	- fix xfer direction, old interface, short reply_len [Travers Carter]
     Changes since 3.1.21 (20011029)
     	- add support for SG_FLAG_MMAP_IO [permit mmap() on sg devices]
     	- update documentation pointers in this header
diff -urN linux-2.4.19-pre4/init/do_mounts.c linux-2.4.19-pre5/init/do_mounts.c
--- linux-2.4.19-pre4/init/do_mounts.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/init/do_mounts.c	Fri Mar 29 14:50:08 2002
@@ -14,11 +14,14 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
 #include <linux/nfs_mount.h>
+#include <linux/minix_fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/romfs_fs.h>
 
 #include <asm/uaccess.h>
 
-extern void rd_load(void);
-extern void initrd_load(void);
+#define BUILD_CRAMDISK
+
 extern int get_filesystem_list(char * buf);
 extern void wait_for_keypress(void);
 
@@ -28,18 +31,27 @@
 asmlinkage long sys_chdir(char *name);
 asmlinkage long sys_chroot(char *name);
 asmlinkage long sys_unlink(char *name);
+asmlinkage long sys_symlink(char *old, char *new);
 asmlinkage long sys_mknod(char *name, int mode, dev_t dev);
 asmlinkage long sys_umount(char *name, int flags);
+asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 unsigned int real_root_dev;	/* do_proc_dointvec cannot handle kdev_t */
 #endif
-int root_mountflags = MS_RDONLY;
-char root_device_name[64];
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;
+#else
+static int rd_doload = 0;
+#endif
+int root_mountflags = MS_RDONLY | MS_VERBOSE;
+static char root_device_name[64];
 
 /* this is initialized in init/main.c */
 kdev_t ROOT_DEV;
 
+static int do_devfs = 0;
+
 static int __init readonly(char *str)
 {
 	if (*str)
@@ -270,92 +282,20 @@
 	}
 	*s = '\0';
 }
-
-static void __init mount_root(void)
+static void __init mount_block_root(char *name, int flags)
 {
-	void *handle;
-	char path[64];
-	char *name = "/dev/root";
-	char *fs_names, *p;
-	int do_devfs = 0;
-
-	root_mountflags |= MS_VERBOSE;
+	char *fs_names = __getname();
+	char *p;
 
-	fs_names = __getname();
 	get_fs_names(fs_names);
-
-#ifdef CONFIG_ROOT_NFS
-	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
-		void *data;
-		data = nfs_root_data();
-		if (data) {
-			int err = sys_mount("/dev/root", "/root", "nfs", root_mountflags, data);
-			if (!err)
-				goto done;
-		}
-		printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
-		ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
-	}
-#endif
-
-#ifdef CONFIG_BLK_DEV_FD
-	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
-#ifdef CONFIG_BLK_DEV_RAM
-		extern int rd_doload;
-		extern void rd_load_secondary(void);
-#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();
-		}
-	}
-#endif
-
-	devfs_make_root (root_device_name);
-	handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME,
-	                            MAJOR (ROOT_DEV), MINOR (ROOT_DEV),
-				    DEVFS_SPECIAL_BLK, 1);
-	if (handle) {
-		int n;
-		unsigned major, minor;
-
-		devfs_get_maj_min (handle, &major, &minor);
-		ROOT_DEV = MKDEV (major, minor);
-		if (!ROOT_DEV)
-			panic("I have no root and I want to scream");
-		n = devfs_generate_path (handle, path + 5, sizeof (path) - 5);
-		if (n >= 0) {
-			name = path + n;
-			devfs_unregister (devfs_find_handle(NULL, "root", 0, 0, 0, 0));
-			devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
-					  name + 5, NULL, NULL);
-			memcpy (name, "/dev/", 5);
-			do_devfs = 1;
-		}
-	}
-	sys_chdir("/dev");
-	sys_unlink("root");
-	sys_mknod("root", S_IFBLK|0600, kdev_t_to_nr(ROOT_DEV));
-	if (do_devfs)
-		sys_mount("devfs", ".", "devfs", 0, NULL);
 retry:
 	for (p = fs_names; *p; p += strlen(p)+1) {
-		int err;
-		err = sys_mount(name,"/root",p,root_mountflags,root_mount_data);
+		int err = sys_mount(name, "/root", p, flags, root_mount_data);
 		switch (err) {
 			case 0:
-				goto done;
+				goto out;
 			case -EACCES:
-				root_mountflags |= MS_RDONLY;
+				flags |= MS_RDONLY;
 				goto retry;
 			case -EINVAL:
 				continue;
@@ -371,94 +311,324 @@
 			kdevname(ROOT_DEV));
 	}
 	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
-
-done:
+out:
 	putname(fs_names);
-	if (do_devfs)
-		sys_umount(".", 0);
+	sys_chdir("/root");
+	ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
+	printk("VFS: Mounted root (%s filesystem)%s.\n",
+		current->fs->pwdmnt->mnt_sb->s_type->name,
+		(current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
 }
+ 
+static int __init mount_nfs_root(void)
+{
+#ifdef CONFIG_ROOT_NFS
+	void *data = nfs_root_data();
 
-#ifdef CONFIG_BLK_DEV_INITRD
+	if (data && sys_mount("/dev/root","/root","nfs",root_mountflags,data) == 0)
+		return 1;
+#endif
+	return 0;
+}
 
-static int __init change_root(kdev_t new_root_dev,const char *put_old)
+static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
 {
-	struct vfsmount *old_rootmnt;
-	struct nameidata devfs_nd;
-	char *new_devname = kmalloc(strlen("/dev/root.old")+1, GFP_KERNEL);
-	int error = 0;
+	void *handle;
+	char path[64];
+	int n;
 
-	if (new_devname)
-		strcpy(new_devname, "/dev/root.old");
+	sys_unlink(name);
+	if (!do_devfs)
+		return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
+
+	handle = devfs_find_handle(NULL, dev ? NULL : devfs_name,
+				MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1);
+	if (!handle)
+		return -1;
+	n = devfs_generate_path(handle, path + 5, sizeof (path) - 5);
+	if (n < 0)
+		return -1;
+	return sys_symlink(path + n + 5, name);
+}
+
+#ifdef CONFIG_MAC_FLOPPY
+int swim3_fd_eject(int devnum);
+#endif
+static void __init change_floppy(char *fmt, ...)
+{
+	extern void wait_for_keypress(void);
+	char buf[80];
+	va_list args;
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+#ifdef CONFIG_BLK_DEV_FD
+	floppy_eject();
+#endif
+#ifdef CONFIG_MAC_FLOPPY
+	swim3_fd_eject(MINOR(ROOT_DEV));
+#endif
+	printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
+	wait_for_keypress();
+}
 
-	/* .. here is directory mounted over root */
-	sys_mount("..", ".", NULL, MS_MOVE, NULL);
-	sys_chdir("/old");
+#ifdef CONFIG_BLK_DEV_RAM
 
-	read_lock(&current->fs->lock);
-	old_rootmnt = mntget(current->fs->pwdmnt);
-	read_unlock(&current->fs->lock);
-
-	/*  First unmount devfs if mounted  */
-	if (path_init("/old/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))
-		error = path_walk("/old/dev", &devfs_nd);
-	if (!error) {
-		if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC &&
-		    devfs_nd.dentry == devfs_nd.mnt->mnt_root)
-			sys_umount("/old/dev", 0);
-		path_release(&devfs_nd);
+static int __init crd_load(int in_fd, int out_fd);
+
+/*
+ * This routine tries to find a RAM disk image to load, and returns the
+ * number of blocks to read for a non-compressed image, 0 if the image
+ * is a compressed image, and -1 if an image with the right magic
+ * numbers could not be found.
+ *
+ * We currently check for the following magic numbers:
+ * 	minix
+ * 	ext2
+ *	romfs
+ * 	gzip
+ */
+static int __init 
+identify_ramdisk_image(int fd, int start_block)
+{
+	const int size = 512;
+	struct minix_super_block *minixsb;
+	struct ext2_super_block *ext2sb;
+	struct romfs_super_block *romfsb;
+	int nblocks = -1;
+	unsigned char *buf;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (buf == 0)
+		return -1;
+
+	minixsb = (struct minix_super_block *) buf;
+	ext2sb = (struct ext2_super_block *) buf;
+	romfsb = (struct romfs_super_block *) buf;
+	memset(buf, 0xe5, size);
+
+	/*
+	 * Read block 0 to test for gzipped kernel
+	 */
+	lseek(fd, start_block * BLOCK_SIZE, 0);
+	read(fd, buf, size);
+
+	/*
+	 * If it matches the gzip magic numbers, return -1
+	 */
+	if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
+		printk(KERN_NOTICE
+		       "RAMDISK: Compressed image found at block %d\n",
+		       start_block);
+		nblocks = 0;
+		goto done;
 	}
 
-	ROOT_DEV = new_root_dev;
-	mount_root();
+	/* romfs is at block zero too */
+	if (romfsb->word0 == ROMSB_WORD0 &&
+	    romfsb->word1 == ROMSB_WORD1) {
+		printk(KERN_NOTICE
+		       "RAMDISK: romfs filesystem found at block %d\n",
+		       start_block);
+		nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
+		goto done;
+	}
 
-	sys_chdir("/root");
-	ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
-	printk("VFS: Mounted root (%s filesystem)%s.\n",
-		current->fs->pwdmnt->mnt_sb->s_type->name,
-		(current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
+	/*
+	 * Read block 1 to test for minix and ext2 superblock
+	 */
+	lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
+	read(fd, buf, size);
+
+	/* Try minix */
+	if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
+	    minixsb->s_magic == MINIX_SUPER_MAGIC2) {
+		printk(KERN_NOTICE
+		       "RAMDISK: Minix filesystem found at block %d\n",
+		       start_block);
+		nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
+		goto done;
+	}
+
+	/* Try ext2 */
+	if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
+		printk(KERN_NOTICE
+		       "RAMDISK: ext2 filesystem found at block %d\n",
+		       start_block);
+		nblocks = le32_to_cpu(ext2sb->s_blocks_count);
+		goto done;
+	}
 
-#if 1
-	shrink_dcache();
-	printk("change_root: old root has d_count=%d\n", 
-	       atomic_read(&old_rootmnt->mnt_root->d_count));
+	printk(KERN_NOTICE
+	       "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
+	       start_block);
+	
+done:
+	lseek(fd, start_block * BLOCK_SIZE, 0);
+	kfree(buf);
+	return nblocks;
+}
 #endif
 
-	error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
-	if (error) {
-		int blivet;
-		struct block_device *ramdisk = old_rootmnt->mnt_sb->s_bdev;
-
-		atomic_inc(&ramdisk->bd_count);
-		blivet = blkdev_get(ramdisk, FMODE_READ, 0, BDEV_FS);
-		printk(KERN_NOTICE "Trying to unmount old root ... ");
-		sys_umount("/old", MNT_DETACH);
-		if (!blivet) {
-			blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0);
-			blkdev_put(ramdisk, BDEV_FS);
-		}
-		if (blivet) {
-			printk(KERN_ERR "error %d\n", blivet);
-		} else {
-			printk("okay\n");
-			error = 0;
+static int __init rd_load_image(char *from)
+{
+	int res = 0;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	int in_fd, out_fd;
+	int nblocks, rd_blocks, devblocks, i;
+	char *buf;
+	unsigned short rotate = 0;
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
+	char rotator[4] = { '|' , '/' , '-' , '\\' };
+#endif
+
+	out_fd = open("/dev/ram", O_RDWR, 0);
+	if (out_fd < 0)
+		goto out;
+
+	in_fd = open(from, O_RDONLY, 0);
+	if (in_fd < 0)
+		goto noclose_input;
+
+	nblocks = identify_ramdisk_image(in_fd, rd_image_start);
+	if (nblocks < 0)
+		goto done;
+
+	if (nblocks == 0) {
+#ifdef BUILD_CRAMDISK
+		if (crd_load(in_fd, out_fd) == 0)
+			goto successful_load;
+#else
+		printk(KERN_NOTICE
+		       "RAMDISK: Kernel does not support compressed "
+		       "RAM disk images\n");
+#endif
+		goto done;
+	}
+
+	/*
+	 * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so
+	 * rd_load_image will work only with filesystem BLOCK_SIZE wide!
+	 * So make sure to use 1k blocksize while generating ext2fs
+	 * ramdisk-images.
+	 */
+	if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
+		rd_blocks = 0;
+	else
+		rd_blocks >>= 1;
+
+	if (nblocks > rd_blocks) {
+		printk("RAMDISK: image too big! (%d/%d blocks)\n",
+		       nblocks, rd_blocks);
+		goto done;
+	}
+		
+	/*
+	 * OK, time to copy in the data
+	 */
+	buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
+	if (buf == 0) {
+		printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
+		goto done;
+	}
+
+	if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0)
+		devblocks = 0;
+	else
+		devblocks >>= 1;
+
+	if (strcmp(from, "/dev/initrd") == 0)
+		devblocks = nblocks;
+
+	if (devblocks == 0) {
+		printk(KERN_ERR "RAMDISK: could not determine device size\n");
+		goto done;
+	}
+
+	printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", 
+		nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
+	for (i=0; i < nblocks; i++) {
+		if (i && (i % devblocks == 0)) {
+			printk("done disk #%d.\n", i/devblocks);
+			rotate = 0;
+			if (close(in_fd)) {
+				printk("Error closing the disk.\n");
+				goto noclose_input;
+			}
+			change_floppy("disk #%d", i/devblocks+1);
+			in_fd = open(from, O_RDONLY, 0);
+			if (in_fd < 0)  {
+				printk("Error opening disk.\n");
+				goto noclose_input;
+			}
+			printk("Loading disk #%d... ", i/devblocks+1);
 		}
-	} else {
-		spin_lock(&dcache_lock);
-		if (new_devname) {
-			void *p = old_rootmnt->mnt_devname;
-			old_rootmnt->mnt_devname = new_devname;
-			new_devname = p;
+		read(in_fd, buf, BLOCK_SIZE);
+		write(out_fd, buf, BLOCK_SIZE);
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
+		if (!(i % 16)) {
+			printk("%c\b", rotator[rotate & 0x3]);
+			rotate++;
 		}
-		spin_unlock(&dcache_lock);
+#endif
 	}
+	printk("done.\n");
+	kfree(buf);
 
-	/* put the old stuff */
-	mntput(old_rootmnt);
-	kfree(new_devname);
-	return error;
+successful_load:
+	res = 1;
+done:
+	close(in_fd);
+noclose_input:
+	close(out_fd);
+out:
+	sys_unlink("/dev/ram");
+#endif
+	return res;
 }
 
+static int __init rd_load_disk(int n)
+{
+#ifdef CONFIG_BLK_DEV_RAM
+	extern int rd_prompt;
+	if (rd_prompt)
+		change_floppy("root floppy disk to be loaded into RAM disk");
+	create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL);
 #endif
+	return rd_load_image("/dev/root");
+}
+
+static void __init mount_root(void)
+{
+#ifdef CONFIG_ROOT_NFS
+	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
+		if (mount_nfs_root()) {
+			sys_chdir("/root");
+			ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
+			printk("VFS: Mounted root (nfs filesystem).\n");
+			return;
+		}
+		printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
+		ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
+	}
+#endif
+	devfs_make_root(root_device_name);
+	create_dev("/dev/root", ROOT_DEV, root_device_name);
+#ifdef CONFIG_BLK_DEV_FD
+	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+		/* rd_doload is 2 for a dual initrd/ramload setup */
+		if (rd_doload==2) {
+			if (rd_load_disk(1)) {
+				ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1);
+				create_dev("/dev/root", ROOT_DEV, NULL);
+			}
+		} else
+			change_floppy("root floppy");
+	}
+#endif
+	mount_block_root("/dev/root", root_mountflags);
+}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 static int do_linuxrc(void * shell)
@@ -482,76 +652,247 @@
 
 #endif
 
+static void __init handle_initrd(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	int ram0 = kdev_t_to_nr(MKDEV(RAMDISK_MAJOR,0));
+	int error;
+	int i, pid;
+
+	create_dev("/dev/root.old", ram0, NULL);
+	mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
+	sys_mkdir("/old", 0700);
+	sys_chdir("/old");
+
+	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
+	if (pid > 0) {
+		while (pid != wait(&i)) {
+			current->policy |= SCHED_YIELD;
+			schedule();
+		}
+	}
+
+	sys_mount("..", ".", NULL, MS_MOVE, NULL);
+	sys_umount("/old/dev", 0);
+
+	if (real_root_dev == ram0) {
+		sys_chdir("/old");
+		return;
+	}
+
+	ROOT_DEV = real_root_dev;
+	mount_root();
+
+	printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
+	error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
+	if (!error)
+		printk("okay\n");
+	else {
+		int fd = open("/dev/root.old", O_RDWR, 0);
+		printk("failed\n");
+		printk(KERN_NOTICE "Unmounting old root\n");
+		sys_umount("/old", MNT_DETACH);
+		printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
+		if (fd < 0) {
+			error = fd;
+		} else {
+			error = sys_ioctl(fd, BLKFLSBUF, 0);
+			close(fd);
+		}
+		printk(error ? "okay\n" : "failed\n");
+	}
+#endif
+}
+
+static int __init initrd_load(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
+	create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL);
+#endif
+	return rd_load_image("/dev/initrd");
+}
+
 /*
  * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
  */
 void prepare_namespace(void)
 {
+	int do_initrd = 0;
+	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
 #ifdef CONFIG_BLK_DEV_INITRD
-	int real_root_mountflags = root_mountflags;
 	if (!initrd_start)
 		mount_initrd = 0;
 	if (mount_initrd)
-		root_mountflags &= ~MS_RDONLY;
+		do_initrd = 1;
 	real_root_dev = ROOT_DEV;
 #endif
 	sys_mkdir("/dev", 0700);
 	sys_mkdir("/root", 0700);
-
-#ifdef CONFIG_BLK_DEV_RAM
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (mount_initrd)
-		initrd_load();
-	else
-#endif
-	rd_load();
+#ifdef CONFIG_DEVFS_FS
+	sys_mount("devfs", "/dev", "devfs", 0, NULL);
+	do_devfs = 1;
 #endif
 
-	/* Mount the root filesystem.. */
+	create_dev("/dev/root", ROOT_DEV, NULL);
+	if (do_initrd) {
+		if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
+			handle_initrd();
+			goto out;
+		}
+	} else if (is_floppy && rd_doload && rd_load_disk(0))
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
 	mount_root();
-	sys_chdir("/root");
-	ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
-	printk("VFS: Mounted root (%s filesystem)%s.\n",
-		current->fs->pwdmnt->mnt_sb->s_type->name,
-		(current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
+out:
+	sys_umount("/dev", 0);
+	sys_mount(".", "/", NULL, MS_MOVE, NULL);
+	sys_chroot(".");
+	mount_devfs_fs ();
+}
 
-#ifdef CONFIG_BLK_DEV_INITRD
-	root_mountflags = real_root_mountflags;
-	if (mount_initrd && ROOT_DEV != real_root_dev
-	    && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
-		int error;
-		int i, pid;
-		sys_mkdir("/old", 0700);
-		sys_chdir("/old");
+#ifdef BUILD_CRAMDISK
 
-		pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
-		if (pid > 0) {
-			while (pid != wait(&i)) {
-				current->policy |= SCHED_YIELD;
-				schedule();
-			}
-		}
-		if (MAJOR(real_root_dev) != RAMDISK_MAJOR
-		     || MINOR(real_root_dev) != 0) {
-			error = change_root(real_root_dev,"/initrd");
-			if (error)
-				printk(KERN_ERR "Change root to /initrd: "
-				    "error %d\n",error);
+/*
+ * gzip declarations
+ */
 
-			sys_chdir("/root");
-			sys_mount(".", "/", NULL, MS_MOVE, NULL);
-			sys_chroot(".");
+#define OF(args)  args
 
-			mount_devfs_fs ();
-			return;
-		}
-		sys_chroot("..");
-		sys_chdir("/");
-		return;
-	}
+#ifndef memzero
+#define memzero(s, n)     memset ((s), 0, (n))
 #endif
-	sys_mount(".", "/", NULL, MS_MOVE, NULL);
-	sys_chroot(".");
 
-	mount_devfs_fs ();
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define INBUFSIZ 4096
+#define WSIZE 0x8000    /* window size--must be a power of two, and */
+			/*  at least 32K for zip's deflate method */
+
+static uch *inbuf;
+static uch *window;
+
+static unsigned insize;  /* valid bytes in inbuf */
+static unsigned inptr;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt;  /* bytes in output buffer */
+static int exit_code;
+static long bytes_out;
+static int crd_infd, crd_outfd;
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+		
+/* Diagnostic functions (stubbed out) */
+#define Assert(cond,msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c,x)
+#define Tracecv(c,x)
+
+#define STATIC static
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+#include "../lib/inflate.c"
+
+static void __init *malloc(int size)
+{
+	return kmalloc(size, GFP_KERNEL);
 }
+
+static void __init free(void *where)
+{
+	kfree(where);
+}
+
+static void __init gzip_mark(void **ptr)
+{
+}
+
+static void __init gzip_release(void **ptr)
+{
+}
+
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int __init fill_inbuf(void)
+{
+	if (exit_code) return -1;
+	
+	insize = read(crd_infd, inbuf, INBUFSIZ);
+	if (insize == 0) return -1;
+
+	inptr = 1;
+
+	return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void __init flush_window(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, ch;
+    
+    write(crd_outfd, window, outcnt);
+    in = window;
+    for (n = 0; n < outcnt; n++) {
+	    ch = *in++;
+	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void __init error(char *x)
+{
+	printk(KERN_ERR "%s", x);
+	exit_code = 1;
+}
+
+static int __init crd_load(int in_fd, int out_fd)
+{
+	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_infd = in_fd;
+	crd_outfd = out_fd;
+	inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
+	if (inbuf == 0) {
+		printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
+		return -1;
+	}
+	window = kmalloc(WSIZE, GFP_KERNEL);
+	if (window == 0) {
+		printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
+		kfree(inbuf);
+		return -1;
+	}
+	makecrc();
+	result = gunzip();
+	kfree(inbuf);
+	kfree(window);
+	return result;
+}
+
+#endif  /* BUILD_CRAMDISK */
diff -urN linux-2.4.19-pre4/kernel/acct.c linux-2.4.19-pre5/kernel/acct.c
--- linux-2.4.19-pre4/kernel/acct.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/kernel/acct.c	Fri Mar 29 14:50:08 2002
@@ -361,7 +361,7 @@
 		file = acct_file;
 		get_file(file);
 		unlock_kernel();
-		do_acct_process(exitcode, acct_file);
+		do_acct_process(exitcode, file);
 		fput(file);
 	} else
 		unlock_kernel();
diff -urN linux-2.4.19-pre4/kernel/ksyms.c linux-2.4.19-pre5/kernel/ksyms.c
--- linux-2.4.19-pre4/kernel/ksyms.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/kernel/ksyms.c	Fri Mar 29 14:50:08 2002
@@ -165,6 +165,7 @@
 EXPORT_SYMBOL(set_buffer_async_io); /* for reiserfs_writepage */
 EXPORT_SYMBOL(__mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_inode_dirty);
+EXPORT_SYMBOL(fd_install);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
 EXPORT_SYMBOL(filp_open);
@@ -453,6 +454,7 @@
 
 /* misc */
 EXPORT_SYMBOL(panic);
+EXPORT_SYMBOL(out_of_line_bug);
 EXPORT_SYMBOL(sprintf);
 EXPORT_SYMBOL(snprintf);
 EXPORT_SYMBOL(sscanf);
diff -urN linux-2.4.19-pre4/kernel/panic.c linux-2.4.19-pre5/kernel/panic.c
--- linux-2.4.19-pre4/kernel/panic.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/kernel/panic.c	Fri Mar 29 14:50:08 2002
@@ -124,3 +124,21 @@
 }
 
 int tainted = 0;
+
+/*
+ * A BUG() call in an inline function in a header should be avoided,
+ * because it can seriously bloat the kernel.  So here we have
+ * helper functions.
+ * We lose the BUG()-time file-and-line info this way, but it's
+ * usually not very useful from an inline anyway.  The backtrace
+ * tells us what we want to know.
+ */
+
+void out_of_line_bug(void)
+{
+	BUG();
+
+	/* Satisfy __attribute__((noreturn)) */
+	for ( ; ; )
+		;
+}
diff -urN linux-2.4.19-pre4/mm/filemap.c linux-2.4.19-pre5/mm/filemap.c
--- linux-2.4.19-pre4/mm/filemap.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/mm/filemap.c	Fri Mar 29 14:50:08 2002
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/iobuf.h>
-#include <linux/compiler.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -870,12 +869,6 @@
 	remove_wait_queue(waitqueue, &wait);
 }
 
-void wake_up_page(struct page *page)
-{
-	wake_up(page_waitqueue(page));
-}
-EXPORT_SYMBOL(wake_up_page);
-
 /*
  * Get an exclusive lock on the page, optimistically
  * assuming it's not locked..
@@ -2205,6 +2198,9 @@
 	int ret = 0;
 	struct file * file = vma->vm_file;
 
+	if ( (flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED) )
+		return -EBUSY;
+
 	if (file && (vma->vm_flags & VM_SHARED)) {
 		ret = filemap_sync(vma, start, end-start, flags);
 
diff -urN linux-2.4.19-pre4/mm/page_alloc.c linux-2.4.19-pre5/mm/page_alloc.c
--- linux-2.4.19-pre4/mm/page_alloc.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/mm/page_alloc.c	Fri Mar 29 14:50:08 2002
@@ -20,7 +20,6 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
-#include <linux/compiler.h>
 #include <linux/module.h>
 
 int nr_swap_pages;
diff -urN linux-2.4.19-pre4/mm/slab.c linux-2.4.19-pre5/mm/slab.c
--- linux-2.4.19-pre4/mm/slab.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/mm/slab.c	Fri Mar 29 14:50:08 2002
@@ -72,7 +72,6 @@
 #include	<linux/slab.h>
 #include	<linux/interrupt.h>
 #include	<linux/init.h>
-#include	<linux/compiler.h>
 #include	<asm/uaccess.h>
 
 /*
diff -urN linux-2.4.19-pre4/mm/swapfile.c linux-2.4.19-pre5/mm/swapfile.c
--- linux-2.4.19-pre4/mm/swapfile.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/mm/swapfile.c	Fri Mar 29 14:50:08 2002
@@ -14,7 +14,6 @@
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/shm.h>
-#include <linux/compiler.h>
 
 #include <asm/pgtable.h>
 
diff -urN linux-2.4.19-pre4/mm/vmscan.c linux-2.4.19-pre5/mm/vmscan.c
--- linux-2.4.19-pre4/mm/vmscan.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/mm/vmscan.c	Fri Mar 29 14:50:08 2002
@@ -20,7 +20,6 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
-#include <linux/compiler.h>
 
 #include <asm/pgalloc.h>
 
diff -urN linux-2.4.19-pre4/net/atm/resources.c linux-2.4.19-pre5/net/atm/resources.c
--- linux-2.4.19-pre4/net/atm/resources.c	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre5/net/atm/resources.c	Fri Mar 29 14:50:08 2002
@@ -27,170 +27,188 @@
 struct atm_vcc *nodev_vccs = NULL;
 extern spinlock_t atm_dev_lock;
 
-
-static struct atm_dev *alloc_atm_dev(const char *type)
+/* Caller must hold atm_dev_lock. */
+static struct atm_dev *__alloc_atm_dev(const char *type)
 {
 	struct atm_dev *dev;
 
-	dev = kmalloc(sizeof(*dev),GFP_KERNEL);
-	if (!dev) return NULL;
-	memset(dev,0,sizeof(*dev));
+	dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
 	dev->next = NULL;
 
-	spin_lock(&atm_dev_lock);
-
 	dev->prev = last_dev;
 
-	if (atm_devs) last_dev->next = dev;
-	else atm_devs = dev;
+	if (atm_devs)
+		last_dev->next = dev;
+	else
+		atm_devs = dev;
 	last_dev = dev;
-	spin_unlock(&atm_dev_lock);
+
 	return dev;
 }
 
-
-static void free_atm_dev(struct atm_dev *dev)
+/* Caller must hold atm_dev_lock. */
+static void __free_atm_dev(struct atm_dev *dev)
 {
-	spin_lock (&atm_dev_lock);
-	
-	if (dev->prev) dev->prev->next = dev->next;
-	else atm_devs = dev->next;
-	if (dev->next) dev->next->prev = dev->prev;
-	else last_dev = dev->prev;
+	if (dev->prev)
+		dev->prev->next = dev->next;
+	else
+		atm_devs = dev->next;
+
+	if (dev->next)
+		dev->next->prev = dev->prev;
+	else
+		last_dev = dev->prev;
+
 	kfree(dev);
-	
-	spin_unlock (&atm_dev_lock);
 }
 
-
+/* Caller must hold atm_dev_lock. */
 struct atm_dev *atm_find_dev(int number)
 {
 	struct atm_dev *dev;
 
 	for (dev = atm_devs; dev; dev = dev->next)
-		if (dev->ops && dev->number == number) return dev;
+		if (dev->ops && dev->number == number)
+			return dev;
 	return NULL;
 }
 
-
-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
-    int number,atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+				 int number, atm_dev_flags_t *flags)
 {
 	struct atm_dev *dev;
 
-	dev = alloc_atm_dev(type);
+	spin_lock(&atm_dev_lock);
+
+	dev = __alloc_atm_dev(type);
 	if (!dev) {
 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
-		    type);
-		return NULL;
+		       type);
+		goto done;
 	}
 	if (number != -1) {
 		if (atm_find_dev(number)) {
-			free_atm_dev(dev);
-			return NULL;
+			__free_atm_dev(dev);
+			dev = NULL;
+			goto done;
 		}
 		dev->number = number;
-	}
-	else {
+	} else {
 		dev->number = 0;
-		while (atm_find_dev(dev->number)) dev->number++;
+		while (atm_find_dev(dev->number))
+			dev->number++;
 	}
 	dev->vccs = dev->last = NULL;
 	dev->dev_data = NULL;
 	barrier();
 	dev->ops = ops;
-	if (flags) dev->flags = *flags;
-	else memset(&dev->flags,0,sizeof(dev->flags));
-	memset((void *) &dev->stats,0,sizeof(dev->stats));
+	if (flags)
+		dev->flags = *flags;
+	else
+		memset(&dev->flags, 0, sizeof(dev->flags));
+	memset(&dev->stats, 0, sizeof(dev->stats));
+
 #ifdef CONFIG_PROC_FS
-	if (ops->proc_read)
+	if (ops->proc_read) {
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
-			    "atm_proc_dev_register failed for dev %s\n",type);
-			spin_unlock (&atm_dev_lock);		
-			free_atm_dev(dev);
-			return NULL;
+			       "atm_proc_dev_register failed for dev %s\n",
+			       type);
+			__free_atm_dev(dev);
+			dev = NULL;
+			goto done;
 		}
+	}
 #endif
-	spin_unlock (&atm_dev_lock);		
+
+done:
+	spin_unlock(&atm_dev_lock);		
+
 	return dev;
 }
 
-
 void atm_dev_deregister(struct atm_dev *dev)
 {
 #ifdef CONFIG_PROC_FS
-	if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
+	if (dev->ops->proc_read)
+		atm_proc_dev_deregister(dev);
 #endif
-	free_atm_dev(dev);
+	spin_lock(&atm_dev_lock);
+	__free_atm_dev(dev);
+	spin_unlock(&atm_dev_lock);
 }
 
-
 void shutdown_atm_dev(struct atm_dev *dev)
 {
 	if (dev->vccs) {
-		set_bit(ATM_DF_CLOSE,&dev->flags);
+		set_bit(ATM_DF_CLOSE, &dev->flags);
 		return;
 	}
-	if (dev->ops->dev_close) dev->ops->dev_close(dev);
+	if (dev->ops->dev_close)
+		dev->ops->dev_close(dev);
 	atm_dev_deregister(dev);
 }
 
-
 /* Handler for sk->destruct, invoked by sk_free() */
 static void atm_free_sock(struct sock *sk)
 {
 	kfree(sk->protinfo.af_atm);
 }
 
-
 struct sock *alloc_atm_vcc_sk(int family)
 {
 	struct sock *sk;
 	struct atm_vcc *vcc;
 
 	sk = sk_alloc(family, GFP_KERNEL, 1);
-	if (!sk) return NULL;
+	if (!sk)
+		return NULL;
 	vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL);
 	if (!vcc) {
 		sk_free(sk);
 		return NULL;
 	}
-	sock_init_data(NULL,sk);
+	sock_init_data(NULL, sk);
 	sk->destruct = atm_free_sock;
 	memset(vcc,0,sizeof(*vcc));
 	vcc->sk = sk;
-	if (nodev_vccs) nodev_vccs->prev = vcc;
+	if (nodev_vccs)
+		nodev_vccs->prev = vcc;
 	vcc->prev = NULL;
 	vcc->next = nodev_vccs;
 	nodev_vccs = vcc;
 	return sk;
 }
 
-
 static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
 {
-	if (vcc->prev) vcc->prev->next = vcc->next;
-	else if (vcc->dev) vcc->dev->vccs = vcc->next;
-	    else nodev_vccs = vcc->next;
-	if (vcc->next) vcc->next->prev = vcc->prev;
-	else if (vcc->dev) vcc->dev->last = vcc->prev;
+	if (vcc->prev)
+		vcc->prev->next = vcc->next;
+	else if (vcc->dev)
+		vcc->dev->vccs = vcc->next;
+	else
+		nodev_vccs = vcc->next;
+	if (vcc->next)
+		vcc->next->prev = vcc->prev;
+	else if (vcc->dev)
+		vcc->dev->last = vcc->prev;
 	if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
 	    test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
 		shutdown_atm_dev(vcc->dev);
 }
 
-
 void free_atm_vcc_sk(struct sock *sk)
 {
-	unlink_vcc(sk->protinfo.af_atm,NULL);
+	unlink_vcc(sk->protinfo.af_atm, NULL);
 	sk_free(sk);
 }
 
-
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
 {
 	unlink_vcc(vcc,dev);
@@ -198,19 +216,20 @@
 	if (dev) {
 		vcc->next = NULL;
 		vcc->prev = dev->last;
-		if (dev->vccs) dev->last->next = vcc;
-		else dev->vccs = vcc;
+		if (dev->vccs)
+			dev->last->next = vcc;
+		else
+			dev->vccs = vcc;
 		dev->last = vcc;
-	}
-	else {
-		if (nodev_vccs) nodev_vccs->prev = vcc;
+	} else {
+		if (nodev_vccs)
+			nodev_vccs->prev = vcc;
 		vcc->next = nodev_vccs;
 		vcc->prev = NULL;
 		nodev_vccs = vcc;
 	}
 }
 
-
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
 EXPORT_SYMBOL(atm_find_dev);
diff -urN linux-2.4.19-pre4/net/core/Makefile linux-2.4.19-pre5/net/core/Makefile
--- linux-2.4.19-pre4/net/core/Makefile	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/core/Makefile	Fri Mar 29 14:50:08 2002
@@ -27,5 +27,8 @@
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PROFILE) += profile.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
+obj-$(CONFIG_NET_RADIO) += wireless.o
+# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
+obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.19-pre4/net/core/dev.c linux-2.4.19-pre5/net/core/dev.c
--- linux-2.4.19-pre4/net/core/dev.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/core/dev.c	Fri Mar 29 14:50:08 2002
@@ -102,6 +102,7 @@
 #include <linux/module.h>
 #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
+#include <net/iw_handler.h>
 #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
 #ifdef CONFIG_PLIP
 extern int plip_init(void);
@@ -1796,122 +1797,6 @@
 #endif	/* CONFIG_PROC_FS */
 
 
-#ifdef WIRELESS_EXT
-#ifdef CONFIG_PROC_FS
-
-/*
- * Print one entry of /proc/net/wireless
- * This is a clone of /proc/net/dev (just above)
- */
-static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = (dev->get_wireless_stats ?
-				       dev->get_wireless_stats(dev) :
-				       (struct iw_statistics *) NULL);
-	int size;
-
-	if (stats != (struct iw_statistics *) NULL) {
-		size = sprintf(buffer,
-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
-			       dev->name,
-			       stats->status,
-			       stats->qual.qual,
-			       stats->qual.updated & 1 ? '.' : ' ',
-			       stats->qual.level,
-			       stats->qual.updated & 2 ? '.' : ' ',
-			       stats->qual.noise,
-			       stats->qual.updated & 4 ? '.' : ' ',
-			       stats->discard.nwid,
-			       stats->discard.code,
-			       stats->discard.fragment,
-			       stats->discard.retries,
-			       stats->discard.misc,
-			       stats->miss.beacon);
-		stats->qual.updated = 0;
-	}
-	else
-		size = 0;
-
-	return size;
-}
-
-/*
- * Print info for /proc/net/wireless (print all entries)
- * This is a clone of /proc/net/dev (just above)
- */
-static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-			  int length)
-{
-	int		len = 0;
-	off_t		begin = 0;
-	off_t		pos = 0;
-	int		size;
-	
-	struct net_device *	dev;
-
-	size = sprintf(buffer,
-		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
-		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
-			);
-	
-	pos += size;
-	len += size;
-
-	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		size = sprintf_wireless_stats(buffer + len, dev);
-		len += size;
-		pos = begin + len;
-
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-		if (pos > offset + length)
-			break;
-	}
-	read_unlock(&dev_base_lock);
-
-	*start = buffer + (offset - begin);	/* Start of wanted data */
-	len -= (offset - begin);		/* Start slop */
-	if (len > length)
-		len = length;			/* Ending slop */
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-#endif	/* CONFIG_PROC_FS */
-
-/*
- *	Allow programatic access to /proc/net/wireless even if /proc
- *	doesn't exist... Also more efficient...
- */
-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = (dev->get_wireless_stats ?
-				       dev->get_wireless_stats(dev) :
-				       (struct iw_statistics *) NULL);
-
-	if (stats != (struct iw_statistics *) NULL) {
-		struct iwreq *	wrq = (struct iwreq *)ifr;
-
-		/* Copy statistics to the user buffer */
-		if(copy_to_user(wrq->u.data.pointer, stats,
-				sizeof(struct iw_statistics)))
-			return -EFAULT;
-
-		/* Check if we need to clear the update flag */
-		if(wrq->u.data.flags != 0)
-			stats->qual.updated = 0;
-		return(0);
-	} else
-		return -EOPNOTSUPP;
-}
-#endif	/* WIRELESS_EXT */
-
 /**
  *	netdev_set_master	-	set up master/slave pair
  *	@slave: slave device
@@ -2209,11 +2094,6 @@
 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
 			return 0;
 
-#ifdef WIRELESS_EXT
-		case SIOCGIWSTATS:
-			return dev_iwstats(dev, ifr);
-#endif	/* WIRELESS_EXT */
-
 		/*
 		 *	Unknown or private ioctl
 		 */
@@ -2239,17 +2119,6 @@
 				return -EOPNOTSUPP;
 			}
 
-#ifdef WIRELESS_EXT
-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				if (dev->do_ioctl) {
-					if (!netif_device_present(dev))
-						return -ENODEV;
-					return dev->do_ioctl(dev, ifr, cmd);
-				}
-				return -EOPNOTSUPP;
-			}
-#endif	/* WIRELESS_EXT */
-
 	}
 	return -EINVAL;
 }
@@ -2431,7 +2300,8 @@
 				}
 				dev_load(ifr.ifr_name);
 				rtnl_lock();
-				ret = dev_ifsioc(&ifr, cmd);
+				/* Follow me in net/core/wireless.c */
+				ret = wireless_process_ioctl(&ifr, cmd);
 				rtnl_unlock();
 				if (!ret && IW_IS_GET(cmd) &&
 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
@@ -2856,6 +2726,7 @@
 	proc_net_create("dev", 0, dev_get_info);
 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
 #ifdef WIRELESS_EXT
+	/* Available in net/core/wireless.c */
 	proc_net_create("wireless", 0, dev_get_wireless_info);
 #endif	/* WIRELESS_EXT */
 #endif	/* CONFIG_PROC_FS */
diff -urN linux-2.4.19-pre4/net/core/neighbour.c linux-2.4.19-pre5/net/core/neighbour.c
--- linux-2.4.19-pre4/net/core/neighbour.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/core/neighbour.c	Fri Mar 29 14:50:08 2002
@@ -1239,6 +1239,7 @@
 	read_lock(&neigh_tbl_lock);
 	for (tbl=neigh_tables; tbl; tbl = tbl->next) {
 		int err = 0;
+		int override = 1;
 		struct neighbour *n;
 
 		if (tbl->family != ndm->ndm_family)
@@ -1266,6 +1267,7 @@
 		if (n) {
 			if (nlh->nlmsg_flags&NLM_F_EXCL)
 				err = -EEXIST;
+			override = nlh->nlmsg_flags&NLM_F_REPLACE;
 		} else if (!(nlh->nlmsg_flags&NLM_F_CREATE))
 			err = -ENOENT;
 		else {
@@ -1278,7 +1280,7 @@
 		if (err == 0) {
 			err = neigh_update(n, nda[NDA_LLADDR-1] ? RTA_DATA(nda[NDA_LLADDR-1]) : NULL,
 					   ndm->ndm_state,
-					   nlh->nlmsg_flags&NLM_F_REPLACE, 0);
+					   override, 0);
 		}
 		if (n)
 			neigh_release(n);
diff -urN linux-2.4.19-pre4/net/core/skbuff.c linux-2.4.19-pre5/net/core/skbuff.c
--- linux-2.4.19-pre4/net/core/skbuff.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/core/skbuff.c	Fri Mar 29 14:50:08 2002
@@ -748,7 +748,7 @@
 			if (skb_cloned(skb)) {
 				if (!realloc)
 					BUG();
-				if (!pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
 					return -ENOMEM;
 			}
 			if (len <= offset) {
diff -urN linux-2.4.19-pre4/net/core/wireless.c linux-2.4.19-pre5/net/core/wireless.c
--- linux-2.4.19-pre4/net/core/wireless.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre5/net/core/wireless.c	Fri Mar 29 14:50:08 2002
@@ -0,0 +1,733 @@
+/*
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/************************** DOCUMENTATION **************************/
+/*
+ * API definition :
+ * --------------
+ * See <linux/wireless.h> for details of the APIs and the rest.
+ *
+ * History :
+ * -------
+ *
+ * v1 - 5.12.01 - Jean II
+ *	o Created this file.
+ *
+ * v2 - 13.12.01 - Jean II
+ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
+ *	o Make Wireless Extension IOCTLs go through here
+ *	o Added iw_handler handling ;-)
+ *	o Added standard ioctl description
+ *	o Initial dumb commit strategy based on orinoco.c
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <asm/uaccess.h>		/* copy_to_user() */
+#include <linux/config.h>		/* Not needed ??? */
+#include <linux/types.h>		/* off_t */
+#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+
+#include <linux/wireless.h>		/* Pretty obvious */
+#include <net/iw_handler.h>		/* New driver API */
+
+/**************************** CONSTANTS ****************************/
+
+/* This will be turned on later on... */
+#undef WE_STRICT_WRITE		/* Check write buffer size */
+
+/* Debuging stuff */
+#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+
+/************************* GLOBAL VARIABLES *************************/
+/*
+ * You should not use global variables, because or re-entrancy.
+ * On our case, it's only const, so it's OK...
+ */
+static const struct iw_ioctl_description	standard_ioctl[] = {
+	/* SIOCSIWCOMMIT (internal) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWNAME */
+	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWNWID */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWNWID */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWFREQ */
+	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWFREQ */
+	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWMODE */
+	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWMODE */
+	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWSENS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWSENS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRANGE */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWRANGE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWPRIV */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWPRIV (handled directly by us) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWSTATS */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWSTATS (handled directly by us) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWSPY */
+	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+	/* SIOCGIWSPY */
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWAP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* SIOCGIWAP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWAPLIST */
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWESSID */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWESSID */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWNICKN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	/* SIOCGIWNICKN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWRATE */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRATE */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRTS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRTS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWFRAG */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWFRAG */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWTXPOW */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWTXPOW */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRETRY */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRETRY */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWENCODE */
+	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+	/* SIOCGIWENCODE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+	/* SIOCSIWPOWER */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWPOWER */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+};
+
+/* Size (in bytes) of the various private data types */
+char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+
+/************************ COMMON SUBROUTINES ************************/
+/*
+ * Stuff that may be used in various place or doesn't fit in one
+ * of the section below.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the driver handler associated with a specific Wireless Extension.
+ * Called from various place, so make sure it remains efficient.
+ */
+static inline iw_handler get_handler(struct net_device *dev,
+				     unsigned int cmd)
+{
+	unsigned int	index;		/* MUST be unsigned */
+
+	/* Check if we have some wireless handlers defined */
+	if(dev->wireless_handlers == NULL)
+		return NULL;
+
+	/* Try as a standard command */
+	index = cmd - SIOCIWFIRST;
+	if(index < dev->wireless_handlers->num_standard)
+		return dev->wireless_handlers->standard[index];
+
+	/* Try as a private command */
+	index = cmd - SIOCIWFIRSTPRIV;
+	if(index < dev->wireless_handlers->num_private)
+		return dev->wireless_handlers->private[index];
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Get statistics out of the driver
+ */
+static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
+{
+	return (dev->get_wireless_stats ?
+		dev->get_wireless_stats(dev) :
+		(struct iw_statistics *) NULL);
+	/* In the future, get_wireless_stats may move from 'struct net_device'
+	 * to 'struct iw_handler_def', to de-bloat struct net_device.
+	 * Definitely worse a thought... */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
+ *
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
+ */
+static inline int call_commit_handler(struct net_device *	dev)
+{
+	if((netif_running(dev)) &&
+	   (dev->wireless_handlers->standard[0] != NULL)) {
+		/* Call the commit handler on the driver */
+		return dev->wireless_handlers->standard[0](dev, NULL,
+							   NULL, NULL);
+	} else
+		return 0;		/* Command completed successfully */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Number of private arguments
+ */
+static inline int get_priv_size(__u16	args)
+{
+	int	num = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	return num * priv_type_size[type];
+}
+
+
+/******************** /proc/net/wireless SUPPORT ********************/
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print one entry (line) of /proc/net/wireless
+ */
+static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+	int size;
+
+	stats = get_wireless_stats(dev);
+	if (stats != (struct iw_statistics *) NULL) {
+		size = sprintf(buffer,
+			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
+			       dev->name,
+			       stats->status,
+			       stats->qual.qual,
+			       stats->qual.updated & 1 ? '.' : ' ',
+			       stats->qual.level,
+			       stats->qual.updated & 2 ? '.' : ' ',
+			       stats->qual.noise,
+			       stats->qual.updated & 4 ? '.' : ' ',
+			       stats->discard.nwid,
+			       stats->discard.code,
+			       stats->discard.fragment,
+			       stats->discard.retries,
+			       stats->discard.misc,
+			       stats->miss.beacon);
+		stats->qual.updated = 0;
+	}
+	else
+		size = 0;
+
+	return size;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+			  int length)
+{
+	int		len = 0;
+	off_t		begin = 0;
+	off_t		pos = 0;
+	int		size;
+	
+	struct net_device *	dev;
+
+	size = sprintf(buffer,
+		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
+			);
+	
+	pos += size;
+	len += size;
+
+	read_lock(&dev_base_lock);
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		size = sprintf_wireless_stats(buffer + len, dev);
+		len += size;
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if (pos > offset + length)
+			break;
+	}
+	read_unlock(&dev_base_lock);
+
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);		/* Start slop */
+	if (len > length)
+		len = length;			/* Ending slop */
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif	/* CONFIG_PROC_FS */
+
+/************************** IOCTL SUPPORT **************************/
+/*
+ * The original user space API to configure all those Wireless Extensions
+ * is through IOCTLs.
+ * In there, we check if we need to call the new driver API (iw_handler)
+ * or just call the driver ioctl handler.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ *	Allow programatic access to /proc/net/wireless even if /proc
+ *	doesn't exist... Also more efficient...
+ */
+static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+
+	stats = get_wireless_stats(dev);
+	if (stats != (struct iw_statistics *) NULL) {
+		struct iwreq *	wrq = (struct iwreq *)ifr;
+
+		/* Copy statistics to the user buffer */
+		if(copy_to_user(wrq->u.data.pointer, stats,
+				sizeof(struct iw_statistics)))
+			return -EFAULT;
+
+		/* Check if we need to clear the update flag */
+		if(wrq->u.data.flags != 0)
+			stats->qual.updated = 0;
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Export the driver private handler definition
+ * They will be picked up by tools like iwpriv...
+ */
+static inline int ioctl_export_private(struct net_device *	dev,
+				       struct ifreq *		ifr)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+
+	/* Check if the driver has something to export */
+	if((dev->wireless_handlers->num_private_args == 0) ||
+	   (dev->wireless_handlers->private_args == NULL))
+		return -EOPNOTSUPP;
+
+	/* Check NULL pointer */
+	if(iwr->u.data.pointer == NULL)
+		return -EFAULT;
+#ifdef WE_STRICT_WRITE
+	/* Check if there is enough buffer up there */
+	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+		return -E2BIG;
+#endif	/* WE_STRICT_WRITE */
+
+	/* Set the number of available ioctls. */
+	iwr->u.data.length = dev->wireless_handlers->num_private_args;
+
+	/* Copy structure to the user buffer. */
+	if (copy_to_user(iwr->u.data.pointer,
+			 dev->wireless_handlers->private_args,
+			 sizeof(struct iw_priv_args) * iwr->u.data.length))
+		return -EFAULT;
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static inline int ioctl_standard_call(struct net_device *	dev,
+				      struct ifreq *		ifr,
+				      unsigned int		cmd,
+				      iw_handler		handler)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+	const struct iw_ioctl_description *	descr;
+	struct iw_request_info			info;
+	int					ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+#ifdef WE_IOCTL_DEBUG
+	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
+	       ifr->ifr_name, cmd);
+	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+#endif	/* WE_IOCTL_DEBUG */
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not */
+	if(descr->header_type != IW_HEADER_TYPE_POINT) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), NULL);
+	} else {
+		char *	extra;
+		int	err;
+
+		/* Check what user space is giving us */
+		if(IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+			/* Check if number of token fits within bounds */
+			if(iwr->u.data.length > descr->max_tokens)
+				return -E2BIG;
+			if(iwr->u.data.length < descr->min_tokens)
+				return -EINVAL;
+		} else {
+			/* Check NULL pointer */
+			if(iwr->u.data.pointer == NULL)
+				return -EFAULT;
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(iwr->u.data.length < descr->max_tokens)
+				return -E2BIG;
+#endif	/* WE_STRICT_WRITE */
+		}
+
+#ifdef WE_IOCTL_DEBUG
+		printk(KERN_DEBUG "Malloc %d bytes\n",
+		       descr->max_tokens * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(descr->max_tokens * descr->token_size,
+				GFP_KERNEL);
+		if (extra == NULL) {
+			return -ENOMEM;
+		}
+
+		/* If it is a SET, get all the extra data in here */
+		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     iwr->u.data.length *
+					     descr->token_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Got %d bytes\n",
+			       iwr->u.data.length * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   iwr->u.data.length *
+					   descr->token_size);
+			if (err)
+				ret =  -EFAULT;				   
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Wrote %d bytes\n",
+			       iwr->u.data.length * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+	/* Call commit handler if needed and defined */
+	if(ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	/* Here, we will generate the appropriate event if needed */
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static inline int ioctl_private_call(struct net_device *	dev,
+				     struct ifreq *		ifr,
+				     unsigned int		cmd,
+				     iw_handler		handler)
+{
+	struct iwreq *			iwr = (struct iwreq *) ifr;
+	struct iw_priv_args *		descr = NULL;
+	struct iw_request_info		info;
+	int				extra_size = 0;
+	int				i;
+	int				ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
+		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
+			descr = &(dev->wireless_handlers->private_args[i]);
+			break;
+		}
+
+#ifdef WE_IOCTL_DEBUG
+	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
+	       ifr->ifr_name, cmd);
+	if(descr) {
+		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
+		       descr->name, descr->set_args, descr->get_args);
+	}
+#endif	/* WE_IOCTL_DEBUG */
+
+	/* Compute the size of the set/get arguments */
+	if(descr != NULL) {
+		if(IW_IS_SET(cmd)) {
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->set_args);
+
+			/* Does it fits in iwr ? */
+			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size < IFNAMSIZ))
+				extra_size = 0;
+		} else {
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->get_args);
+
+			/* Does it fits in iwr ? */
+			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size < IFNAMSIZ))
+				extra_size = 0;
+		}
+	}
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not. */
+	if(extra_size == 0) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+	} else {
+		char *	extra;
+		int	err;
+
+		/* Check what user space is giving us */
+		if(IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+
+			/* Does it fits within bounds ? */
+			if(iwr->u.data.length > (descr->set_args &
+						 IW_PRIV_SIZE_MASK))
+				return -E2BIG;
+		} else {
+			/* Check NULL pointer */
+			if(iwr->u.data.pointer == NULL)
+				return -EFAULT;
+		}
+
+#ifdef WE_IOCTL_DEBUG
+		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
+#endif	/* WE_IOCTL_DEBUG */
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL) {
+			return -ENOMEM;
+		}
+
+		/* If it is a SET, get all the extra data in here */
+		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     extra_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   extra_size);
+			if (err)
+				ret =  -EFAULT;				   
+#ifdef WE_IOCTL_DEBUG
+			printk(KERN_DEBUG "Wrote %d elem\n",
+			       iwr->u.data.length);
+#endif	/* WE_IOCTL_DEBUG */
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+
+	/* Call commit handler if needed and defined */
+	if(ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main IOCTl dispatcher. Called from the main networking code
+ * (dev_ioctl() in net/core/dev.c).
+ * Check the type of IOCTL and call the appropriate wrapper...
+ */
+int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+	struct net_device *dev;
+	iw_handler	handler;
+
+	/* Permissions are already checked in dev_ioctl() before calling us.
+	 * The copy_to/from_user() of ifr is also dealt with in there */
+
+	/* Make sure the device exist */
+	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+		return -ENODEV;
+
+	/* A bunch of special cases, then the generic case...
+	 * Note that 'cmd' is already filtered in dev_ioctl() with
+	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
+	switch(cmd) 
+	{
+		case SIOCGIWSTATS:
+			/* Get Wireless Stats */
+			return dev_iwstats(dev, ifr);
+
+		case SIOCGIWPRIV:
+			/* Check if we have some wireless handlers defined */
+			if(dev->wireless_handlers != NULL) {
+				/* We export to user space the definition of
+				 * the private handler ourselves */
+				return ioctl_export_private(dev, ifr);
+			}
+			// ## Fall-through for old API ##
+		default:
+			/* Generic IOCTL */
+			/* Basic check */
+			if (!netif_device_present(dev))
+				return -ENODEV;
+			/* New driver API : try to find the handler */
+			handler = get_handler(dev, cmd);
+			if(handler != NULL) {
+				/* Standard and private are not the same */
+				if(cmd < SIOCIWFIRSTPRIV)
+					return ioctl_standard_call(dev,
+								   ifr,
+								   cmd,
+								   handler);
+				else
+					return ioctl_private_call(dev,
+								  ifr,
+								  cmd,
+								  handler);
+			}
+			/* Old driver API : call driver ioctl handler */
+			if (dev->do_ioctl) {
+				return dev->do_ioctl(dev, ifr, cmd);
+			}
+			return -EOPNOTSUPP;
+	}
+	/* Not reached */
+	return -EINVAL;
+}
diff -urN linux-2.4.19-pre4/net/ipv4/af_inet.c linux-2.4.19-pre5/net/ipv4/af_inet.c
--- linux-2.4.19-pre4/net/ipv4/af_inet.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/ipv4/af_inet.c	Fri Mar 29 14:50:08 2002
@@ -620,13 +620,6 @@
 		if (sk->state != TCP_CLOSE) 
 			goto out;
 
-		err = -EAGAIN;
-		if (sk->num == 0) {
-			if (sk->prot->get_port(sk, 0) != 0)
-				goto out;
-			sk->sport = htons(sk->num);
-		}
-
 		err = sk->prot->connect(sk, uaddr, addr_len);
 		if (err < 0)
 			goto out;
diff -urN linux-2.4.19-pre4/net/ipv4/arp.c linux-2.4.19-pre5/net/ipv4/arp.c
--- linux-2.4.19-pre4/net/ipv4/arp.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/ipv4/arp.c	Fri Mar 29 14:50:08 2002
@@ -450,6 +450,32 @@
 }
 
 /*
+ * Check if we can use proxy ARP for this path
+ */
+
+static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
+{
+	struct in_device *out_dev;
+	int imi, omi = -1;
+
+	if (!IN_DEV_PROXY_ARP(in_dev))
+		return 0;
+
+	if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)
+		return 1;
+	if (imi == -1)
+		return 0;
+
+	/* place to check for proxy_arp for routes */
+
+	if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
+		omi = IN_DEV_MEDIUM_ID(out_dev);
+		in_dev_put(out_dev);
+	}
+	return (omi != imi && omi != -1);
+}
+
+/*
  *	Interface to link layer: send routine and receive handler.
  */
 
@@ -755,7 +781,7 @@
 		} else if (IN_DEV_FORWARD(in_dev)) {
 			if ((rt->rt_flags&RTCF_DNAT) ||
 			    (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
-			     (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
+			     (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
 				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 				if (n)
 					neigh_release(n);
diff -urN linux-2.4.19-pre4/net/ipv4/devinet.c linux-2.4.19-pre5/net/ipv4/devinet.c
--- linux-2.4.19-pre4/net/ipv4/devinet.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/ipv4/devinet.c	Fri Mar 29 14:50:08 2002
@@ -1032,7 +1032,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[14];
+	ctl_table devinet_vars[15];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1066,6 +1066,9 @@
 	{NET_IPV4_CONF_PROXY_ARP, "proxy_arp",
          &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,
          &proc_dointvec},
+	{NET_IPV4_CONF_MEDIUM_ID, "medium_id",
+         &ipv4_devconf.medium_id, sizeof(int), 0644, NULL,
+         &proc_dointvec},
 	{NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",
          &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,
          &proc_dointvec},
diff -urN linux-2.4.19-pre4/net/ipv4/fib_frontend.c linux-2.4.19-pre5/net/ipv4/fib_frontend.c
--- linux-2.4.19-pre4/net/ipv4/fib_frontend.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/ipv4/fib_frontend.c	Fri Mar 29 14:50:08 2002
@@ -579,6 +579,9 @@
 	switch (event) {
 	case NETDEV_UP:
 		fib_add_ifaddr(ifa);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+		fib_sync_up(ifa->ifa_dev->dev);
+#endif
 		rt_cache_flush(-1);
 		break;
 	case NETDEV_DOWN:
diff -urN linux-2.4.19-pre4/net/ipv4/fib_semantics.c linux-2.4.19-pre5/net/ipv4/fib_semantics.c
--- linux-2.4.19-pre4/net/ipv4/fib_semantics.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv4/fib_semantics.c	Fri Mar 29 14:50:08 2002
@@ -56,6 +56,8 @@
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 
+static spinlock_t fib_multipath_lock = SPIN_LOCK_UNLOCKED;
+
 #define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
 for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
@@ -869,8 +871,14 @@
 					 nh->nh_scope != scope) {
 					nh->nh_flags |= RTNH_F_DEAD;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
+					spin_lock_bh(&fib_multipath_lock);
 					fi->fib_power -= nh->nh_power;
 					nh->nh_power = 0;
+					spin_unlock_bh(&fib_multipath_lock);
+					if (force && nh->nh_dev) {
+						dev_put(nh->nh_dev);
+						nh->nh_dev = NULL;
+					}
 #endif
 					dead++;
 				}
@@ -906,13 +914,19 @@
 				alive++;
 				continue;
 			}
+			if (nh->nh_dev == NULL && nh->nh_oif == dev->ifindex) {
+				dev_hold(dev);
+				nh->nh_dev = dev;
+			}
 			if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
 				continue;
 			if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
 				continue;
 			alive++;
+			spin_lock_bh(&fib_multipath_lock);
 			nh->nh_power = 0;
 			nh->nh_flags &= ~RTNH_F_DEAD;
+			spin_unlock_bh(&fib_multipath_lock);
 		} endfor_nexthops(fi)
 
 		if (alive > 0) {
@@ -933,6 +947,7 @@
 	struct fib_info *fi = res->fi;
 	int w;
 
+	spin_lock_bh(&fib_multipath_lock);
 	if (fi->fib_power <= 0) {
 		int power = 0;
 		change_nexthops(fi) {
@@ -942,12 +957,12 @@
 			}
 		} endfor_nexthops(fi);
 		fi->fib_power = power;
-#if 1
 		if (power <= 0) {
-			printk(KERN_CRIT "impossible 777\n");
+			spin_unlock_bh(&fib_multipath_lock);
+			/* Race condition: route has just become dead. */
+			res->nh_sel = 0;
 			return;
 		}
-#endif
 	}
 
 
@@ -963,15 +978,15 @@
 				nh->nh_power--;
 				fi->fib_power--;
 				res->nh_sel = nhsel;
+				spin_unlock_bh(&fib_multipath_lock);
 				return;
 			}
 		}
 	} endfor_nexthops(fi);
 
-#if 1
-	printk(KERN_CRIT "impossible 888\n");
-#endif
-	return;
+	/* Race condition: route has just become dead. */
+	res->nh_sel = 0;
+	spin_unlock_bh(&fib_multipath_lock);
 }
 #endif
 
diff -urN linux-2.4.19-pre4/net/ipv4/icmp.c linux-2.4.19-pre5/net/ipv4/icmp.c
--- linux-2.4.19-pre4/net/ipv4/icmp.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv4/icmp.c	Fri Mar 29 14:50:08 2002
@@ -139,6 +139,8 @@
   { EHOSTUNREACH,	1 }	/*	ICMP_PREC_CUTOFF	*/
 };
 
+extern int sysctl_ip_default_ttl;
+
 /* Control parameters for ECHO replies. */
 int sysctl_icmp_echo_ignore_all;
 int sysctl_icmp_echo_ignore_broadcasts;
@@ -354,6 +356,7 @@
 	icmp_out_count(icmp_param->data.icmph.type);
 
 	sk->protinfo.af_inet.tos = skb->nh.iph->tos;
+	sk->protinfo.af_inet.ttl = sysctl_ip_default_ttl;
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
 	if (icmp_param->replyopts.optlen) {
@@ -498,6 +501,7 @@
 	icmp_param.offset=skb_in->nh.raw - skb_in->data;
 	icmp_out_count(icmp_param.data.icmph.type);
 	icmp_socket->sk->protinfo.af_inet.tos = tos;
+	icmp_socket->sk->protinfo.af_inet.ttl = sysctl_ip_default_ttl;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
 	if (icmp_param.replyopts.srr) {
@@ -876,7 +880,7 @@
  
 int icmp_rcv(struct sk_buff *skb)
 {
-	struct icmphdr *icmph = skb->h.icmph;
+	struct icmphdr *icmph;
 	struct rtable *rt = (struct rtable*)skb->dst;
 
 	ICMP_INC_STATS_BH(IcmpInMsgs);
@@ -895,6 +899,8 @@
 	if (!pskb_pull(skb, sizeof(struct icmphdr)))
 		goto error;
 
+	icmph = skb->h.icmph;
+
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
diff -urN linux-2.4.19-pre4/net/ipv4/ip_gre.c linux-2.4.19-pre5/net/ipv4/ip_gre.c
--- linux-2.4.19-pre4/net/ipv4/ip_gre.c	Tue Oct 30 15:08:12 2001
+++ linux-2.4.19-pre5/net/ipv4/ip_gre.c	Fri Mar 29 14:50:08 2002
@@ -760,7 +760,10 @@
 	}
 
 	df = tiph->frag_off;
-	mtu = rt->u.dst.pmtu - tunnel->hlen;
+	if (df)
+		mtu = rt->u.dst.pmtu - tunnel->hlen;
+	else
+		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
 
 	if (skb->protocol == __constant_htons(ETH_P_IP)) {
 		if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68)
diff -urN linux-2.4.19-pre4/net/ipv4/ip_input.c linux-2.4.19-pre5/net/ipv4/ip_input.c
--- linux-2.4.19-pre4/net/ipv4/ip_input.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv4/ip_input.c	Fri Mar 29 14:50:08 2002
@@ -224,8 +224,6 @@
 	nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
-	if (!pskb_may_pull(skb, ihl))
-		goto out;
 	__skb_pull(skb, ihl);
 
 #ifdef CONFIG_NETFILTER
@@ -279,7 +277,6 @@
 			sock_put(raw_sk);
 		} else if (!flag) {		/* Free and report errors */
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	
-out:
 			kfree_skb(skb);
 		}
 	}
@@ -346,7 +343,6 @@
 			goto drop;
 		iph = skb->nh.iph;
 
-		skb->ip_summed = 0;
 		if (ip_options_compile(NULL, skb))
 			goto inhdr_error;
 
diff -urN linux-2.4.19-pre4/net/ipv4/ipip.c linux-2.4.19-pre5/net/ipv4/ipip.c
--- linux-2.4.19-pre4/net/ipv4/ipip.c	Wed Oct 17 14:16:39 2001
+++ linux-2.4.19-pre5/net/ipv4/ipip.c	Fri Mar 29 14:50:08 2002
@@ -572,7 +572,11 @@
 		goto tx_error;
 	}
 
-	mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	if (tiph->frag_off)
+		mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	else
+		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
+
 	if (mtu < 68) {
 		tunnel->stat.collisions++;
 		ip_rt_put(rt);
diff -urN linux-2.4.19-pre4/net/ipv4/netfilter/Config.in linux-2.4.19-pre5/net/ipv4/netfilter/Config.in
--- linux-2.4.19-pre4/net/ipv4/netfilter/Config.in	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/ipv4/netfilter/Config.in	Fri Mar 29 14:50:08 2002
@@ -47,7 +47,7 @@
       define_bool CONFIG_IP_NF_NAT_NEEDED y
       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
-      bool '    NAT of local connections' CONFIG_IP_NF_NAT_LOCAL
+      bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
       fi
diff -urN linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_core.c	Tue Aug  7 08:30:50 2001
+++ linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_core.c	Fri Mar 29 14:50:08 2002
@@ -175,6 +175,7 @@
 destroy_conntrack(struct nf_conntrack *nfct)
 {
 	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
+	struct ip_conntrack_protocol *proto;
 
 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
@@ -182,6 +183,13 @@
 	if (ct->master.master)
 		nf_conntrack_put(&ct->master);
 
+	/* To make sure we don't get any weird locking issues here:
+	 * destroy_conntrack() MUST NOT be called with a write lock
+	 * to ip_conntrack_lock!!! -HW */
+	proto = find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+	if (proto && proto->destroy)
+		proto->destroy(ct);
+
 	if (ip_conntrack_destroyed)
 		ip_conntrack_destroyed(ct);
 	kmem_cache_free(ip_conntrack_cachep, ct);
diff -urN linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Apr 27 14:15:01 2001
+++ linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Mar 29 14:50:08 2002
@@ -57,5 +57,5 @@
 struct ip_conntrack_protocol ip_conntrack_generic_protocol
 = { { NULL, NULL }, 0, "unknown",
     generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
-    generic_print_conntrack, established, new, NULL };
+    generic_print_conntrack, established, new, NULL, NULL };
 
diff -urN linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Apr 27 14:15:01 2001
+++ linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Mar 29 14:50:08 2002
@@ -113,4 +113,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_icmp
 = { { NULL, NULL }, IPPROTO_ICMP, "icmp",
     icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
-    icmp_print_conntrack, icmp_packet, icmp_new, NULL };
+    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL };
diff -urN linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Apr 27 14:15:01 2001
+++ linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Mar 29 14:50:08 2002
@@ -230,4 +230,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
 = { { NULL, NULL }, IPPROTO_TCP, "tcp",
     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
-    tcp_packet, tcp_new, NULL };
+    tcp_packet, tcp_new, NULL, NULL };
diff -urN linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.4.19-pre4/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Apr 27 14:15:01 2001
+++ linux-2.4.19-pre5/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Mar 29 14:50:08 2002
@@ -71,4 +71,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_udp
 = { { NULL, NULL }, IPPROTO_UDP, "udp",
     udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
-    udp_packet, udp_new, NULL };
+    udp_packet, udp_new, NULL, NULL };
diff -urN linux-2.4.19-pre4/net/ipv4/route.c linux-2.4.19-pre5/net/ipv4/route.c
--- linux-2.4.19-pre4/net/ipv4/route.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv4/route.c	Fri Mar 29 14:50:08 2002
@@ -583,7 +583,7 @@
 	if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
 		goto out;
 	if (net_ratelimit())
-		printk("dst cache overflow\n");
+		printk(KERN_WARNING "dst cache overflow\n");
 	return 1;
 
 work_done:
@@ -657,7 +657,7 @@
 			}
 
 			if (net_ratelimit())
-				printk("Neighbour table overflow.\n");
+				printk(KERN_WARNING "Neighbour table overflow.\n");
 			rt_drop(rt);
 			return -ENOBUFS;
 		}
@@ -667,8 +667,8 @@
 #if RT_CACHE_DEBUG >= 2
 	if (rt->u.rt_next) {
 		struct rtable *trt;
-		printk("rt_cache @%02x: %u.%u.%u.%u", hash,
-				NIPQUAD(rt->rt_dst));
+		printk(KERN_DEBUG "rt_cache @%02x: %u.%u.%u.%u", hash,
+		       NIPQUAD(rt->rt_dst));
 		for (trt = rt->u.rt_next; trt; trt = trt->u.rt_next)
 			printk(" . %u.%u.%u.%u", NIPQUAD(trt->rt_dst));
 		printk("\n");
@@ -2454,7 +2454,7 @@
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	for (order = 0;
-	     (PAGE_SIZE << order) < 256 * sizeof(ip_rt_acct) * NR_CPUS; order++)
+	     (PAGE_SIZE << order) < 256 * sizeof(struct ip_rt_acct) * NR_CPUS; order++)
 		/* NOTHING */;
 	ip_rt_acct = (struct ip_rt_acct *)__get_free_pages(GFP_KERNEL, order);
 	if (!ip_rt_acct)
@@ -2487,7 +2487,7 @@
 	if (!rt_hash_table)
 		panic("Failed to allocate IP route cache hash table\n");
 
-	printk("IP: routing cache hash table of %u buckets, %ldKbytes\n",
+	printk(KERN_INFO "IP: routing cache hash table of %u buckets, %ldKbytes\n",
 	       rt_hash_mask,
 	       (long) (rt_hash_mask * sizeof(struct rt_hash_bucket)) / 1024);
 
diff -urN linux-2.4.19-pre4/net/ipv4/sysctl_net_ipv4.c linux-2.4.19-pre5/net/ipv4/sysctl_net_ipv4.c
--- linux-2.4.19-pre4/net/ipv4/sysctl_net_ipv4.c	Tue Oct 30 15:08:12 2001
+++ linux-2.4.19-pre5/net/ipv4/sysctl_net_ipv4.c	Fri Mar 29 14:50:08 2002
@@ -219,6 +219,8 @@
 	 &sysctl_icmp_ratelimit, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_IPV4_ICMP_RATEMASK, "icmp_ratemask",
 	 &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_TW_REUSE, "tcp_tw_reuse",
+	 &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -urN linux-2.4.19-pre4/net/ipv4/tcp.c linux-2.4.19-pre5/net/ipv4/tcp.c
--- linux-2.4.19-pre4/net/ipv4/tcp.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/ipv4/tcp.c	Fri Mar 29 14:50:08 2002
@@ -1791,7 +1791,7 @@
 
 #ifdef TCP_DEBUG
 	if (sk->zapped) {
-		printk("TCP: double destroy sk=%p\n", sk);
+		printk(KERN_DEBUG "TCP: double destroy sk=%p\n", sk);
 		sock_hold(sk);
 	}
 	sk->zapped = 1;
@@ -2552,7 +2552,7 @@
 		sysctl_tcp_rmem[2] = 2*43689;
 	}
 
-	printk("TCP: Hash tables configured (established %d bind %d)\n",
+	printk(KERN_INFO "TCP: Hash tables configured (established %d bind %d)\n",
 	       tcp_ehash_size<<1, tcp_bhash_size);
 
 	tcpdiag_init();
diff -urN linux-2.4.19-pre4/net/ipv4/tcp_input.c linux-2.4.19-pre5/net/ipv4/tcp_input.c
--- linux-2.4.19-pre4/net/ipv4/tcp_input.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv4/tcp_input.c	Fri Mar 29 14:50:08 2002
@@ -124,9 +124,6 @@
 	len = skb->len;
 	if (len >= tp->ack.rcv_mss) {
 		tp->ack.rcv_mss = len;
-		/* Dubious? Rather, it is final cut. 8) */
-		if (tcp_flag_word(skb->h.th)&TCP_REMNANT)
-			tp->ack.pending |= TCP_ACK_PUSHED;
 	} else {
 		/* Otherwise, we make more careful check taking into account,
 		 * that SACKs block is variable.
@@ -461,7 +458,7 @@
 		if (after(tp->snd_una, tp->rtt_seq)) {
 			if (tp->mdev_max < tp->rttvar)
 				tp->rttvar -= (tp->rttvar-tp->mdev_max)>>2;
-			tp->rtt_seq = tp->snd_una;
+			tp->rtt_seq = tp->snd_nxt;
 			tp->mdev_max = TCP_RTO_MIN;
 		}
 	} else {
@@ -1763,6 +1760,7 @@
 			acked |= FLAG_DATA_ACKED;
 		} else {
 			acked |= FLAG_SYN_ACKED;
+			tp->retrans_stamp = 0;
 		}
 
 		if (sacked) {
@@ -3850,6 +3848,7 @@
 	switch (sk->state) {
 	case TCP_CLOSE_WAIT:
 	case TCP_CLOSING:
+	case TCP_LAST_ACK:
 		if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
 			break;
 	case TCP_FIN_WAIT1:
diff -urN linux-2.4.19-pre4/net/ipv4/tcp_ipv4.c linux-2.4.19-pre5/net/ipv4/tcp_ipv4.c
--- linux-2.4.19-pre4/net/ipv4/tcp_ipv4.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv4/tcp_ipv4.c	Fri Mar 29 14:50:08 2002
@@ -64,6 +64,8 @@
 #include <linux/ipsec.h>
 
 extern int sysctl_ip_dynaddr;
+extern int sysctl_ip_default_ttl;
+int sysctl_tcp_tw_reuse = 0;
 
 /* Check TCP sequence numbers in ICMP packets. */
 #define ICMP_MIN_LENGTH 8
@@ -162,23 +164,24 @@
 	local_bh_enable();
 }
 
-static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum) 
-{ 
-	sk->num = snum; 
+static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum)
+{
+	sk->num = snum;
 	if ((sk->bind_next = tb->owners) != NULL)
 		tb->owners->bind_pprev = &sk->bind_next;
 	tb->owners = sk;
 	sk->bind_pprev = &tb->owners;
 	sk->prev = (struct sock *) tb;
-} 
+}
 
 static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
-{ 
+{
 	struct sock *sk2 = tb->owners;
 	int sk_reuse = sk->reuse;
 	
 	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
 		if (sk != sk2 &&
+		    sk2->reuse <= 1 &&
 		    sk->bound_dev_if == sk2->bound_dev_if) {
 			if (!sk_reuse	||
 			    !sk2->reuse	||
@@ -190,8 +193,8 @@
 			}
 		}
 	}
-	return sk2 != NULL; 
-} 
+	return sk2 != NULL;
+}
 
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
@@ -244,12 +247,14 @@
 				break;
 	}
 	if (tb != NULL && tb->owners != NULL) {
-		if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+		if (sk->reuse > 1)
+			goto success;
+		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
-			ret = 1; 
+			ret = 1;
 			if (tcp_bind_conflict(sk, tb))
-				goto fail_unlock; 
+				goto fail_unlock;
 		}
 	}
 	ret = 1;
@@ -266,7 +271,7 @@
 		tb->fastreuse = 0;
 success:
 	if (sk->prev == NULL)
-		tcp_bind_hash(sk, tb, snum); 
+		tcp_bind_hash(sk, tb, snum);
 	BUG_TRAP(sk->prev == (struct sock *) tb);
  	ret = 0;
 
@@ -337,13 +342,13 @@
 	}
 }
 
-static __inline__ void __tcp_v4_hash(struct sock *sk)
+static __inline__ void __tcp_v4_hash(struct sock *sk, const int listen_possible)
 {
 	struct sock **skp;
 	rwlock_t *lock;
 
 	BUG_TRAP(sk->pprev==NULL);
-	if(sk->state == TCP_LISTEN) {
+	if(listen_possible && sk->state == TCP_LISTEN) {
 		skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 		lock = &tcp_lhash_lock;
 		tcp_listen_wlock();
@@ -358,7 +363,7 @@
 	sk->pprev = skp;
 	sock_prot_inc_use(sk->prot);
 	write_unlock(lock);
-	if (sk->state == TCP_LISTEN)
+	if (listen_possible && sk->state == TCP_LISTEN)
 		wake_up(&tcp_lhash_wait);
 }
 
@@ -366,7 +371,7 @@
 {
 	if (sk->state != TCP_CLOSE) {
 		local_bh_disable();
-		__tcp_v4_hash(sk);
+		__tcp_v4_hash(sk, 1);
 		local_bh_enable();
 	}
 }
@@ -375,6 +380,9 @@
 {
 	rwlock_t *lock;
 
+	if (!sk->pprev)
+		goto ende;
+
 	if (sk->state == TCP_LISTEN) {
 		local_bh_disable();
 		tcp_listen_wlock();
@@ -393,6 +401,8 @@
 		sock_prot_dec_use(sk->prot);
 	}
 	write_unlock_bh(lock);
+
+ ende:
 	if (sk->state == TCP_LISTEN)
 		wake_up(&tcp_lhash_wait);
 }
@@ -530,19 +540,21 @@
 					  skb->h.th->source);
 }
 
-static int tcp_v4_check_established(struct sock *sk)
+/* called with local bh disabled */
+static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
+				      struct tcp_tw_bucket **twp)
 {
 	u32 daddr = sk->rcv_saddr;
 	u32 saddr = sk->daddr;
 	int dif = sk->bound_dev_if;
 	TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
-	__u32 ports = TCP_COMBINED_PORTS(sk->dport, sk->num);
-	int hash = tcp_hashfn(daddr, sk->num, saddr, sk->dport);
+	__u32 ports = TCP_COMBINED_PORTS(sk->dport, lport);
+	int hash = tcp_hashfn(daddr, lport, saddr, sk->dport);
 	struct tcp_ehash_bucket *head = &tcp_ehash[hash];
 	struct sock *sk2, **skp;
 	struct tcp_tw_bucket *tw;
 
-	write_lock_bh(&head->lock);
+	write_lock(&head->lock);
 
 	/* Check TIME-WAIT sockets first. */
 	for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp) != NULL;
@@ -566,7 +578,9 @@
 			   fall back to VJ's scheme and use initial
 			   timestamp retrieved from peer table.
 			 */
-			if (tw->ts_recent_stamp) {
+			if (tw->ts_recent_stamp &&
+			    (!twp || (sysctl_tcp_tw_reuse &&
+				      xtime.tv_sec - tw->ts_recent_stamp > 1))) {
 				if ((tp->write_seq = tw->snd_nxt+65535+2) == 0)
 					tp->write_seq = 1;
 				tp->ts_recent = tw->ts_recent;
@@ -587,6 +601,10 @@
 	}
 
 unique:
+	/* Must record num and sport now. Otherwise we will see
+	 * in hash table socket with a funny identity. */
+	sk->num = lport;
+	sk->sport = htons(lport);
 	BUG_TRAP(sk->pprev==NULL);
 	if ((sk->next = *skp) != NULL)
 		(*skp)->pprev = &sk->next;
@@ -595,15 +613,16 @@
 	sk->pprev = skp;
 	sk->hashent = hash;
 	sock_prot_inc_use(sk->prot);
-	write_unlock_bh(&head->lock);
+	write_unlock(&head->lock);
 
-	if (tw) {
+	if (twp) {
+		*twp = tw;
+		NET_INC_STATS_BH(TimeWaitRecycled);
+	} else if (tw) {
 		/* Silly. Should hash-dance instead... */
-		local_bh_disable();
 		tcp_tw_deschedule(tw);
 		tcp_timewait_kill(tw);
 		NET_INC_STATS_BH(TimeWaitRecycled);
-		local_bh_enable();
 
 		tcp_tw_put(tw);
 	}
@@ -611,34 +630,120 @@
 	return 0;
 
 not_unique:
-	write_unlock_bh(&head->lock);
+	write_unlock(&head->lock);
 	return -EADDRNOTAVAIL;
 }
 
-/* Hash SYN-SENT socket to established hash table after
- * checking that it is unique. Note, that without kernel lock
- * we MUST make these two operations atomically.
- *
- * Optimization: if it is bound and tcp_bind_bucket has the only
- * owner (us), we need not to scan established bucket.
+/*
+ * Bind a port for a connect operation and hash it.
  */
-
-int tcp_v4_hash_connecting(struct sock *sk)
+static int tcp_v4_hash_connect(struct sock *sk)
 {
 	unsigned short snum = sk->num;
-	struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)];
-	struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev;
+	struct tcp_bind_hashbucket *head;
+	struct tcp_bind_bucket *tb;
+
+	if (snum == 0) {
+		int rover;
+		int low = sysctl_local_port_range[0];
+		int high = sysctl_local_port_range[1];
+		int remaining = (high - low) + 1;
+		struct tcp_tw_bucket *tw = NULL;
+
+		local_bh_disable();
+
+		/* TODO. Actually it is not so bad idea to remove
+		 * tcp_portalloc_lock before next submission to Linus.
+		 * As soon as we touch this place at all it is time to think.
+		 *
+		 * Now it protects single _advisory_ variable tcp_port_rover,
+		 * hence it is mostly useless.
+		 * Code will work nicely if we just delete it, but
+		 * I am afraid in contented case it will work not better or
+		 * even worse: another cpu just will hit the same bucket
+		 * and spin there.
+		 * So some cpu salt could remove both contention and
+		 * memory pingpong. Any ideas how to do this in a nice way?
+		 */
+		spin_lock(&tcp_portalloc_lock);
+		rover = tcp_port_rover;
+
+		do {
+			rover++;
+			if ((rover < low) || (rover > high))
+				rover = low;
+			head = &tcp_bhash[tcp_bhashfn(rover)];
+			spin_lock(&head->lock);		
+
+			/* Does not bother with rcv_saddr checks,
+			 * because the established check is already
+			 * unique enough.
+			 */
+			for (tb = head->chain; tb; tb = tb->next) {
+				if (tb->port == rover) {
+					BUG_TRAP(tb->owners != NULL);
+					if (tb->fastreuse >= 0)
+						goto next_port;
+					if (!__tcp_v4_check_established(sk, rover, &tw))
+						goto ok;
+					goto next_port;
+				}
+			}
+
+			tb = tcp_bucket_create(head, rover);
+			if (!tb) {
+				spin_unlock(&head->lock);
+				break;
+			}
+			tb->fastreuse = -1;
+			goto ok;
+
+		next_port:
+			spin_unlock(&head->lock);
+		} while (--remaining > 0);
+		tcp_port_rover = rover;
+		spin_unlock(&tcp_portalloc_lock);
+
+		local_bh_enable();
+
+		return -EADDRNOTAVAIL;
+
+	ok:
+		/* All locks still held and bhs disabled */
+		tcp_port_rover = rover;
+		spin_unlock(&tcp_portalloc_lock);
+
+		tcp_bind_hash(sk, tb, rover);
+		if (!sk->pprev) {
+			sk->sport = htons(rover);
+			__tcp_v4_hash(sk, 0);
+		}
+		spin_unlock(&head->lock);
 
+		if (tw) {
+			tcp_tw_deschedule(tw);
+			tcp_timewait_kill(tw);
+			tcp_tw_put(tw);
+		}
+
+		local_bh_enable();
+		return 0;
+	}
+
+	head  = &tcp_bhash[tcp_bhashfn(snum)];
+	tb  = (struct tcp_bind_bucket *)sk->prev;
 	spin_lock_bh(&head->lock);
 	if (tb->owners == sk && sk->bind_next == NULL) {
-		__tcp_v4_hash(sk);
+		__tcp_v4_hash(sk, 0);
 		spin_unlock_bh(&head->lock);
 		return 0;
 	} else {
-		spin_unlock_bh(&head->lock);
-
+		int ret;
+		spin_unlock(&head->lock);
 		/* No definite answer... Walk to established hash table */
-		return tcp_v4_check_established(sk);
+		ret = __tcp_v4_check_established(sk, snum, NULL);
+		local_bh_enable();
+		return ret;
 	}
 }
 
@@ -647,7 +752,6 @@
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
-	struct sk_buff *buff;
 	struct rtable *rt;
 	u32 daddr, nexthop;
 	int tmp;
@@ -682,12 +786,6 @@
 	if (!sk->protinfo.af_inet.opt || !sk->protinfo.af_inet.opt->srr)
 		daddr = rt->rt_dst;
 
-	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
-
-	if (buff == NULL)
-		goto failure;
-
 	if (!sk->saddr)
 		sk->saddr = rt->rt_src;
 	sk->rcv_saddr = sk->saddr;
@@ -718,22 +816,36 @@
 	sk->dport = usin->sin_port;
 	sk->daddr = daddr;
 
+	tp->ext_header_len = 0;
+	if (sk->protinfo.af_inet.opt)
+		tp->ext_header_len = sk->protinfo.af_inet.opt->optlen;
+
+	tp->mss_clamp = 536;
+
+	/* Socket identity is still unknown (sport may be zero).
+	 * However we set state to SYN-SENT and not releasing socket
+	 * lock select source port, enter ourselves into the hash tables and
+	 * complete initalization after this.
+	 */
+	tcp_set_state(sk, TCP_SYN_SENT);
+	err = tcp_v4_hash_connect(sk);
+	if (err)
+		goto failure;
+
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
 							   sk->sport, usin->sin_port);
 
-	tp->ext_header_len = 0;
-	if (sk->protinfo.af_inet.opt)
-		tp->ext_header_len = sk->protinfo.af_inet.opt->optlen;
 	sk->protinfo.af_inet.id = tp->write_seq^jiffies;
 
-	tp->mss_clamp = 536;
+	err = tcp_connect(sk);
+	if (err)
+		goto failure;
 
-	err = tcp_connect(sk, buff);
-	if (err == 0)
-		return 0;
+	return 0;
 
 failure:
+	tcp_set_state(sk, TCP_CLOSE);
 	__sk_dst_reset(sk);
 	sk->route_caps = 0;
 	sk->dport = 0;
@@ -786,7 +898,6 @@
 	req->expires = jiffies + TCP_TIMEOUT_INIT;
 	req->retrans = 0;
 	req->sk = NULL;
-	req->index = h;
 	req->dl_next = lopt->syn_table[h];
 
 	write_lock(&tp->syn_wait_lock);
@@ -1072,6 +1183,7 @@
 	arg.n_iov = 1;
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2; 
 
+	tcp_socket->sk->protinfo.af_inet.ttl = sysctl_ip_default_ttl;
 	ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
 
 	TCP_INC_STATS_BH(TcpOutSegs);
@@ -1456,7 +1568,7 @@
 	newtp->advmss = dst->advmss;
 	tcp_initialize_rcv_mss(newsk);
 
-	__tcp_v4_hash(newsk);
+	__tcp_v4_hash(newsk, 0);
 	__tcp_inherit_port(sk, newsk);
 
 	return newsk;
@@ -1876,7 +1988,6 @@
 	tcp_v4_rebuild_header,
 	tcp_v4_conn_request,
 	tcp_v4_syn_recv_sock,
-	tcp_v4_hash_connecting,
 	tcp_v4_remember_stamp,
 	sizeof(struct iphdr),
 
diff -urN linux-2.4.19-pre4/net/ipv4/tcp_minisocks.c linux-2.4.19-pre5/net/ipv4/tcp_minisocks.c
--- linux-2.4.19-pre4/net/ipv4/tcp_minisocks.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/ipv4/tcp_minisocks.c	Fri Mar 29 14:50:08 2002
@@ -782,6 +782,8 @@
 			newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len;
 		newtp->mss_clamp = req->mss;
 		TCP_ECN_openreq_child(newtp, req);
+
+		TCP_INC_STATS_BH(TcpPassiveOpens);
 	}
 	return newsk;
 }
@@ -845,8 +847,38 @@
 	/* Further reproduces section "SEGMENT ARRIVES"
 	   for state SYN-RECEIVED of RFC793.
 	   It is broken, however, it does not work only
-	   when SYNs are crossed, which is impossible in our
-	   case.
+	   when SYNs are crossed.
+
+	   You would think that SYN crossing is impossible here, since
+	   we should have a SYN_SENT socket (from connect()) on our end,
+	   but this is not true if the crossed SYNs were sent to both
+	   ends by a malicious third party.  We must defend against this,
+	   and to do that we first verify the ACK (as per RFC793, page
+	   36) and reset if it is invalid.  Is this a true full defense?
+	   To convince ourselves, let us consider a way in which the ACK
+	   test can still pass in this 'malicious crossed SYNs' case.
+	   Malicious sender sends identical SYNs (and thus identical sequence
+	   numbers) to both A and B:
+
+		A: gets SYN, seq=7
+		B: gets SYN, seq=7
+
+	   By our good fortune, both A and B select the same initial
+	   send sequence number of seven :-)
+
+		A: sends SYN|ACK, seq=7, ack_seq=8
+		B: sends SYN|ACK, seq=7, ack_seq=8
+
+	   So we are now A eating this SYN|ACK, ACK test passes.  So
+	   does sequence test, SYN is truncated, and thus we consider
+	   it a bare ACK.
+
+	   If tp->defer_accept, we silently drop this bare ACK.  Otherwise,
+	   we create an established connection.  Both ends (listening sockets)
+	   accept the new incoming connection and try to talk to each other. 8-)
+
+	   Note: This case is both harmless, and rare.  Possibility is about the
+	   same as us discovering intelligent life on another plant tomorrow.
 
 	   But generally, we should (RFC lies!) to accept ACK
 	   from SYNACK both here and in tcp_rcv_state_process().
@@ -858,6 +890,22 @@
 	   before attempt to create socket.
 	 */
 
+	/* RFC793 page 36: "If the connection is in any non-synchronized state ...
+	 *                  and the incoming segment acknowledges something not yet
+	 *                  sent (the segment carries an unaccaptable ACK) ...
+	 *                  a reset is sent."
+	 */
+	if (!(flg & TCP_FLAG_ACK))
+		return NULL;
+
+	/* Invalid ACK: reset will be sent by listening socket */
+	if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
+		return sk;
+	/* Also, it would be not so bad idea to check rcv_tsecr, which
+	 * is essentially ACK extension and too early or too late values
+	 * should cause reset in unsynchronized states.
+	 */
+
 	/* RFC793: "first check sequence number". */
 
 	if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
@@ -887,19 +935,6 @@
 	if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
 		goto embryonic_reset;
 
-	/* RFC793: "fifth check the ACK field" */
-
-	if (!(flg & TCP_FLAG_ACK))
-		return NULL;
-
-	/* Invalid ACK: reset will be sent by listening socket */
-	if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
-		return sk;
-	/* Also, it would be not so bad idea to check rcv_tsecr, which
-	 * is essentially ACK extension and too early or too late values
-	 * should cause reset in unsynchronized states.
-	 */
-
 	/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
 	if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) {
 		req->acked = 1;
diff -urN linux-2.4.19-pre4/net/ipv4/tcp_output.c linux-2.4.19-pre5/net/ipv4/tcp_output.c
--- linux-2.4.19-pre4/net/ipv4/tcp_output.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/ipv4/tcp_output.c	Fri Mar 29 14:50:08 2002
@@ -38,6 +38,7 @@
 
 #include <net/tcp.h>
 
+#include <linux/compiler.h>
 #include <linux/smp_lock.h>
 
 /* People can turn this off for buggy TCP's found in printers etc. */
@@ -1157,14 +1158,14 @@
 	return skb;
 }
 
-int tcp_connect(struct sock *sk, struct sk_buff *buff)
+/* 
+ * Do all connect socket setups that can be done AF independent.
+ */ 
+static inline void tcp_connect_init(struct sock *sk)
 {
 	struct dst_entry *dst = __sk_dst_get(sk);
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-	/* Reserve space for headers. */
-	skb_reserve(buff, MAX_TCP_HEADER);
-
 	/* We'll fix this up when we get a response from the other end.
 	 * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
 	 */
@@ -1191,14 +1192,6 @@
 
 	tp->rcv_ssthresh = tp->rcv_wnd;
 
-	/* Socket identity change complete, no longer
-	 * in TCP_CLOSE, so enter ourselves into the
-	 * hash tables.
-	 */
-	tcp_set_state(sk,TCP_SYN_SENT);
-	if (tp->af_specific->hash_connecting(sk))
-		goto err_out;
-
 	sk->err = 0;
 	sk->done = 0;
 	tp->snd_wnd = 0;
@@ -1212,6 +1205,24 @@
 	tp->rto = TCP_TIMEOUT_INIT;
 	tp->retransmits = 0;
 	tcp_clear_retrans(tp);
+}
+
+/*
+ * Build a SYN and send it off.
+ */ 
+int tcp_connect(struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct sk_buff *buff;
+
+	tcp_connect_init(sk);
+
+	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
+	if (unlikely(buff == NULL))
+		return -ENOBUFS;
+
+	/* Reserve space for headers. */
+	skb_reserve(buff, MAX_TCP_HEADER);
 
 	TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
 	TCP_ECN_send_syn(tp, buff);
@@ -1234,11 +1245,6 @@
 	/* Timer for repeating the SYN until an answer. */
 	tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
 	return 0;
-
-err_out:
-	tcp_set_state(sk,TCP_CLOSE);
-	kfree_skb(buff);
-	return -EADDRNOTAVAIL;
 }
 
 /* Send out a delayed ack, the caller does the policy checking
diff -urN linux-2.4.19-pre4/net/ipv4/udp.c linux-2.4.19-pre5/net/ipv4/udp.c
--- linux-2.4.19-pre4/net/ipv4/udp.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/ipv4/udp.c	Fri Mar 29 14:50:08 2002
@@ -712,6 +712,8 @@
 {
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
 	struct rtable *rt;
+	u32 saddr;
+	int oif;
 	int err;
 
 	
@@ -723,8 +725,16 @@
 
 	sk_dst_reset(sk);
 
-	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
-			       RT_CONN_FLAGS(sk), sk->bound_dev_if);
+	oif = sk->bound_dev_if;
+	saddr = sk->saddr;
+	if (MULTICAST(usin->sin_addr.s_addr)) {
+		if (!oif)
+			oif = sk->protinfo.af_inet.mc_index;
+		if (!saddr)
+			saddr = sk->protinfo.af_inet.mc_addr;
+	}
+	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
+			       RT_CONN_FLAGS(sk), oif);
 	if (err)
 		return err;
 	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
diff -urN linux-2.4.19-pre4/net/ipv6/addrconf.c linux-2.4.19-pre5/net/ipv6/addrconf.c
--- linux-2.4.19-pre4/net/ipv6/addrconf.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre5/net/ipv6/addrconf.c	Fri Mar 29 14:50:09 2002
@@ -62,6 +62,8 @@
 
 #include <asm/uaccess.h>
 
+#define IPV6_MAX_ADDRESSES 16
+
 /* Set to 3 to get tracing... */
 #define ACONF_DEBUG 2
 
@@ -586,6 +588,18 @@
 	return err;
 }
 
+int ipv6_count_addresses(struct inet6_dev *idev)
+{
+	int cnt = 0;
+	struct inet6_ifaddr *ifp;
+
+	read_lock_bh(&idev->lock);
+	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)
+		cnt++;
+	read_unlock_bh(&idev->lock);
+	return cnt;
+}
+
 int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev)
 {
 	struct inet6_ifaddr * ifp;
@@ -895,8 +909,12 @@
 		ifp = ipv6_get_ifaddr(&addr, dev);
 
 		if (ifp == NULL && valid_lft) {
-			ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
-					    addr_type&IPV6_ADDR_SCOPE_MASK, 0);
+			/* Do not allow to create too much of autoconfigured
+			 * addresses; this would be too easy way to crash kernel.
+			 */
+			if (ipv6_count_addresses(in6_dev) < IPV6_MAX_ADDRESSES)
+				ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+						    addr_type&IPV6_ADDR_SCOPE_MASK, 0);
 
 			if (ifp == NULL) {
 				in6_dev_put(in6_dev);
diff -urN linux-2.4.19-pre4/net/ipv6/ndisc.c linux-2.4.19-pre5/net/ipv6/ndisc.c
--- linux-2.4.19-pre4/net/ipv6/ndisc.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv6/ndisc.c	Fri Mar 29 14:50:09 2002
@@ -356,7 +356,7 @@
 	ipv6_addr_copy(&msg->target, solicited_addr);
 
 	if (inc_opt)
-		ndisc_fill_option((void*)&msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
+		ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
 
 	/* checksum */
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len, 
@@ -417,7 +417,7 @@
 	ipv6_addr_copy(&msg->target, solicit);
 
 	if (send_llinfo)
-		ndisc_fill_option((void*)&msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
+		ndisc_fill_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
 
 	/* checksum */
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
@@ -567,6 +567,11 @@
 			printk(KERN_WARNING "ICMP RA: source address is not linklocal\n");
 		return;
 	}
+	if (optlen < 0) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP RA: packet too short\n");
+		return;
+	}
 
 	/*
 	 *	set the RA_RECV flag in the interface
@@ -923,7 +928,7 @@
 	u8 *opt;
 
 	opt = skb->h.raw;
-	opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+	opt += sizeof(struct nd_msg);
 	opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
 
 	return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
@@ -931,12 +936,11 @@
 
 static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
 {
-	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	u8 *opt;
+	struct nd_msg *msg = (struct nd_msg*) skb->h.raw;
 
-	opt = skb->h.raw;
-	opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
-	opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_TARGET_LL_ADDR);
+	opt = ndisc_find_option(msg->opt, skb->dev->addr_len+2,
+				skb->tail - msg->opt, ND_OPT_TARGET_LL_ADDR);
 
 	return neigh_update(neigh, opt,
 			    msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
@@ -957,7 +961,6 @@
 	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	struct neighbour *neigh;
 	struct inet6_ifaddr *ifp;
-	unsigned int payload_len;
 
 	__skb_push(skb, skb->data-skb->h.raw);
 
@@ -980,11 +983,9 @@
 	 *	(Some checking in ndisc_find_option)
 	 */
 
-	payload_len = ntohs(skb->nh.ipv6h->payload_len);
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
-		/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
-		if (payload_len < 8+16) {
+		if (skb->len < sizeof(struct nd_msg)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NS: packet too short\n");
 			return 0;
@@ -1064,12 +1065,13 @@
 
 				neigh = ndisc_recv_ns(saddr, skb);
 
-				if (neigh) {
+				if (neigh || !dev->hard_header) {
 					ndisc_send_na(dev, neigh, saddr, &ifp->addr, 
 						      ifp->idev->cnf.forwarding, 1, 
 						      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 
 						      1);
-					neigh_release(neigh);
+					if (neigh)
+						neigh_release(neigh);
 				}
 			}
 			in6_ifa_put(ifp);
@@ -1113,8 +1115,7 @@
 		return 0;
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
-		/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
-		if (payload_len < 16+8 ) {
+		if (skb->len < sizeof(struct nd_msg)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NA: packet too short\n");
 			return 0;
@@ -1175,35 +1176,12 @@
 		break;
 
 	case NDISC_ROUTER_ADVERTISEMENT:
-		/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
-		if (payload_len < 8+4+4) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP RA: packet too short\n");
-			return 0;
-		}
 		ndisc_router_discovery(skb);
 		break;
 
 	case NDISC_REDIRECT:
-		/* XXX: import nd_redirect from glibc netinet/icmp6.h */
-		if (payload_len < 8+16+16) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP redirect: packet too short\n");
-			return 0;
-		}
 		ndisc_redirect_rcv(skb);
 		break;
-
-	case NDISC_ROUTER_SOLICITATION:
-		/* No RS support in the kernel, but we do some required checks */
-
-		/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
-		if (payload_len < 8) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP RS: packet too short\n");
-			return 0;
-		}
-		break;
 	};
 
 	return 0;
diff -urN linux-2.4.19-pre4/net/ipv6/sit.c linux-2.4.19-pre5/net/ipv6/sit.c
--- linux-2.4.19-pre4/net/ipv6/sit.c	Mon Oct  1 09:19:56 2001
+++ linux-2.4.19-pre5/net/ipv6/sit.c	Fri Mar 29 14:50:09 2002
@@ -517,7 +517,11 @@
 		goto tx_error;
 	}
 
-	mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	if (tiph->frag_off)
+		mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	else
+		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
+
 	if (mtu < 68) {
 		tunnel->stat.collisions++;
 		ip_rt_put(rt);
diff -urN linux-2.4.19-pre4/net/ipv6/tcp_ipv6.c linux-2.4.19-pre5/net/ipv6/tcp_ipv6.c
--- linux-2.4.19-pre4/net/ipv6/tcp_ipv6.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/ipv6/tcp_ipv6.c	Fri Mar 29 14:50:09 2002
@@ -133,7 +133,7 @@
 				break;
 	}
 	if (tb != NULL && tb->owners != NULL) {
-		if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
 			struct sock *sk2 = tb->owners;
@@ -366,22 +366,22 @@
 }
 
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
-					      struct ipv6hdr *ip6h,
-					      struct tcphdr *th,
-					      int iif,
-					      struct open_request ***prevp)
+					      struct open_request ***prevp,
+					      __u16 rport,
+					      struct in6_addr *raddr,
+					      struct in6_addr *laddr,
+					      int iif)
 {
 	struct tcp_listen_opt *lopt = tp->listen_opt;
 	struct open_request *req, **prev;  
-	__u16 rport = th->source;
 
-	for (prev = &lopt->syn_table[tcp_v6_synq_hash(&ip6h->saddr, rport)];
+	for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport)];
 	     (req = *prev) != NULL;
 	     prev = &req->dl_next) {
 		if (req->rmt_port == rport &&
 		    req->class->family == AF_INET6 &&
-		    !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
-		    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
+		    !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, raddr) &&
+		    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, laddr) &&
 		    (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
 			BUG_TRAP(req->sk == NULL);
 			*prevp = prev;
@@ -486,11 +486,21 @@
 	return -EADDRNOTAVAIL;
 }
 
-static int tcp_v6_hash_connecting(struct sock *sk)
+static int tcp_v6_hash_connect(struct sock *sk)
 {
-	unsigned short snum = sk->num;
-	struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)];
-	struct tcp_bind_bucket *tb = head->chain;
+	struct tcp_bind_hashbucket *head;
+	struct tcp_bind_bucket *tb;
+
+	/* XXX */ 
+	if (sk->num == 0) { 
+		int err = tcp_v6_get_port(sk, sk->num);
+		if (err)
+			return err;
+		sk->sport = htons(sk->num); 	
+	}
+
+	head = &tcp_bhash[tcp_bhashfn(sk->num)];
+	tb = head->chain;
 
 	spin_lock_bh(&head->lock);
 
@@ -520,7 +530,6 @@
 	struct in6_addr saddr_buf;
 	struct flowi fl;
 	struct dst_entry *dst;
-	struct sk_buff *buff;
 	int addr_type;
 	int err;
 
@@ -660,27 +669,25 @@
 		tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen;
 	tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
-	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
-
-	if (buff == NULL)
-		goto failure;
-
 	sk->dport = usin->sin6_port;
 
-	/*
-	 *	Init variables
-	 */
+	tcp_set_state(sk, TCP_SYN_SENT); 
+	err = tcp_v6_hash_connect(sk); 
+	if (err)
+		goto late_failure;
 
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
 							     np->daddr.s6_addr32,
 							     sk->sport, sk->dport);
+	err = tcp_connect(sk);
+	if (err)
+		goto late_failure;
 
-	err = tcp_connect(sk, buff);
-	if (err == 0)
-		return 0;
+	return 0;
 
+late_failure:
+	tcp_set_state(sk, TCP_CLOSE); 
 failure:
 	__sk_dst_reset(sk);
 	sk->dport = 0;
@@ -692,8 +699,6 @@
 		int type, int code, int offset, __u32 info)
 {
 	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
-	struct in6_addr *saddr = &hdr->saddr;
-	struct in6_addr *daddr = &hdr->daddr;
 	struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
 	struct ipv6_pinfo *np;
 	struct sock *sk;
@@ -701,7 +706,7 @@
 	struct tcp_opt *tp; 
 	__u32 seq;
 
-	sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
+	sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
 
 	if (sk == NULL) {
 		ICMP6_INC_STATS_BH(Icmp6InErrors);
@@ -773,15 +778,12 @@
 	/* Might be for an open_request */
 	switch (sk->state) {
 		struct open_request *req, **prev;
-		struct ipv6hdr hd;
 	case TCP_LISTEN:
 		if (sk->lock.users)
 			goto out;
 
-		/* Grrrr - fix this later. */
-		ipv6_addr_copy(&hd.saddr, saddr);
-		ipv6_addr_copy(&hd.daddr, daddr); 
-		req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
+		req = tcp_v6_search_req(tp, &prev, th->dest, &hdr->daddr,
+					&hdr->saddr, tcp_v6_iif(skb));
 		if (!req)
 			goto out;
 
@@ -1088,7 +1090,8 @@
 	struct sock *nsk;
 
 	/* Find possible connection requests. */
-	req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &prev);
+	req = tcp_v6_search_req(tp, &prev, th->source, &skb->nh.ipv6h->saddr,
+				&skb->nh.ipv6h->daddr, tcp_v6_iif(skb));
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
@@ -1123,7 +1126,6 @@
 	req->sk = NULL;
 	req->expires = jiffies + TCP_TIMEOUT_INIT;
 	req->retrans = 0;
-	req->index = h;
 	req->dl_next = lopt->syn_table[h];
 
 	write_lock(&tp->syn_wait_lock);
@@ -1762,7 +1764,6 @@
 	tcp_v6_rebuild_header,
 	tcp_v6_conn_request,
 	tcp_v6_syn_recv_sock,
-	tcp_v6_hash_connecting,
 	tcp_v6_remember_stamp,
 	sizeof(struct ipv6hdr),
 
@@ -1782,7 +1783,6 @@
 	tcp_v4_rebuild_header,
 	tcp_v6_conn_request,
 	tcp_v6_syn_recv_sock,
-	tcp_v4_hash_connecting,
 	tcp_v4_remember_stamp,
 	sizeof(struct iphdr),
 
diff -urN linux-2.4.19-pre4/net/ipv6/udp.c linux-2.4.19-pre5/net/ipv6/udp.c
--- linux-2.4.19-pre4/net/ipv6/udp.c	Fri Mar 29 14:49:13 2002
+++ linux-2.4.19-pre5/net/ipv6/udp.c	Fri Mar 29 14:50:09 2002
@@ -292,6 +292,8 @@
 				return -EINVAL;
 			}
 			sk->bound_dev_if = usin->sin6_scope_id;
+			if (!sk->bound_dev_if && (addr_type&IPV6_ADDR_MULTICAST))
+				fl.oif = np->mcast_oif;
 		}
 
 		/* Connect to link-local address requires an interface */
@@ -316,6 +318,9 @@
 	fl.uli_u.ports.dport = sk->dport;
 	fl.uli_u.ports.sport = sk->sport;
 
+	if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
+		fl.oif = np->mcast_oif;
+
 	if (flowlabel) {
 		if (flowlabel->opt && flowlabel->opt->srcrt) {
 			struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
diff -urN linux-2.4.19-pre4/net/khttpd/sockets.c linux-2.4.19-pre5/net/khttpd/sockets.c
--- linux-2.4.19-pre4/net/khttpd/sockets.c	Mon Mar 27 10:35:57 2000
+++ linux-2.4.19-pre5/net/khttpd/sockets.c	Fri Mar 29 14:50:09 2002
@@ -82,7 +82,7 @@
 	
 	MainSocket = sock;
 	
-	EnterFunction("StartListening");
+	LeaveFunction("StartListening");
 	return 1; 
 }	
 
diff -urN linux-2.4.19-pre4/net/netsyms.c linux-2.4.19-pre5/net/netsyms.c
--- linux-2.4.19-pre4/net/netsyms.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.19-pre5/net/netsyms.c	Fri Mar 29 14:50:09 2002
@@ -364,7 +364,6 @@
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
 EXPORT_SYMBOL(tcp_v4_do_rcv);
 EXPORT_SYMBOL(tcp_v4_connect);
-EXPORT_SYMBOL(tcp_v4_hash_connecting);
 EXPORT_SYMBOL(tcp_unhash);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(tcp_prot);
diff -urN linux-2.4.19-pre4/net/packet/af_packet.c linux-2.4.19-pre5/net/packet/af_packet.c
--- linux-2.4.19-pre4/net/packet/af_packet.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.19-pre5/net/packet/af_packet.c	Fri Mar 29 14:50:09 2002
@@ -355,6 +355,8 @@
 	if (dev->hard_header) {
 		skb->data -= dev->hard_header_len;
 		skb->tail -= dev->hard_header_len;
+		if (len < dev->hard_header_len)
+			skb->nh.raw = skb->data;
 	}
 
 	/* Returns -EFAULT on error */
diff -urN linux-2.4.19-pre4/net/sched/sch_prio.c linux-2.4.19-pre5/net/sched/sch_prio.c
--- linux-2.4.19-pre4/net/sched/sch_prio.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.19-pre5/net/sched/sch_prio.c	Fri Mar 29 14:50:09 2002
@@ -327,6 +327,7 @@
 
 	if (cl - 1 > q->bands)
 		return -ENOENT;
+	tcm->tcm_handle |= TC_H_MIN(cl);
 	if (q->queues[cl-1])
 		tcm->tcm_info = q->queues[cl-1]->handle;
 	return 0;
diff -urN linux-2.4.19-pre4/net/sched/sch_sfq.c linux-2.4.19-pre5/net/sched/sch_sfq.c
--- linux-2.4.19-pre4/net/sched/sch_sfq.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.19-pre5/net/sched/sch_sfq.c	Fri Mar 29 14:50:09 2002
@@ -105,6 +105,7 @@
 /* Parameters */
 	int		perturb_period;
 	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
+	int		limit;
 
 /* Variables */
 	struct timer_list perturb_timer;
@@ -275,7 +276,7 @@
 			q->tail = x;
 		}
 	}
-	if (++sch->q.qlen < SFQ_DEPTH-1) {
+	if (++sch->q.qlen < q->limit-1) {
 		sch->stats.bytes += skb->len;
 		sch->stats.packets++;
 		return 0;
@@ -310,7 +311,7 @@
 			q->tail = x;
 		}
 	}
-	if (++sch->q.qlen < SFQ_DEPTH-1)
+	if (++sch->q.qlen < q->limit - 1)
 		return 0;
 
 	sch->stats.drops++;
@@ -390,6 +391,11 @@
 	sch_tree_lock(sch);
 	q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
 	q->perturb_period = ctl->perturb_period*HZ;
+	if (ctl->limit)
+		q->limit = min_t(u32, ctl->limit, SFQ_DEPTH);
+
+	while (sch->q.qlen >= q->limit-1)
+		sfq_drop(sch);
 
 	del_timer(&q->perturb_timer);
 	if (q->perturb_period) {
@@ -416,6 +422,7 @@
 		q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH;
 		q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH;
 	}
+	q->limit = SFQ_DEPTH;
 	q->max_depth = 0;
 	q->tail = SFQ_DEPTH;
 	if (opt == NULL) {
@@ -448,9 +455,9 @@
 	opt.quantum = q->quantum;
 	opt.perturb_period = q->perturb_period/HZ;
 
-	opt.limit = SFQ_DEPTH;
+	opt.limit = q->limit;
 	opt.divisor = SFQ_HASH_DIVISOR;
-	opt.flows = SFQ_DEPTH;
+	opt.flows = q->limit;
 
 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
diff -urN linux-2.4.19-pre4/scripts/patch-kernel linux-2.4.19-pre5/scripts/patch-kernel
--- linux-2.4.19-pre4/scripts/patch-kernel	Fri Nov  9 14:12:54 2001
+++ linux-2.4.19-pre5/scripts/patch-kernel	Fri Mar 29 14:50:09 2002
@@ -46,6 +46,15 @@
 patchdir=${2-.}
 stopvers=${3-imnotaversion}
 
+if [ "$1" = -h -o "$1" = --help -o ! -r "$sourcedir/Makefile" ]; then
+cat << USAGE
+usage: patch-kernel [-h] [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ]
+  The source directory defaults to /usr/src/linux, and
+  the patch directory defaults to the current directory.
+USAGE
+exit 1
+fi
+
 # See if we have any -ac options
 for PARM in $*
 do
